.. | .. |
---|
1 | | -/* SPDX-License-Identifier: GPL-2.0 */ |
---|
2 | 1 | /* |
---|
3 | 2 | * Linux cfg80211 driver |
---|
4 | 3 | * |
---|
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 | + * |
---|
7 | 8 | * Unless you and Broadcom execute a separate written software license |
---|
8 | 9 | * agreement governing use of this software, this software is licensed to you |
---|
9 | 10 | * under the terms of the GNU General Public License version 2 (the "GPL"), |
---|
10 | 11 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the |
---|
11 | 12 | * following added to such license: |
---|
12 | | - * |
---|
| 13 | + * |
---|
13 | 14 | * As a special exception, the copyright holders of this software give you |
---|
14 | 15 | * permission to link this software with independent modules, and to copy and |
---|
15 | 16 | * distribute the resulting executable under terms of your choice, provided that |
---|
.. | .. |
---|
17 | 18 | * the license of that module. An independent module is a module which is not |
---|
18 | 19 | * derived from this software. The special exception does not apply to any |
---|
19 | 20 | * modifications of the software. |
---|
20 | | - * |
---|
| 21 | + * |
---|
21 | 22 | * Notwithstanding the above, under no circumstances may you combine this |
---|
22 | 23 | * software in any way with any other Broadcom software provided under a license |
---|
23 | 24 | * other than the GPL, without Broadcom's express prior written consent. |
---|
.. | .. |
---|
25 | 26 | * |
---|
26 | 27 | * <<Broadcom-WL-IPTag/Open:>> |
---|
27 | 28 | * |
---|
28 | | - * $Id: wl_cfg80211.c 715966 2019-05-30 02:36:59Z $ |
---|
| 29 | + * $Id: wl_cfg80211.c 814814 2019-04-15 03:31:10Z $ |
---|
29 | 30 | */ |
---|
30 | 31 | /* */ |
---|
31 | 32 | #include <typedefs.h> |
---|
32 | 33 | #include <linuxver.h> |
---|
33 | | -#include <osl.h> |
---|
34 | 34 | #include <linux/kernel.h> |
---|
35 | 35 | |
---|
36 | 36 | #include <bcmutils.h> |
---|
| 37 | +#include <bcmstdlib_s.h> |
---|
37 | 38 | #include <bcmwifi_channels.h> |
---|
38 | 39 | #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> |
---|
41 | 50 | #include <linux/if_arp.h> |
---|
42 | | -#include <linux/uaccess.h> |
---|
| 51 | +#include <asm/uaccess.h> |
---|
43 | 52 | |
---|
44 | | -#include <proto/ethernet.h> |
---|
| 53 | +#include <ethernet.h> |
---|
45 | 54 | #include <linux/kernel.h> |
---|
46 | 55 | #include <linux/kthread.h> |
---|
47 | 56 | #include <linux/netdevice.h> |
---|
.. | .. |
---|
54 | 63 | #include <net/rtnetlink.h> |
---|
55 | 64 | |
---|
56 | 65 | #include <wlioctl.h> |
---|
| 66 | +#include <bcmevent.h> |
---|
57 | 67 | #include <wldev_common.h> |
---|
58 | 68 | #include <wl_cfg80211.h> |
---|
59 | 69 | #include <wl_cfgp2p.h> |
---|
60 | | -#include <wl_android.h> |
---|
| 70 | +#include <wl_cfgscan.h> |
---|
61 | 71 | #include <bcmdevs.h> |
---|
| 72 | +#ifdef OEM_ANDROID |
---|
| 73 | +#include <wl_android.h> |
---|
| 74 | +#endif // endif |
---|
62 | 75 | #include <dngl_stats.h> |
---|
63 | 76 | #include <dhd.h> |
---|
64 | 77 | #include <dhd_linux.h> |
---|
| 78 | +#include <dhd_linux_pktdump.h> |
---|
65 | 79 | #include <dhd_debug.h> |
---|
66 | 80 | #include <dhdioctl.h> |
---|
67 | 81 | #include <wlioctl.h> |
---|
.. | .. |
---|
70 | 84 | #ifdef PNO_SUPPORT |
---|
71 | 85 | #include <dhd_pno.h> |
---|
72 | 86 | #endif /* PNO_SUPPORT */ |
---|
73 | | - |
---|
74 | | -#if defined(WL_VENDOR_EXT_SUPPORT) |
---|
75 | 87 | #include <wl_cfgvendor.h> |
---|
76 | | -#endif /* defined(WL_VENDOR_EXT_SUPPORT) */ |
---|
77 | 88 | |
---|
78 | 89 | #ifdef WL_NAN |
---|
79 | 90 | #include <wl_cfgnan.h> |
---|
80 | 91 | #endif /* WL_NAN */ |
---|
| 92 | + |
---|
81 | 93 | #ifdef PROP_TXSTATUS |
---|
82 | 94 | #include <dhd_wlfc.h> |
---|
83 | | -#endif |
---|
| 95 | +#endif // endif |
---|
84 | 96 | |
---|
85 | 97 | #ifdef BCMPCIE |
---|
86 | 98 | #include <dhd_flowring.h> |
---|
87 | | -#endif |
---|
| 99 | +#endif // endif |
---|
| 100 | +#ifdef RTT_SUPPORT |
---|
| 101 | +#include <dhd_rtt.h> |
---|
| 102 | +#endif /* RTT_SUPPORT */ |
---|
88 | 103 | |
---|
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 */ |
---|
95 | 107 | |
---|
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 |
---|
97 | 112 | |
---|
| 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 */ |
---|
98 | 156 | #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); |
---|
99 | 174 | |
---|
100 | 175 | 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; |
---|
104 | 178 | |
---|
| 179 | +#define MAX_VIF_OFFSET 15 |
---|
105 | 180 | #define MAX_WAIT_TIME 1500 |
---|
106 | 181 | #ifdef WLAIBSS_MCHAN |
---|
107 | 182 | #define IBSS_IF_NAME "ibss%d" |
---|
.. | .. |
---|
126 | 201 | #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) |
---|
127 | 202 | #endif /* VSDB */ |
---|
128 | 203 | |
---|
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 | | - |
---|
137 | 204 | #define DNGL_FUNC(func, parameters) func parameters |
---|
138 | 205 | #define COEX_DHCP |
---|
139 | 206 | |
---|
140 | 207 | #define WLAN_EID_SSID 0 |
---|
141 | 208 | #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 */ |
---|
145 | 231 | |
---|
146 | 232 | #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
147 | 233 | 4 && __GNUC_MINOR__ >= 6)) |
---|
148 | 234 | #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(); \ |
---|
151 | 236 | (entry) = list_first_entry((ptr), type, member); \ |
---|
152 | | -_Pragma("GCC diagnostic pop") \ |
---|
| 237 | +GCC_DIAGNOSTIC_POP(); \ |
---|
153 | 238 | |
---|
154 | 239 | #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(); \ |
---|
157 | 241 | entry = container_of((ptr), type, member); \ |
---|
158 | | -_Pragma("GCC diagnostic pop") \ |
---|
| 242 | +GCC_DIAGNOSTIC_POP(); \ |
---|
159 | 243 | |
---|
160 | 244 | #else |
---|
161 | 245 | #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \ |
---|
.. | .. |
---|
166 | 250 | |
---|
167 | 251 | #endif /* STRICT_GCC_WARNINGS */ |
---|
168 | 252 | |
---|
| 253 | +#ifdef WL_RELMCAST |
---|
169 | 254 | enum rmc_event_type { |
---|
170 | 255 | RMC_EVENT_NONE, |
---|
171 | 256 | RMC_EVENT_LEADER_CHECK_FAIL |
---|
172 | 257 | }; |
---|
| 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 */ |
---|
173 | 264 | |
---|
174 | 265 | /* This is to override regulatory domains defined in cfg80211 module (reg.c) |
---|
175 | 266 | * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN |
---|
.. | .. |
---|
184 | 275 | 4 && __GNUC_MINOR__ >= 6)) |
---|
185 | 276 | _Pragma("GCC diagnostic push") |
---|
186 | 277 | _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") |
---|
187 | | -#endif |
---|
| 278 | +#endif // endif |
---|
188 | 279 | static const struct ieee80211_regdomain brcm_regdom = { |
---|
| 280 | +#ifdef WL_6E |
---|
| 281 | + .n_reg_rules = 5, |
---|
| 282 | +#else |
---|
189 | 283 | .n_reg_rules = 4, |
---|
| 284 | +#endif /* WL_6E */ |
---|
190 | 285 | .alpha2 = "99", |
---|
191 | 286 | .reg_rules = { |
---|
192 | 287 | /* IEEE 802.11b/g, channels 1..11 */ |
---|
.. | .. |
---|
197 | 292 | */ |
---|
198 | 293 | REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), |
---|
199 | 294 | /* 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), |
---|
201 | 296 | /* 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 | + } |
---|
203 | 303 | }; |
---|
204 | 304 | #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
205 | 305 | 4 && __GNUC_MINOR__ >= 6)) |
---|
206 | 306 | _Pragma("GCC diagnostic pop") |
---|
207 | | -#endif |
---|
208 | | - |
---|
| 307 | +#endif // endif |
---|
209 | 308 | |
---|
210 | 309 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ |
---|
211 | 310 | (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) |
---|
.. | .. |
---|
224 | 323 | * to kernel version. |
---|
225 | 324 | * |
---|
226 | 325 | * 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) |
---|
228 | 329 | */ |
---|
229 | 330 | #ifdef WL_ENABLE_P2P_IF |
---|
230 | 331 | .max = 3, |
---|
231 | 332 | #else |
---|
232 | | - .max = 2, |
---|
| 333 | + .max = 4, |
---|
233 | 334 | #endif /* WL_ENABLE_P2P_IF */ |
---|
234 | 335 | .types = BIT(NL80211_IFTYPE_STATION), |
---|
235 | 336 | }, |
---|
.. | .. |
---|
248 | 349 | .types = BIT(NL80211_IFTYPE_ADHOC), |
---|
249 | 350 | }, |
---|
250 | 351 | }; |
---|
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 | + |
---|
256 | 355 | static const struct ieee80211_iface_combination |
---|
257 | 356 | common_iface_combinations[] = { |
---|
258 | 357 | { |
---|
259 | 358 | .num_different_channels = NUM_DIFF_CHANNELS, |
---|
260 | 359 | /* |
---|
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 |
---|
266 | 361 | */ |
---|
267 | | - .max_interfaces = 4, |
---|
| 362 | + .max_interfaces = IFACE_MAX_CNT, |
---|
268 | 363 | .limits = common_if_limits, |
---|
269 | 364 | .n_limits = ARRAY_SIZE(common_if_limits), |
---|
270 | 365 | }, |
---|
271 | 366 | }; |
---|
272 | 367 | #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ |
---|
273 | 368 | |
---|
| 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 */ |
---|
274 | 393 | |
---|
275 | 394 | /* Data Element Definitions */ |
---|
276 | 395 | #define WPS_ID_CONFIG_METHODS 0x1008 |
---|
.. | .. |
---|
308 | 427 | #define PM_BLOCK 1 |
---|
309 | 428 | #define PM_ENABLE 0 |
---|
310 | 429 | |
---|
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) */ |
---|
314 | 434 | |
---|
315 | 435 | #ifndef IBSS_COALESCE_ALLOWED |
---|
316 | | -#define IBSS_COALESCE_ALLOWED 0 |
---|
317 | | -#endif |
---|
| 436 | +#define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT |
---|
| 437 | +#endif // endif |
---|
318 | 438 | |
---|
319 | 439 | #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 |
---|
323 | 442 | |
---|
324 | 443 | #define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */ |
---|
325 | 444 | #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 | + |
---|
326 | 545 | /* |
---|
327 | 546 | * cfg80211_ops api/callback list |
---|
328 | 547 | */ |
---|
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); |
---|
343 | 551 | static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); |
---|
344 | 552 | #ifdef WLAIBSS_MCHAN |
---|
345 | 553 | static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name); |
---|
.. | .. |
---|
357 | 565 | static s32 wl_cfg80211_get_station(struct wiphy *wiphy, |
---|
358 | 566 | struct net_device *dev, u8 *mac, |
---|
359 | 567 | 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 |
---|
364 | 569 | static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, |
---|
365 | 570 | 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) */ |
---|
366 | 577 | static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, |
---|
367 | 578 | u16 reason_code); |
---|
368 | 579 | #if defined(WL_CFG80211_P2P_DEV_IF) |
---|
.. | .. |
---|
409 | 620 | #else |
---|
410 | 621 | static s32 wl_cfg80211_del_station(struct wiphy *wiphy, |
---|
411 | 622 | struct net_device *ndev, u8* mac_addr); |
---|
412 | | -#endif |
---|
| 623 | +#endif // endif |
---|
413 | 624 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) |
---|
414 | 625 | static s32 wl_cfg80211_change_station(struct wiphy *wiphy, |
---|
415 | 626 | struct net_device *dev, const u8 *mac, struct station_parameters *params); |
---|
416 | 627 | #else |
---|
417 | 628 | static s32 wl_cfg80211_change_station(struct wiphy *wiphy, |
---|
418 | 629 | struct net_device *dev, u8 *mac, struct station_parameters *params); |
---|
419 | | -#endif |
---|
| 630 | +#endif // endif |
---|
420 | 631 | #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) |
---|
422 | 633 | static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
---|
423 | 634 | #else |
---|
424 | 635 | static s32 wl_cfg80211_suspend(struct wiphy *wiphy); |
---|
425 | | -#endif |
---|
| 636 | +#endif // endif |
---|
426 | 637 | static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, |
---|
427 | 638 | struct cfg80211_pmksa *pmksa); |
---|
428 | 639 | static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, |
---|
429 | 640 | struct cfg80211_pmksa *pmksa); |
---|
430 | 641 | static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, |
---|
431 | 642 | 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) |
---|
437 | 644 | #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \ |
---|
438 | 645 | KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) |
---|
439 | 646 | static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, |
---|
440 | 647 | 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); |
---|
442 | 649 | #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \ |
---|
443 | 650 | (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0))) |
---|
444 | 651 | static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, |
---|
445 | 652 | 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); |
---|
447 | 654 | #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) |
---|
448 | 655 | 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 */ |
---|
452 | 659 | 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); |
---|
455 | 662 | #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ |
---|
456 | 663 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) |
---|
457 | 664 | static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
---|
.. | .. |
---|
459 | 666 | #else |
---|
460 | 667 | static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
---|
461 | 668 | 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); |
---|
471 | 676 | 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); |
---|
474 | 678 | |
---|
475 | 679 | s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, |
---|
476 | 680 | 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); |
---|
478 | 682 | s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg, |
---|
479 | 683 | 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) */ |
---|
481 | 688 | #ifdef GTK_OFFLOAD_SUPPORT |
---|
482 | 689 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) |
---|
483 | 690 | static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev, |
---|
484 | 691 | struct cfg80211_gtk_rekey_data *data); |
---|
485 | 692 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */ |
---|
486 | | -#endif |
---|
| 693 | +#endif /* GTK_OFFLOAD_SUPPORT */ |
---|
487 | 694 | chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec); |
---|
488 | 695 | 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 */ |
---|
500 | 714 | |
---|
501 | 715 | /* |
---|
502 | 716 | * event & event Q handlers for cfg80211 interfaces |
---|
503 | 717 | */ |
---|
504 | 718 | static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg); |
---|
505 | 719 | 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); |
---|
507 | 721 | static void wl_init_eq(struct bcm_cfg80211 *cfg); |
---|
508 | 722 | static void wl_flush_eq(struct bcm_cfg80211 *cfg); |
---|
509 | 723 | static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg); |
---|
.. | .. |
---|
513 | 727 | static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg); |
---|
514 | 728 | static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type, |
---|
515 | 729 | 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); |
---|
518 | 731 | static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, |
---|
519 | 732 | const wl_event_msg_t *e, void *data); |
---|
520 | 733 | static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg, |
---|
521 | 734 | bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); |
---|
522 | 735 | static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, |
---|
523 | 736 | 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); |
---|
526 | 737 | static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, |
---|
527 | 738 | const wl_event_msg_t *e, void *data, bool completed); |
---|
528 | 739 | static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, |
---|
.. | .. |
---|
533 | 744 | static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, |
---|
534 | 745 | bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); |
---|
535 | 746 | #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 */ |
---|
545 | 747 | #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); |
---|
548 | 748 | static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, |
---|
549 | 749 | const wl_event_msg_t *e, void *data); |
---|
550 | 750 | #endif /* GSCAN_SUPPORT */ |
---|
| 751 | +#ifdef RSSI_MONITOR_SUPPORT |
---|
551 | 752 | static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev, |
---|
552 | 753 | const wl_event_msg_t *e, void *data); |
---|
| 754 | +#endif /* RSSI_MONITOR_SUPPORT */ |
---|
553 | 755 | static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, |
---|
554 | 756 | 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) |
---|
556 | 762 | static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, |
---|
557 | 763 | 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 |
---|
558 | 766 | static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg); |
---|
559 | 767 | #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 |
---|
560 | 771 | |
---|
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, |
---|
563 | 775 | 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 | + |
---|
565 | 795 | /* |
---|
566 | 796 | * register/deregister parent device |
---|
567 | 797 | */ |
---|
.. | .. |
---|
582 | 812 | */ |
---|
583 | 813 | static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, |
---|
584 | 814 | 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); |
---|
586 | 815 | static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev); |
---|
587 | 816 | |
---|
588 | 817 | /* |
---|
.. | .. |
---|
598 | 827 | struct cfg80211_connect_params *sme); |
---|
599 | 828 | static s32 wl_set_set_sharedkey(struct net_device *dev, |
---|
600 | 829 | 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 | + |
---|
601 | 842 | static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev); |
---|
602 | 843 | 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); |
---|
604 | 845 | void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg); |
---|
605 | 846 | |
---|
606 | 847 | /* |
---|
.. | .. |
---|
608 | 849 | */ |
---|
609 | 850 | static void wl_rst_ie(struct bcm_cfg80211 *cfg); |
---|
610 | 851 | 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); |
---|
613 | 854 | static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size); |
---|
614 | 855 | static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size); |
---|
615 | 856 | static u32 wl_get_ielen(struct bcm_cfg80211 *cfg); |
---|
616 | 857 | #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 |
---|
627 | 860 | |
---|
628 | 861 | static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data); |
---|
629 | 862 | 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 */ |
---|
638 | 863 | |
---|
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); |
---|
642 | 866 | static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); |
---|
643 | 867 | s32 wl_cfg80211_channel_to_freq(u32 channel); |
---|
644 | | - |
---|
645 | | - |
---|
646 | 868 | static void wl_cfg80211_work_handler(struct work_struct *work); |
---|
647 | 869 | static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, |
---|
648 | 870 | u8 key_idx, const u8 *mac_addr, |
---|
649 | 871 | 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 | + |
---|
650 | 877 | /* |
---|
651 | 878 | * key indianess swap utilities |
---|
652 | 879 | */ |
---|
.. | .. |
---|
673 | 900 | static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg); |
---|
674 | 901 | static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg); |
---|
675 | 902 | static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); |
---|
| 903 | + |
---|
676 | 904 | static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, |
---|
677 | 905 | struct net_device *ndev); |
---|
678 | 906 | static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e); |
---|
679 | 907 | static void wl_link_up(struct bcm_cfg80211 *cfg); |
---|
680 | 908 | 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); |
---|
682 | 910 | 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 | | - |
---|
686 | 911 | int wl_cfg80211_get_ioctl_version(void); |
---|
687 | 912 | |
---|
688 | 913 | /* |
---|
.. | .. |
---|
698 | 923 | #ifdef DEBUGFS_CFG80211 |
---|
699 | 924 | static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg); |
---|
700 | 925 | 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); |
---|
706 | 928 | |
---|
707 | 929 | #ifdef WL_CFG80211_ACL |
---|
708 | 930 | /* ACL */ |
---|
.. | .. |
---|
713 | 935 | /* |
---|
714 | 936 | * Some external functions, TODO: move them to dhd_linux.h |
---|
715 | 937 | */ |
---|
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); |
---|
717 | 940 | int dhd_del_monitor(struct net_device *ndev); |
---|
718 | 941 | int dhd_monitor_init(void *dhd_pub); |
---|
719 | 942 | 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 */ |
---|
724 | 950 | |
---|
| 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 */ |
---|
725 | 981 | |
---|
726 | 982 | static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev, |
---|
727 | 983 | 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 */ |
---|
728 | 1016 | |
---|
729 | 1017 | static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ, |
---|
730 | 1018 | WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ }; |
---|
731 | 1019 | |
---|
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)) */ |
---|
739 | 1085 | |
---|
740 | 1086 | #ifdef RSSI_OFFSET |
---|
741 | 1087 | static s32 wl_rssi_offset(s32 rssi) |
---|
.. | .. |
---|
747 | 1093 | } |
---|
748 | 1094 | #else |
---|
749 | 1095 | #define wl_rssi_offset(x) x |
---|
750 | | -#endif |
---|
| 1096 | +#endif // endif |
---|
751 | 1097 | |
---|
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 || \ |
---|
754 | 1100 | (akm) == RSN_AKM_PSK) |
---|
755 | | - |
---|
756 | 1101 | |
---|
757 | 1102 | extern int dhd_wait_pend8021x(struct net_device *dev); |
---|
758 | 1103 | #ifdef PROP_TXSTATUS_VSDB |
---|
759 | 1104 | extern int disable_proptx; |
---|
760 | 1105 | #endif /* PROP_TXSTATUS_VSDB */ |
---|
761 | 1106 | |
---|
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); |
---|
765 | 1110 | static s32 |
---|
766 | 1111 | wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, |
---|
767 | 1112 | const wl_event_msg_t *e, void *data); |
---|
.. | .. |
---|
771 | 1116 | int freq; |
---|
772 | 1117 | int chan_type; |
---|
773 | 1118 | }; |
---|
774 | | -#endif |
---|
| 1119 | +#endif // endif |
---|
775 | 1120 | |
---|
| 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) */ |
---|
776 | 1126 | |
---|
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)) |
---|
807 | 1127 | #define CHAN2G(_channel, _freq, _flags) { \ |
---|
808 | 1128 | .band = IEEE80211_BAND_2GHZ, \ |
---|
809 | 1129 | .center_freq = (_freq), \ |
---|
.. | .. |
---|
821 | 1141 | .max_antenna_gain = 0, \ |
---|
822 | 1142 | .max_power = 30, \ |
---|
823 | 1143 | } |
---|
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 | | -} |
---|
833 | 1144 | |
---|
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)), \ |
---|
837 | 1149 | .hw_value = (_channel), \ |
---|
838 | 1150 | .flags = (_flags), \ |
---|
839 | 1151 | .max_antenna_gain = 0, \ |
---|
840 | 1152 | .max_power = 30, \ |
---|
841 | 1153 | } |
---|
842 | | -#endif /* if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */ |
---|
| 1154 | +#endif /* WL_6E */ |
---|
843 | 1155 | |
---|
844 | 1156 | #define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) |
---|
845 | 1157 | #define RATETAB_ENT(_rateid, _flags) \ |
---|
.. | .. |
---|
904 | 1216 | CHAN5G(165, 0) |
---|
905 | 1217 | }; |
---|
906 | 1218 | |
---|
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 | + |
---|
915 | 1305 | static struct ieee80211_supported_band __wl_band_2ghz = { |
---|
916 | 1306 | .band = IEEE80211_BAND_2GHZ, |
---|
917 | 1307 | .channels = __wl_2ghz_channels, |
---|
918 | 1308 | .n_channels = ARRAY_SIZE(__wl_2ghz_channels), |
---|
919 | 1309 | .bitrates = wl_g_rates, |
---|
920 | | - .n_bitrates = wl_g_rates_size |
---|
| 1310 | + .n_bitrates = wl_g_rates_size, |
---|
921 | 1311 | }; |
---|
922 | 1312 | |
---|
923 | 1313 | static struct ieee80211_supported_band __wl_band_5ghz_a = { |
---|
.. | .. |
---|
925 | 1315 | .channels = __wl_5ghz_a_channels, |
---|
926 | 1316 | .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), |
---|
927 | 1317 | .bitrates = wl_a_rates, |
---|
928 | | - .n_bitrates = wl_a_rates_size |
---|
| 1318 | + .n_bitrates = wl_a_rates_size, |
---|
929 | 1319 | }; |
---|
930 | 1320 | |
---|
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 */ |
---|
938 | 1330 | |
---|
939 | 1331 | static const u32 __wl_cipher_suites[] = { |
---|
940 | 1332 | WLAN_CIPHER_SUITE_WEP40, |
---|
941 | 1333 | WLAN_CIPHER_SUITE_WEP104, |
---|
942 | 1334 | WLAN_CIPHER_SUITE_TKIP, |
---|
943 | 1335 | 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 | + */ |
---|
944 | 1341 | 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) |
---|
946 | 1353 | 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 */ |
---|
948 | 1361 | }; |
---|
949 | 1362 | |
---|
950 | 1363 | #ifdef WL_SUPPORT_ACS |
---|
.. | .. |
---|
963 | 1376 | }; |
---|
964 | 1377 | #endif /* WL_SUPPORT_ACS */ |
---|
965 | 1378 | |
---|
| 1379 | +#ifdef WL_CFG80211_GON_COLLISION |
---|
| 1380 | +#define BLOCK_GON_REQ_MAX_NUM 5 |
---|
| 1381 | +#endif /* WL_CFG80211_GON_COLLISION */ |
---|
966 | 1382 | |
---|
967 | 1383 | #if defined(USE_DYNAMIC_MAXPKT_RXGLOM) |
---|
968 | 1384 | static int maxrxpktglom = 0; |
---|
969 | | -#endif |
---|
| 1385 | +#endif // endif |
---|
970 | 1386 | |
---|
971 | 1387 | /* IOCtl version read from targeted driver */ |
---|
972 | | -static int ioctl_version; |
---|
| 1388 | +int ioctl_version; |
---|
973 | 1389 | #ifdef DEBUGFS_CFG80211 |
---|
974 | | -#define S_SUBLOGLEVEL 20 |
---|
| 1390 | +#define SUBLOGLEVEL 20 |
---|
| 1391 | +#define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1)) |
---|
975 | 1392 | static const struct { |
---|
976 | 1393 | u32 log_level; |
---|
977 | 1394 | char *sublogname; |
---|
.. | .. |
---|
983 | 1400 | {WL_DBG_TRACE, "TRACE"}, |
---|
984 | 1401 | {WL_DBG_P2P_ACTION, "P2PACTION"} |
---|
985 | 1402 | }; |
---|
986 | | -#endif |
---|
| 1403 | +#endif // endif |
---|
987 | 1404 | |
---|
| 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; |
---|
988 | 1410 | |
---|
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) |
---|
991 | 1476 | { |
---|
| 1477 | + u16 wq_duration = 0; |
---|
| 1478 | +#if defined(OEM_ANDROID) |
---|
| 1479 | + dhd_pub_t *dhd = NULL; |
---|
| 1480 | +#endif /* BCMDONGLEHOST && OEM_ANDROID */ |
---|
| 1481 | + |
---|
992 | 1482 | if (cfg == NULL) |
---|
993 | 1483 | return; |
---|
994 | 1484 | |
---|
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 */ |
---|
1001 | 1488 | |
---|
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")); |
---|
1016 | 1521 | } |
---|
1017 | 1522 | } |
---|
| 1523 | + mutex_unlock(&cfg->pm_sync); |
---|
1018 | 1524 | } |
---|
1019 | 1525 | |
---|
1020 | 1526 | /* Return a new chanspec given a legacy chanspec |
---|
1021 | 1527 | * Returns INVCHANSPEC on error |
---|
1022 | 1528 | */ |
---|
1023 | | -static chanspec_t |
---|
| 1529 | +chanspec_t |
---|
1024 | 1530 | wl_chspec_from_legacy(chanspec_t legacy_chspec) |
---|
1025 | 1531 | { |
---|
1026 | 1532 | chanspec_t chspec; |
---|
.. | .. |
---|
1049 | 1555 | |
---|
1050 | 1556 | if (wf_chspec_malformed(chspec)) { |
---|
1051 | 1557 | WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", |
---|
1052 | | - chspec)); |
---|
| 1558 | + chspec)); |
---|
1053 | 1559 | return INVCHANSPEC; |
---|
1054 | 1560 | } |
---|
1055 | 1561 | |
---|
.. | .. |
---|
1066 | 1572 | |
---|
1067 | 1573 | if (wf_chspec_malformed(chspec)) { |
---|
1068 | 1574 | WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", |
---|
1069 | | - chspec)); |
---|
| 1575 | + chspec)); |
---|
1070 | 1576 | return INVCHANSPEC; |
---|
1071 | 1577 | } |
---|
1072 | 1578 | |
---|
.. | .. |
---|
1095 | 1601 | /* cannot express the bandwidth */ |
---|
1096 | 1602 | char chanbuf[CHANSPEC_STR_LEN]; |
---|
1097 | 1603 | 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)); |
---|
1101 | 1607 | return INVCHANSPEC; |
---|
1102 | 1608 | } |
---|
1103 | 1609 | |
---|
1104 | 1610 | return lchspec; |
---|
| 1611 | +} |
---|
| 1612 | + |
---|
| 1613 | +bool wl_cfg80211_is_hal_started(struct bcm_cfg80211 *cfg) |
---|
| 1614 | +{ |
---|
| 1615 | + return cfg->hal_started; |
---|
1105 | 1616 | } |
---|
1106 | 1617 | |
---|
1107 | 1618 | /* given a chanspec value, do the endian and chanspec version conversion to |
---|
.. | .. |
---|
1127 | 1638 | * Returns INVCHANSPEC on error |
---|
1128 | 1639 | */ |
---|
1129 | 1640 | chanspec_t |
---|
1130 | | -wl_ch_host_to_driver(s32 bssidx, u16 channel) |
---|
| 1641 | +wl_ch_host_to_driver(u16 channel) |
---|
1131 | 1642 | { |
---|
1132 | 1643 | chanspec_t chanspec; |
---|
| 1644 | + chanspec_band_t band; |
---|
1133 | 1645 | |
---|
1134 | | - chanspec = channel & WL_CHANSPEC_CHAN_MASK; |
---|
| 1646 | + band = WL_CHANNEL_BAND(channel); |
---|
1135 | 1647 | |
---|
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 | + } |
---|
1144 | 1652 | |
---|
1145 | 1653 | return wl_chspec_host_to_driver(chanspec); |
---|
1146 | 1654 | } |
---|
.. | .. |
---|
1170 | 1678 | char *c = NULL; |
---|
1171 | 1679 | int count = 0; |
---|
1172 | 1680 | |
---|
1173 | | - memset(n, 0, ETHER_ADDR_LEN); |
---|
| 1681 | + bzero(n, ETHER_ADDR_LEN); |
---|
1174 | 1682 | for (;;) { |
---|
1175 | 1683 | n->octet[count++] = (uint8)simple_strtoul(a, &c, 16); |
---|
1176 | 1684 | if (!*c++ || count == ETHER_ADDR_LEN) |
---|
.. | .. |
---|
1190 | 1698 | [NL80211_IFTYPE_STATION] = { |
---|
1191 | 1699 | .tx = 0xffff, |
---|
1192 | 1700 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | |
---|
| 1701 | +#ifdef WL_SAE |
---|
| 1702 | + BIT(IEEE80211_STYPE_AUTH >> 4) | |
---|
| 1703 | +#endif /* WL_SAE */ |
---|
1193 | 1704 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
---|
1194 | 1705 | }, |
---|
1195 | 1706 | [NL80211_IFTYPE_AP] = { |
---|
.. | .. |
---|
1259 | 1770 | key->iv_initialized = dtoh32(key->iv_initialized); |
---|
1260 | 1771 | } |
---|
1261 | 1772 | |
---|
| 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 | + |
---|
1262 | 1814 | /* Dump the contents of the encoded wps ie buffer and get pbc value */ |
---|
1263 | 1815 | 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) |
---|
1265 | 1817 | { |
---|
1266 | 1818 | #define WPS_IE_FIXED_LEN 6 |
---|
1267 | | - u16 len; |
---|
1268 | | - u8 *subel = NULL; |
---|
| 1819 | + s16 len; |
---|
| 1820 | + const u8 *subel = NULL; |
---|
1269 | 1821 | u16 subelt_id; |
---|
1270 | 1822 | u16 subelt_len; |
---|
1271 | 1823 | u16 val; |
---|
.. | .. |
---|
1274 | 1826 | WL_ERR(("invalid argument : NULL\n")); |
---|
1275 | 1827 | return; |
---|
1276 | 1828 | } |
---|
1277 | | - len = (u16)wps_ie[TLV_LEN_OFF]; |
---|
| 1829 | + len = (s16)wps_ie[TLV_LEN_OFF]; |
---|
1278 | 1830 | |
---|
1279 | 1831 | if (len > wps_ie_len) { |
---|
1280 | 1832 | WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len)); |
---|
.. | .. |
---|
1293 | 1845 | subelt_len = HTON16(val); |
---|
1294 | 1846 | |
---|
1295 | 1847 | 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 | + } |
---|
1297 | 1852 | WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n", |
---|
1298 | 1853 | subel, subelt_id, subelt_len)); |
---|
1299 | 1854 | |
---|
.. | .. |
---|
1306 | 1861 | valptr[1] = *(subel + 1); |
---|
1307 | 1862 | WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val))); |
---|
1308 | 1863 | } 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 | + } |
---|
1314 | 1874 | } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) { |
---|
1315 | 1875 | valptr[0] = *subel; |
---|
1316 | 1876 | valptr[1] = *(subel + 1); |
---|
.. | .. |
---|
1349 | 1909 | s32 err = 0; |
---|
1350 | 1910 | s32 disable = 0; |
---|
1351 | 1911 | s32 txpwrqdbm; |
---|
1352 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 1912 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
1353 | 1913 | |
---|
1354 | 1914 | /* Make sure radio is off or on as far as software is concerned */ |
---|
1355 | 1915 | disable = WL_RADIO_SW_DISABLE << 16; |
---|
1356 | 1916 | 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)); |
---|
1358 | 1918 | if (unlikely(err)) { |
---|
1359 | 1919 | WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); |
---|
1360 | 1920 | return err; |
---|
.. | .. |
---|
1363 | 1923 | if (dbm > 0xffff) |
---|
1364 | 1924 | dbm = 0xffff; |
---|
1365 | 1925 | 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 */ |
---|
1366 | 1932 | err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm, |
---|
1367 | 1933 | sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, |
---|
1368 | 1934 | &cfg->ioctl_buf_sync); |
---|
.. | .. |
---|
1378 | 1944 | { |
---|
1379 | 1945 | s32 err = 0; |
---|
1380 | 1946 | s32 txpwrdbm; |
---|
1381 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 1947 | + char ioctl_buf[WLC_IOCTL_SMLEN]; |
---|
1382 | 1948 | |
---|
1383 | 1949 | 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); |
---|
1385 | 1951 | if (unlikely(err)) { |
---|
1386 | 1952 | WL_ERR(("error (%d)\n", err)); |
---|
1387 | 1953 | return err; |
---|
1388 | 1954 | } |
---|
1389 | 1955 | |
---|
1390 | | - memcpy(&txpwrdbm, cfg->ioctl_buf, sizeof(txpwrdbm)); |
---|
| 1956 | + memcpy(&txpwrdbm, ioctl_buf, sizeof(txpwrdbm)); |
---|
1391 | 1957 | txpwrdbm = dtoh32(txpwrdbm); |
---|
1392 | 1958 | *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4; |
---|
1393 | 1959 | |
---|
1394 | | - WL_INFORM(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm)); |
---|
| 1960 | + WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm)); |
---|
1395 | 1961 | |
---|
1396 | 1962 | return err; |
---|
1397 | 1963 | } |
---|
.. | .. |
---|
1399 | 1965 | static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) |
---|
1400 | 1966 | { |
---|
1401 | 1967 | chanspec_t chspec; |
---|
1402 | | - int err = 0; |
---|
| 1968 | + int cur_band, err = 0; |
---|
1403 | 1969 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
1404 | 1970 | struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); |
---|
1405 | 1971 | 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; |
---|
1408 | 1974 | char *buf; |
---|
1409 | 1975 | |
---|
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)))) { |
---|
1412 | 1978 | /* STA interface is not associated. So start the new interface on a temp |
---|
1413 | 1979 | * channel . Later proper channel will be applied by the above framework |
---|
1414 | 1980 | * via set_channel (cfg80211 API). |
---|
1415 | 1981 | */ |
---|
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; |
---|
1422 | 1989 | } |
---|
| 1990 | + return wl_ch_host_to_driver(channel); |
---|
1423 | 1991 | } |
---|
1424 | | - |
---|
1425 | | - buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); |
---|
| 1992 | + |
---|
| 1993 | + buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX); |
---|
1426 | 1994 | if (!buf) { |
---|
1427 | 1995 | 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); |
---|
1429 | 1997 | } |
---|
1430 | 1998 | |
---|
1431 | 1999 | *(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))) { |
---|
1434 | 2002 | 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); |
---|
1436 | 2004 | } |
---|
1437 | 2005 | 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 */ |
---|
1440 | 2015 | |
---|
1441 | 2016 | WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec)); |
---|
1442 | 2017 | } |
---|
1443 | 2018 | |
---|
1444 | | - kfree(buf); |
---|
| 2019 | + MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX); |
---|
1445 | 2020 | return chspec; |
---|
1446 | 2021 | } |
---|
1447 | 2022 | |
---|
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) |
---|
1450 | 2929 | { |
---|
1451 | 2930 | #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")); |
---|
1453 | 2932 | return ERR_PTR(-EOPNOTSUPP); |
---|
1454 | 2933 | #else |
---|
| 2934 | + struct wireless *wdev; |
---|
1455 | 2935 | struct net_device* ndev = NULL; |
---|
1456 | 2936 | |
---|
1457 | 2937 | 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; |
---|
1460 | 2952 | #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; |
---|
1461 | 3376 | } |
---|
1462 | 3377 | |
---|
1463 | 3378 | static bcm_struct_cfgdev * |
---|
.. | .. |
---|
1470 | 3385 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) |
---|
1471 | 3386 | unsigned char name_assign_type, |
---|
1472 | 3387 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */ |
---|
1473 | | -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) |
---|
1474 | 3388 | 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) */ |
---|
1478 | 3392 | struct vif_params *params) |
---|
1479 | 3393 | { |
---|
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; |
---|
1489 | 3396 | 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; |
---|
1505 | 3399 | |
---|
1506 | | - if (!cfg) |
---|
| 3400 | + WL_DBG(("Enter iftype: %d\n", type)); |
---|
| 3401 | + if (!cfg) { |
---|
1507 | 3402 | 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 | + } |
---|
1517 | 3404 | |
---|
1518 | 3405 | /* Use primary I/F for sending cmds down to firmware */ |
---|
1519 | 3406 | primary_ndev = bcmcfg_to_prmry_ndev(cfg); |
---|
1520 | | - |
---|
1521 | 3407 | if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) { |
---|
1522 | 3408 | WL_ERR(("device is not ready\n")); |
---|
1523 | 3409 | return ERR_PTR(-ENODEV); |
---|
1524 | 3410 | } |
---|
1525 | 3411 | |
---|
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 | | - |
---|
1585 | 3412 | 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)) { |
---|
1587 | 3423 | return ERR_PTR(-ENODEV); |
---|
1588 | 3424 | } |
---|
1589 | | - if (cfg->p2p_supported && (wlif_type != -1)) { |
---|
1590 | | - ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */ |
---|
1591 | 3425 | |
---|
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 | +} |
---|
1600 | 3428 | |
---|
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); |
---|
1759 | 3436 | #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; |
---|
1763 | 3498 | } 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--; |
---|
1787 | 3502 | } |
---|
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; |
---|
1808 | 3504 | } |
---|
1809 | 3505 | } |
---|
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; |
---|
1814 | 3602 | } |
---|
1815 | 3603 | |
---|
1816 | 3604 | static s32 |
---|
1817 | 3605 | wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) |
---|
1818 | 3606 | { |
---|
1819 | | - struct net_device *dev = NULL; |
---|
1820 | | - struct ether_addr p2p_mac; |
---|
1821 | 3607 | 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; |
---|
1830 | 3613 | |
---|
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; |
---|
1839 | 3616 | } |
---|
1840 | | -#endif /* WL_CFG80211_P2P_DEV_IF */ |
---|
1841 | | - dev = cfgdev_to_wlc_ndev(cfgdev, cfg); |
---|
1842 | 3617 | |
---|
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; |
---|
1855 | 3623 | } |
---|
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); |
---|
1860 | 3624 | |
---|
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; |
---|
1940 | 3629 | } |
---|
| 3630 | + |
---|
| 3631 | + if ((ret = wl_cfg80211_del_if(cfg, primary_ndev, |
---|
| 3632 | + wdev, NULL)) < 0) { |
---|
| 3633 | + WL_ERR(("IF del failed\n")); |
---|
| 3634 | + } |
---|
| 3635 | + |
---|
1941 | 3636 | return ret; |
---|
1942 | 3637 | } |
---|
1943 | 3638 | |
---|
1944 | 3639 | 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) |
---|
1952 | 3641 | { |
---|
1953 | | - s32 ap = 0; |
---|
1954 | | - s32 infra = 0; |
---|
1955 | | - s32 ibss = 0; |
---|
1956 | 3642 | s32 wlif_type; |
---|
1957 | 3643 | s32 mode = 0; |
---|
1958 | | - s32 err = BCME_OK; |
---|
1959 | 3644 | s32 index; |
---|
| 3645 | + s32 err; |
---|
1960 | 3646 | s32 conn_idx = -1; |
---|
1961 | 3647 | chanspec_t chspec; |
---|
1962 | 3648 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
1963 | | - struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); |
---|
1964 | 3649 | 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 */ |
---|
1965 | 3653 | |
---|
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 | + |
---|
1967 | 3797 | 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; |
---|
1968 | 3840 | case NL80211_IFTYPE_MONITOR: |
---|
1969 | 3841 | case NL80211_IFTYPE_WDS: |
---|
1970 | 3842 | 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 */ |
---|
1992 | 3844 | 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; |
---|
2063 | 3848 | } |
---|
2064 | 3849 | |
---|
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; |
---|
2073 | 3854 | } |
---|
2074 | 3855 | |
---|
| 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 */ |
---|
2075 | 3860 | 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; |
---|
2077 | 3870 | } |
---|
2078 | 3871 | |
---|
2079 | 3872 | 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) |
---|
2081 | 3875 | { |
---|
2082 | 3876 | 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; |
---|
2084 | 3879 | |
---|
2085 | 3880 | /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd") |
---|
2086 | 3881 | * redirect the IF_ADD event to ifchange as it is not a real "new" interface |
---|
2087 | 3882 | */ |
---|
2088 | 3883 | 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); |
---|
2090 | 3885 | |
---|
2091 | 3886 | /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */ |
---|
2092 | 3887 | if (wl_get_p2p_status(cfg, IF_ADDING)) { |
---|
.. | .. |
---|
2094 | 3889 | wl_clr_p2p_status(cfg, IF_ADDING); |
---|
2095 | 3890 | } else if (cfg->bss_pending_op) { |
---|
2096 | 3891 | ifadd_expected = TRUE; |
---|
2097 | | - cfg->bss_pending_op = FALSE; |
---|
| 3892 | + bss_pending_op = FALSE; |
---|
2098 | 3893 | } |
---|
2099 | 3894 | |
---|
2100 | 3895 | if (ifadd_expected) { |
---|
.. | .. |
---|
2103 | 3898 | if_event_info->valid = TRUE; |
---|
2104 | 3899 | if_event_info->ifidx = ifidx; |
---|
2105 | 3900 | 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'; |
---|
2108 | 3904 | if (mac) |
---|
2109 | 3905 | 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(); |
---|
2110 | 3914 | wake_up_interruptible(&cfg->netif_change_event); |
---|
2111 | 3915 | return BCME_OK; |
---|
2112 | 3916 | } |
---|
.. | .. |
---|
2115 | 3919 | } |
---|
2116 | 3920 | |
---|
2117 | 3921 | 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) |
---|
2119 | 3923 | { |
---|
2120 | 3924 | bool ifdel_expected = FALSE; |
---|
2121 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 3925 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
2122 | 3926 | wl_if_event_info *if_event_info = &cfg->if_event_info; |
---|
| 3927 | + bool bss_pending_op = TRUE; |
---|
2123 | 3928 | |
---|
2124 | 3929 | if (wl_get_p2p_status(cfg, IF_DELETING)) { |
---|
2125 | 3930 | ifdel_expected = TRUE; |
---|
2126 | 3931 | wl_clr_p2p_status(cfg, IF_DELETING); |
---|
2127 | 3932 | } else if (cfg->bss_pending_op) { |
---|
2128 | 3933 | ifdel_expected = TRUE; |
---|
2129 | | - cfg->bss_pending_op = FALSE; |
---|
| 3934 | + bss_pending_op = FALSE; |
---|
2130 | 3935 | } |
---|
2131 | 3936 | |
---|
2132 | 3937 | if (ifdel_expected) { |
---|
2133 | 3938 | if_event_info->valid = TRUE; |
---|
2134 | 3939 | if_event_info->ifidx = ifidx; |
---|
2135 | 3940 | 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(); |
---|
2136 | 3947 | wake_up_interruptible(&cfg->netif_change_event); |
---|
2137 | 3948 | return BCME_OK; |
---|
2138 | 3949 | } |
---|
.. | .. |
---|
2141 | 3952 | } |
---|
2142 | 3953 | |
---|
2143 | 3954 | 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) |
---|
2145 | 3957 | { |
---|
2146 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 3958 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
2147 | 3959 | |
---|
2148 | 3960 | if (wl_get_p2p_status(cfg, IF_CHANGING)) { |
---|
2149 | 3961 | wl_set_p2p_status(cfg, IF_CHANGED); |
---|
| 3962 | + OSL_SMP_WMB(); |
---|
2150 | 3963 | wake_up_interruptible(&cfg->netif_change_event); |
---|
2151 | 3964 | return BCME_OK; |
---|
2152 | 3965 | } |
---|
2153 | 3966 | |
---|
2154 | 3967 | 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(¶ms->bssid, ðer_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(¶ms->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(¶ms->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; |
---|
2985 | 3968 | } |
---|
2986 | 3969 | |
---|
2987 | 3970 | static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) |
---|
.. | .. |
---|
3013 | 3996 | s32 err = 0; |
---|
3014 | 3997 | u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); |
---|
3015 | 3998 | |
---|
| 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 | + |
---|
3016 | 4007 | retry = htod32(retry); |
---|
3017 | | - err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true); |
---|
| 4008 | + err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry)); |
---|
3018 | 4009 | if (unlikely(err)) { |
---|
3019 | 4010 | WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); |
---|
3020 | 4011 | return err; |
---|
.. | .. |
---|
3073 | 4064 | int bw = 0, tmp_bw = 0; |
---|
3074 | 4065 | int i; |
---|
3075 | 4066 | u32 tmp_c; |
---|
3076 | | - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; |
---|
| 4067 | + |
---|
3077 | 4068 | #define LOCAL_BUF_SIZE 1024 |
---|
3078 | | - buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags); |
---|
| 4069 | + buf = (u8 *)MALLOC(cfg->osh, LOCAL_BUF_SIZE); |
---|
3079 | 4070 | if (!buf) { |
---|
3080 | 4071 | WL_ERR(("buf memory alloc failed\n")); |
---|
3081 | 4072 | goto exit; |
---|
.. | .. |
---|
3113 | 4104 | } |
---|
3114 | 4105 | } |
---|
3115 | 4106 | exit: |
---|
3116 | | - if (buf) |
---|
3117 | | - kfree(buf); |
---|
| 4107 | + if (buf) { |
---|
| 4108 | + MFREE(cfg->osh, buf, LOCAL_BUF_SIZE); |
---|
| 4109 | + } |
---|
3118 | 4110 | #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)); |
---|
3120 | 4112 | return ret_c; |
---|
3121 | 4113 | } |
---|
3122 | 4114 | |
---|
3123 | 4115 | 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) |
---|
3125 | 4118 | { |
---|
3126 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 4119 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
3127 | 4120 | |
---|
3128 | 4121 | if (cfg != NULL && ibss_vsie != NULL) { |
---|
3129 | 4122 | if (cfg->ibss_vsie != NULL) { |
---|
3130 | | - kfree(cfg->ibss_vsie); |
---|
| 4123 | + MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len); |
---|
3131 | 4124 | } |
---|
3132 | 4125 | cfg->ibss_vsie = ibss_vsie; |
---|
3133 | 4126 | cfg->ibss_vsie_len = ibss_vsie_len; |
---|
.. | .. |
---|
3139 | 4132 | { |
---|
3140 | 4133 | /* free & initiralize VSIE (Vendor Specific IE) */ |
---|
3141 | 4134 | 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); |
---|
3144 | 4136 | cfg->ibss_vsie_len = 0; |
---|
3145 | 4137 | } |
---|
3146 | 4138 | } |
---|
.. | .. |
---|
3148 | 4140 | s32 |
---|
3149 | 4141 | wl_cfg80211_ibss_vsie_delete(struct net_device *dev) |
---|
3150 | 4142 | { |
---|
3151 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 4143 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
3152 | 4144 | char *ioctl_buf = NULL; |
---|
3153 | | - s32 ret = BCME_OK; |
---|
| 4145 | + s32 ret = BCME_OK, bssidx; |
---|
3154 | 4146 | |
---|
3155 | 4147 | 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); |
---|
3157 | 4149 | if (!ioctl_buf) { |
---|
3158 | 4150 | WL_ERR(("ioctl memory alloc failed\n")); |
---|
3159 | 4151 | return -ENOMEM; |
---|
3160 | 4152 | } |
---|
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 | + } |
---|
3162 | 4158 | /* 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)); |
---|
3165 | 4160 | |
---|
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); |
---|
3169 | 4164 | WL_ERR(("ret=%d\n", ret)); |
---|
3170 | 4165 | |
---|
3171 | 4166 | 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); |
---|
3175 | 4169 | cfg->ibss_vsie_len = 0; |
---|
3176 | 4170 | } |
---|
3177 | | - |
---|
| 4171 | +end: |
---|
3178 | 4172 | if (ioctl_buf) { |
---|
3179 | | - kfree(ioctl_buf); |
---|
| 4173 | + MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN); |
---|
3180 | 4174 | } |
---|
3181 | 4175 | } |
---|
3182 | 4176 | |
---|
.. | .. |
---|
3192 | 4186 | struct wireless_dev* wdev = NULL; |
---|
3193 | 4187 | struct net_device *new_ndev = NULL; |
---|
3194 | 4188 | struct net_device *primary_ndev = NULL; |
---|
3195 | | - s32 timeout; |
---|
| 4189 | + long timeout; |
---|
3196 | 4190 | wl_aibss_if_t aibss_if; |
---|
3197 | 4191 | wl_if_event_info *event = NULL; |
---|
3198 | 4192 | |
---|
.. | .. |
---|
3206 | 4200 | /* generate a new MAC address for the IBSS interface */ |
---|
3207 | 4201 | get_primary_mac(cfg, &cfg->ibss_if_addr); |
---|
3208 | 4202 | cfg->ibss_if_addr.octet[4] ^= 0x40; |
---|
3209 | | - memset(&aibss_if, sizeof(aibss_if), 0); |
---|
| 4203 | + bzero(&aibss_if, sizeof(aibss_if)); |
---|
3210 | 4204 | memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr)); |
---|
3211 | 4205 | aibss_if.chspec = 0; |
---|
3212 | 4206 | aibss_if.len = sizeof(aibss_if); |
---|
3213 | 4207 | |
---|
3214 | 4208 | 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)); |
---|
3216 | 4210 | 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); |
---|
3218 | 4212 | if (err) { |
---|
3219 | 4213 | WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err)); |
---|
3220 | 4214 | goto fail; |
---|
.. | .. |
---|
3235 | 4229 | event->mac, event->bssidx, event->name); |
---|
3236 | 4230 | if (new_ndev == NULL) |
---|
3237 | 4231 | goto fail; |
---|
3238 | | - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); |
---|
| 4232 | + wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev)); |
---|
3239 | 4233 | if (wdev == NULL) |
---|
3240 | 4234 | goto fail; |
---|
3241 | 4235 | wdev->wiphy = wiphy; |
---|
.. | .. |
---|
3248 | 4242 | * needs to be modified to take one parameter (bool need_rtnl_lock) |
---|
3249 | 4243 | */ |
---|
3250 | 4244 | 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) |
---|
3252 | 4246 | goto fail; |
---|
3253 | 4247 | |
---|
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); |
---|
3255 | 4250 | cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev); |
---|
3256 | 4251 | WL_ERR(("IBSS interface %s created\n", new_ndev->name)); |
---|
3257 | 4252 | return cfg->ibss_cfgdev; |
---|
.. | .. |
---|
3260 | 4255 | WL_ERR(("failed to create IBSS interface %s \n", name)); |
---|
3261 | 4256 | cfg->bss_pending_op = FALSE; |
---|
3262 | 4257 | 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 | + } |
---|
3266 | 4262 | return NULL; |
---|
3267 | 4263 | } |
---|
3268 | 4264 | |
---|
.. | .. |
---|
3273 | 4269 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
3274 | 4270 | struct net_device *ndev = NULL; |
---|
3275 | 4271 | struct net_device *primary_ndev = NULL; |
---|
3276 | | - s32 timeout; |
---|
| 4272 | + long timeout; |
---|
3277 | 4273 | |
---|
3278 | 4274 | if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet)) |
---|
3279 | 4275 | return -EINVAL; |
---|
.. | .. |
---|
3281 | 4277 | primary_ndev = bcmcfg_to_prmry_ndev(cfg); |
---|
3282 | 4278 | |
---|
3283 | 4279 | 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)); |
---|
3285 | 4281 | 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); |
---|
3287 | 4283 | if (err) { |
---|
3288 | 4284 | WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err)); |
---|
3289 | 4285 | goto fail; |
---|
.. | .. |
---|
3295 | 4291 | goto fail; |
---|
3296 | 4292 | } |
---|
3297 | 4293 | |
---|
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); |
---|
3299 | 4295 | cfg->ibss_cfgdev = NULL; |
---|
3300 | 4296 | return 0; |
---|
3301 | 4297 | |
---|
.. | .. |
---|
3306 | 4302 | #endif /* WLAIBSS_MCHAN */ |
---|
3307 | 4303 | |
---|
3308 | 4304 | 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) |
---|
3312 | 4306 | { |
---|
3313 | | - wl_interface_create_t iface; |
---|
3314 | | - s32 ret; |
---|
3315 | | - wl_interface_info_t *info; |
---|
| 4307 | + s32 ret = BCME_ERROR; |
---|
3316 | 4308 | |
---|
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; |
---|
3318 | 4332 | |
---|
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; |
---|
3344 | 4337 | } |
---|
3345 | | - |
---|
3346 | | - if (ret < 0) |
---|
3347 | | - WL_ERR(("Interface %s failed!! ret %d\n", |
---|
3348 | | - del ? "remove" : "create", ret)); |
---|
3349 | | - |
---|
3350 | 4338 | return ret; |
---|
3351 | 4339 | } |
---|
3352 | 4340 | |
---|
| 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 |
---|
3353 | 4500 | |
---|
3354 | 4501 | s32 |
---|
3355 | 4502 | wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg, |
---|
3356 | 4503 | 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) |
---|
3358 | 4505 | { |
---|
3359 | 4506 | s32 ret = BCME_OK; |
---|
3360 | 4507 | s32 val = 0; |
---|
.. | .. |
---|
3365 | 4512 | struct ether_addr ea; |
---|
3366 | 4513 | } bss_setbuf; |
---|
3367 | 4514 | |
---|
3368 | | - WL_INFORM(("iface_type:%d del:%d \n", iface_type, del)); |
---|
| 4515 | + WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype, del)); |
---|
3369 | 4516 | |
---|
3370 | 4517 | bzero(&bss_setbuf, sizeof(bss_setbuf)); |
---|
3371 | 4518 | |
---|
3372 | | - /* AP=3, STA=2, up=1, down=0, val=-1 */ |
---|
| 4519 | + /* AP=2, STA=3, up=1, down=0, val=-1 */ |
---|
3373 | 4520 | 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 */ |
---|
3377 | 4524 | 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 */ |
---|
3380 | 4528 | WL_DBG(("Adding STA Interface \n")); |
---|
3381 | | - val = 2; |
---|
| 4529 | + val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE; |
---|
3382 | 4530 | } 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)); |
---|
3384 | 4532 | return -EINVAL; |
---|
3385 | 4533 | } |
---|
3386 | 4534 | |
---|
.. | .. |
---|
3391 | 4539 | memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN); |
---|
3392 | 4540 | } |
---|
3393 | 4541 | |
---|
| 4542 | + WL_INFORM_MEM(("wl bss %d bssidx:%d iface:%s \n", val, bsscfg_idx, ndev->name)); |
---|
3394 | 4543 | ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), |
---|
3395 | 4544 | cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); |
---|
3396 | 4545 | if (ret != 0) |
---|
.. | .. |
---|
3399 | 4548 | return ret; |
---|
3400 | 4549 | } |
---|
3401 | 4550 | |
---|
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 | +} |
---|
3403 | 5063 | /* Create a Generic Network Interface and initialize it depending up on |
---|
3404 | 5064 | * the interface type |
---|
3405 | 5065 | */ |
---|
3406 | | -bcm_struct_cfgdev* |
---|
| 5066 | +struct wireless_dev * |
---|
3407 | 5067 | wl_cfg80211_create_iface(struct wiphy *wiphy, |
---|
3408 | | - enum nl80211_iftype iface_type, |
---|
| 5068 | + wl_iftype_t wl_iftype, |
---|
3409 | 5069 | u8 *mac_addr, const char *name) |
---|
3410 | 5070 | { |
---|
3411 | 5071 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
.. | .. |
---|
3413 | 5073 | struct net_device *primary_ndev = NULL; |
---|
3414 | 5074 | s32 ret = BCME_OK; |
---|
3415 | 5075 | s32 bsscfg_idx = 0; |
---|
3416 | | - u32 timeout; |
---|
| 5076 | + long timeout; |
---|
3417 | 5077 | wl_if_event_info *event = NULL; |
---|
3418 | | - struct wireless_dev *wdev = NULL; |
---|
3419 | 5078 | u8 addr[ETH_ALEN]; |
---|
| 5079 | + struct net_info *iter, *next; |
---|
3420 | 5080 | |
---|
3421 | 5081 | WL_DBG(("Enter\n")); |
---|
3422 | | - |
---|
3423 | 5082 | if (!name) { |
---|
3424 | 5083 | WL_ERR(("Interface name not provided\n")); |
---|
3425 | 5084 | return NULL; |
---|
3426 | 5085 | } |
---|
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 | + } |
---|
3428 | 5098 | primary_ndev = bcmcfg_to_prmry_ndev(cfg); |
---|
3429 | | - |
---|
3430 | 5099 | if (likely(!mac_addr)) { |
---|
3431 | 5100 | /* Use primary MAC with the locally administered bit for the |
---|
3432 | 5101 | * Secondary STA I/F |
---|
.. | .. |
---|
3438 | 5107 | memcpy(addr, mac_addr, ETH_ALEN); |
---|
3439 | 5108 | } |
---|
3440 | 5109 | |
---|
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 | | - |
---|
3447 | 5110 | 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)); |
---|
3466 | 5112 | |
---|
3467 | 5113 | /* |
---|
3468 | 5114 | * Intialize the firmware I/F. |
---|
3469 | 5115 | */ |
---|
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 | + } |
---|
3472 | 5120 | if (ret == BCME_UNSUPPORTED) { |
---|
3473 | 5121 | /* Use bssidx 1 by default */ |
---|
3474 | 5122 | bsscfg_idx = 1; |
---|
3475 | 5123 | 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; |
---|
3478 | 5126 | } |
---|
3479 | 5127 | } else if (ret < 0) { |
---|
3480 | 5128 | WL_ERR(("Interface create failed!! ret:%d \n", ret)); |
---|
3481 | | - goto fail; |
---|
| 5129 | + goto exit; |
---|
3482 | 5130 | } else { |
---|
3483 | 5131 | /* Success */ |
---|
3484 | 5132 | bsscfg_idx = ret; |
---|
3485 | 5133 | } |
---|
3486 | 5134 | |
---|
3487 | 5135 | WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx)); |
---|
3488 | | - |
---|
3489 | 5136 | /* |
---|
3490 | 5137 | * Wait till the firmware send a confirmation event back. |
---|
3491 | 5138 | */ |
---|
.. | .. |
---|
3493 | 5140 | timeout = wait_event_interruptible_timeout(cfg->netif_change_event, |
---|
3494 | 5141 | !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); |
---|
3495 | 5142 | 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; |
---|
3498 | 5149 | } |
---|
3499 | 5150 | |
---|
| 5151 | + event = &cfg->if_event_info; |
---|
3500 | 5152 | /* |
---|
3501 | 5153 | * Since FW operation is successful,we can go ahead with the |
---|
3502 | 5154 | * the host interface creation. |
---|
3503 | 5155 | */ |
---|
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); |
---|
3513 | 5158 | |
---|
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; |
---|
3518 | 5162 | } |
---|
3519 | 5163 | |
---|
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: |
---|
3557 | 5165 | 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 | | - |
---|
3564 | 5166 | return NULL; |
---|
3565 | 5167 | } |
---|
3566 | 5168 | |
---|
3567 | 5169 | 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) |
---|
3569 | 5171 | { |
---|
3570 | 5172 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
3571 | 5173 | struct net_device *ndev = NULL; |
---|
3572 | | - struct net_device *primary_ndev = NULL; |
---|
3573 | 5174 | s32 ret = BCME_OK; |
---|
3574 | 5175 | 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; |
---|
3578 | 5179 | |
---|
3579 | 5180 | WL_DBG(("Enter\n")); |
---|
3580 | | - |
---|
3581 | | - if (!cfg->bss_cfgdev) |
---|
3582 | | - return 0; |
---|
3583 | 5181 | |
---|
3584 | 5182 | /* If any scan is going on, abort it */ |
---|
3585 | 5183 | if (wl_get_drv_status_all(cfg, SCANNING)) { |
---|
3586 | 5184 | 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); |
---|
3588 | 5186 | } |
---|
3589 | 5187 | |
---|
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 | + } |
---|
3592 | 5194 | |
---|
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 | + |
---|
3594 | 5210 | memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info)); |
---|
3595 | 5211 | |
---|
| 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)); |
---|
3596 | 5219 | /* Delete the firmware interface. "interface_remove" command |
---|
3597 | 5220 | * should go on the interface to be deleted |
---|
3598 | 5221 | */ |
---|
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); |
---|
3601 | 5231 | if (ret == BCME_UNSUPPORTED) { |
---|
3602 | 5232 | 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) { |
---|
3604 | 5234 | WL_ERR(("DEL bss failed ret:%d \n", ret)); |
---|
3605 | 5235 | goto exit; |
---|
3606 | 5236 | } |
---|
| 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; |
---|
3607 | 5245 | } else if (ret < 0) { |
---|
3608 | 5246 | WL_ERR(("Interface DEL failed ret:%d \n", ret)); |
---|
3609 | 5247 | goto exit; |
---|
.. | .. |
---|
3613 | 5251 | !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME)); |
---|
3614 | 5252 | if (timeout <= 0 || cfg->bss_pending_op) { |
---|
3615 | 5253 | 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 */ |
---|
3616 | 5257 | } |
---|
3617 | 5258 | |
---|
3618 | 5259 | 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 | + } |
---|
3624 | 5278 | |
---|
3625 | | - WL_DBG(("IF_DEL Done.\n")); |
---|
3626 | | - |
---|
| 5279 | + cfg->bss_pending_op = false; |
---|
3627 | 5280 | return ret; |
---|
3628 | 5281 | } |
---|
3629 | | -#endif /* defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) */ |
---|
3630 | 5282 | |
---|
3631 | 5283 | static s32 |
---|
3632 | 5284 | wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, |
---|
.. | .. |
---|
3647 | 5299 | |
---|
3648 | 5300 | WL_TRACE(("In\n")); |
---|
3649 | 5301 | 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) { |
---|
3652 | 5305 | WL_ERR(("Invalid parameter\n")); |
---|
3653 | 5306 | return -EINVAL; |
---|
3654 | 5307 | } |
---|
.. | .. |
---|
3711 | 5364 | } else { |
---|
3712 | 5365 | cfg->ibss_starter = true; |
---|
3713 | 5366 | } |
---|
| 5367 | + |
---|
| 5368 | + if (bss) { |
---|
| 5369 | + CFG80211_PUT_BSS(wiphy, bss); |
---|
| 5370 | + } |
---|
| 5371 | + |
---|
3714 | 5372 | if (chan) { |
---|
3715 | 5373 | if (chan->band == IEEE80211_BAND_5GHZ) |
---|
3716 | 5374 | param[0] = WLC_BAND_5G; |
---|
.. | .. |
---|
3728 | 5386 | * Join with specific BSSID and cached SSID |
---|
3729 | 5387 | * If SSID is zero join based on BSSID only |
---|
3730 | 5388 | */ |
---|
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, |
---|
3733 | 5391 | params->ssid_len); |
---|
3734 | 5392 | join_params.ssid.SSID_len = htod32(params->ssid_len); |
---|
3735 | 5393 | if (params->bssid) { |
---|
3736 | 5394 | 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); |
---|
3739 | 5397 | if (unlikely(err)) { |
---|
3740 | 5398 | WL_ERR(("Error (%d)\n", err)); |
---|
3741 | 5399 | return err; |
---|
3742 | 5400 | } |
---|
3743 | 5401 | } 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); |
---|
3746 | 5403 | |
---|
3747 | 5404 | if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { |
---|
3748 | 5405 | scan_suppress = TRUE; |
---|
3749 | 5406 | /* 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)); |
---|
3752 | 5409 | if (unlikely(err)) { |
---|
3753 | 5410 | WL_ERR(("Scan Suppress Setting Failed (%d)\n", err)); |
---|
3754 | 5411 | return err; |
---|
.. | .. |
---|
3764 | 5421 | wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED); |
---|
3765 | 5422 | wldev_iovar_setint(dev, "wsec", 0); |
---|
3766 | 5423 | |
---|
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); |
---|
3770 | 5426 | if (unlikely(err)) { |
---|
3771 | | - WL_ERR(("Error (%d)\n", err)); |
---|
| 5427 | + WL_ERR(("IBSS set_ssid Error (%d)\n", err)); |
---|
3772 | 5428 | return err; |
---|
3773 | 5429 | } |
---|
3774 | 5430 | |
---|
3775 | 5431 | if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { |
---|
3776 | 5432 | scan_suppress = FALSE; |
---|
3777 | 5433 | /* 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)); |
---|
3780 | 5436 | if (unlikely(err)) { |
---|
3781 | 5437 | WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err)); |
---|
3782 | 5438 | return err; |
---|
.. | .. |
---|
3784 | 5440 | } |
---|
3785 | 5441 | wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); |
---|
3786 | 5442 | 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 |
---|
3787 | 5447 | cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */ |
---|
| 5448 | +#endif /* WL_RELMCAST */ |
---|
3788 | 5449 | return err; |
---|
3789 | 5450 | } |
---|
3790 | 5451 | |
---|
.. | .. |
---|
3798 | 5459 | RETURN_EIO_IF_NOT_UP(cfg); |
---|
3799 | 5460 | wl_link_down(cfg); |
---|
3800 | 5461 | |
---|
3801 | | - WL_ERR(("Leave IBSS\n")); |
---|
| 5462 | + WL_INFORM_MEM(("Leave IBSS\n")); |
---|
3802 | 5463 | curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); |
---|
3803 | 5464 | wl_set_drv_status(cfg, DISCONNECTING, dev); |
---|
3804 | 5465 | scbval.val = 0; |
---|
3805 | 5466 | 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)); |
---|
3808 | 5469 | if (unlikely(err)) { |
---|
3809 | 5470 | wl_clr_drv_status(cfg, DISCONNECTING, dev); |
---|
3810 | 5471 | WL_ERR(("error(%d)\n", err)); |
---|
.. | .. |
---|
3818 | 5479 | } |
---|
3819 | 5480 | |
---|
3820 | 5481 | #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) |
---|
3822 | 5485 | { |
---|
3823 | 5486 | 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; |
---|
3828 | 5491 | |
---|
3829 | 5492 | if (!wpa2ie) |
---|
3830 | | - return -1; |
---|
| 5493 | + return BCME_BADARG; |
---|
3831 | 5494 | |
---|
3832 | 5495 | 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]; |
---|
3837 | 5510 | suite_count = ltoh16_ua(&ucast->count); |
---|
3838 | 5511 | if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || |
---|
3839 | 5512 | (len -= (WPA_IE_SUITE_COUNT_LEN + |
---|
3840 | 5513 | (WPA_SUITE_LEN * suite_count))) <= 0) |
---|
3841 | 5514 | 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]; |
---|
3843 | 5522 | suite_count = ltoh16_ua(&mgmt->count); |
---|
3844 | 5523 | |
---|
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 { |
---|
3851 | 5529 | return BCME_BADLEN; |
---|
| 5530 | + } |
---|
3852 | 5531 | |
---|
3853 | | - return 0; |
---|
| 5532 | + return BCME_OK; |
---|
3854 | 5533 | } |
---|
3855 | 5534 | #endif /* MFP */ |
---|
3856 | 5535 | |
---|
3857 | 5536 | static s32 |
---|
3858 | 5537 | wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) |
---|
3859 | 5538 | { |
---|
3860 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 5539 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
3861 | 5540 | struct wl_security *sec; |
---|
3862 | 5541 | s32 val = 0; |
---|
3863 | 5542 | s32 err = 0; |
---|
.. | .. |
---|
3872 | 5551 | val = WPA_AUTH_PSK | |
---|
3873 | 5552 | WPA_AUTH_UNSPECIFIED; |
---|
3874 | 5553 | 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 */ |
---|
3877 | 5570 | else |
---|
3878 | 5571 | val = WPA_AUTH_DISABLED; |
---|
3879 | 5572 | |
---|
3880 | 5573 | if (is_wps_conn(sme)) |
---|
3881 | 5574 | val = WPA_AUTH_DISABLED; |
---|
3882 | 5575 | |
---|
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)); |
---|
3884 | 5584 | err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); |
---|
3885 | 5585 | if (unlikely(err)) { |
---|
3886 | 5586 | WL_ERR(("set wpa_auth failed (%d)\n", err)); |
---|
.. | .. |
---|
3891 | 5591 | return err; |
---|
3892 | 5592 | } |
---|
3893 | 5593 | |
---|
| 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 */ |
---|
3894 | 5618 | |
---|
3895 | 5619 | static s32 |
---|
3896 | 5620 | wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) |
---|
3897 | 5621 | { |
---|
3898 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 5622 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
3899 | 5623 | struct wl_security *sec; |
---|
3900 | 5624 | s32 val = 0; |
---|
3901 | 5625 | s32 err = 0; |
---|
.. | .. |
---|
3919 | 5643 | val = WL_AUTH_OPEN_SHARED; |
---|
3920 | 5644 | WL_DBG(("automatic\n")); |
---|
3921 | 5645 | 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 */ |
---|
3922 | 5666 | default: |
---|
3923 | 5667 | val = 2; |
---|
3924 | 5668 | WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); |
---|
3925 | 5669 | break; |
---|
3926 | 5670 | } |
---|
3927 | 5671 | |
---|
| 5672 | + WL_INFORM_MEM(("[%s] wl auth 0x%0x \n", dev->name, val)); |
---|
3928 | 5673 | err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); |
---|
3929 | 5674 | if (unlikely(err)) { |
---|
3930 | 5675 | WL_ERR(("set auth failed (%d)\n", err)); |
---|
.. | .. |
---|
3935 | 5680 | return err; |
---|
3936 | 5681 | } |
---|
3937 | 5682 | |
---|
| 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 | + |
---|
3938 | 5722 | static s32 |
---|
3939 | 5723 | wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) |
---|
3940 | 5724 | { |
---|
3941 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 5725 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
3942 | 5726 | struct wl_security *sec; |
---|
3943 | 5727 | s32 pval = 0; |
---|
3944 | 5728 | s32 gval = 0; |
---|
3945 | 5729 | s32 err = 0; |
---|
3946 | 5730 | s32 wsec_val = 0; |
---|
3947 | | - |
---|
| 5731 | +#ifdef BCMWAPI_WPI |
---|
| 5732 | + s32 wapi_val = 0; |
---|
| 5733 | + s32 val = 0; |
---|
| 5734 | +#endif // endif |
---|
3948 | 5735 | s32 bssidx; |
---|
| 5736 | +#ifdef WL_GCMP |
---|
| 5737 | + uint32 algos = 0, mask = 0; |
---|
| 5738 | +#endif /* WL_GCMP */ |
---|
3949 | 5739 | |
---|
3950 | 5740 | if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { |
---|
3951 | 5741 | WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); |
---|
.. | .. |
---|
3953 | 5743 | } |
---|
3954 | 5744 | |
---|
3955 | 5745 | 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 | + } |
---|
3956 | 5751 | 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 | + } |
---|
3960 | 5769 | 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); |
---|
3963 | 5777 | 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 */ |
---|
3967 | 5780 | break; |
---|
3968 | | - default: |
---|
3969 | | - WL_ERR(("invalid cipher pairwise (%d)\n", |
---|
3970 | | - sme->crypto.ciphers_pairwise[0])); |
---|
3971 | | - return -EINVAL; |
---|
3972 | 5781 | } |
---|
3973 | 5782 | } |
---|
| 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 */ |
---|
3974 | 5801 | 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 | + } |
---|
3975 | 5807 | 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; |
---|
3979 | 5811 | 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); |
---|
3982 | 5819 | break; |
---|
3983 | | - case WLAN_CIPHER_SUITE_CCMP: |
---|
3984 | | - gval = AES_ENABLED; |
---|
| 5820 | +#endif /* WL_GCMP */ |
---|
| 5821 | + default: /* No post processing required */ |
---|
3985 | 5822 | 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; |
---|
3993 | 5823 | } |
---|
3994 | 5824 | } |
---|
3995 | 5825 | |
---|
3996 | 5826 | 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 */ |
---|
3997 | 5830 | |
---|
3998 | 5831 | 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 { |
---|
4002 | 5835 | /* WPS-2.0 allows no security */ |
---|
4003 | | - err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); |
---|
| 5836 | + wsec_val = 0; |
---|
| 5837 | + } |
---|
4004 | 5838 | } 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 | + { |
---|
4005 | 5846 | WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); |
---|
4006 | 5847 | 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 | + } |
---|
4011 | 5849 | } |
---|
| 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); |
---|
4012 | 5853 | if (unlikely(err)) { |
---|
4013 | 5854 | WL_ERR(("error (%d)\n", err)); |
---|
4014 | 5855 | return err; |
---|
4015 | 5856 | } |
---|
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 */ |
---|
4017 | 5862 | sec = wl_read_prof(cfg, dev, WL_PROF_SEC); |
---|
4018 | 5863 | sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; |
---|
4019 | 5864 | 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", ¤t_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)); |
---|
4020 | 6243 | |
---|
4021 | 6244 | return err; |
---|
4022 | 6245 | } |
---|
| 6246 | +#endif /* WL_SAE */ |
---|
| 6247 | +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) */ |
---|
4023 | 6248 | |
---|
4024 | 6249 | static s32 |
---|
4025 | 6250 | wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) |
---|
4026 | 6251 | { |
---|
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)) */ |
---|
4028 | 6259 | struct wl_security *sec; |
---|
4029 | 6260 | s32 val = 0; |
---|
4030 | 6261 | s32 err = 0; |
---|
4031 | 6262 | 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 */ |
---|
4037 | 6263 | |
---|
4038 | 6264 | if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { |
---|
4039 | 6265 | WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); |
---|
.. | .. |
---|
4056 | 6282 | val = WPA_AUTH_PSK; |
---|
4057 | 6283 | break; |
---|
4058 | 6284 | 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])); |
---|
4061 | 6287 | return -EINVAL; |
---|
4062 | 6288 | } |
---|
4063 | 6289 | } else if (val & (WPA2_AUTH_PSK | |
---|
4064 | 6290 | WPA2_AUTH_UNSPECIFIED)) { |
---|
4065 | 6291 | switch (sme->crypto.akm_suites[0]) { |
---|
4066 | | - case WLAN_AKM_SUITE_8021X: |
---|
4067 | | - val = WPA2_AUTH_UNSPECIFIED; |
---|
4068 | | - break; |
---|
4069 | 6292 | #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 |
---|
4070 | 6309 | case WL_AKM_SUITE_SHA256_1X: |
---|
4071 | 6310 | val = WPA2_AUTH_1X_SHA256; |
---|
4072 | 6311 | break; |
---|
4073 | 6312 | case WL_AKM_SUITE_SHA256_PSK: |
---|
4074 | 6313 | val = WPA2_AUTH_PSK_SHA256; |
---|
4075 | 6314 | break; |
---|
| 6315 | +#endif // endif |
---|
4076 | 6316 | #endif /* MFP */ |
---|
| 6317 | + case WLAN_AKM_SUITE_8021X: |
---|
4077 | 6318 | case WLAN_AKM_SUITE_PSK: |
---|
4078 | | - val = WPA2_AUTH_PSK; |
---|
4079 | | - break; |
---|
4080 | 6319 | #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X) |
---|
4081 | 6320 | case WLAN_AKM_SUITE_FT_8021X: |
---|
4082 | | - val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; |
---|
4083 | | - break; |
---|
4084 | | -#endif |
---|
| 6321 | +#endif // endif |
---|
4085 | 6322 | #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK) |
---|
4086 | 6323 | 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]); |
---|
4088 | 6338 | 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; |
---|
4090 | 6345 | 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])); |
---|
4093 | 6348 | return -EINVAL; |
---|
4094 | 6349 | } |
---|
4095 | 6350 | } |
---|
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 | + } |
---|
4107 | 6365 | } |
---|
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)); |
---|
4118 | 6386 | return err; |
---|
4119 | 6387 | } |
---|
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; |
---|
4122 | 6397 | } |
---|
4123 | 6398 | #endif /* MFP */ |
---|
4124 | 6399 | |
---|
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)); |
---|
4127 | 6401 | err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); |
---|
4128 | 6402 | 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)); |
---|
4130 | 6404 | return err; |
---|
4131 | 6405 | } |
---|
4132 | 6406 | } |
---|
.. | .. |
---|
4140 | 6414 | wl_set_set_sharedkey(struct net_device *dev, |
---|
4141 | 6415 | struct cfg80211_connect_params *sme) |
---|
4142 | 6416 | { |
---|
4143 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 6417 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
4144 | 6418 | struct wl_security *sec; |
---|
4145 | 6419 | struct wl_wsec_key key; |
---|
4146 | 6420 | s32 val; |
---|
.. | .. |
---|
4159 | 6433 | sec->wpa_versions, sec->cipher_pairwise)); |
---|
4160 | 6434 | if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | |
---|
4161 | 6435 | NL80211_WPA_VERSION_2)) && |
---|
| 6436 | +#ifdef BCMWAPI_WPI |
---|
| 6437 | + !is_wapi(sec->cipher_pairwise) && |
---|
| 6438 | +#endif // endif |
---|
4162 | 6439 | (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | |
---|
4163 | 6440 | WLAN_CIPHER_SUITE_WEP104))) |
---|
4164 | 6441 | { |
---|
4165 | | - memset(&key, 0, sizeof(key)); |
---|
| 6442 | + bzero(&key, sizeof(key)); |
---|
4166 | 6443 | key.len = (u32) sme->key_len; |
---|
4167 | 6444 | key.index = (u32) sme->key_idx; |
---|
4168 | 6445 | if (unlikely(key.len > sizeof(key.data))) { |
---|
.. | .. |
---|
4171 | 6448 | } |
---|
4172 | 6449 | memcpy(key.data, sme->key, key.len); |
---|
4173 | 6450 | 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 { |
---|
4182 | 6455 | WL_ERR(("Invalid algorithm (%d)\n", |
---|
4183 | 6456 | sme->crypto.ciphers_pairwise[0])); |
---|
4184 | 6457 | return -EINVAL; |
---|
.. | .. |
---|
4194 | 6467 | WL_ERR(("WLC_SET_KEY error (%d)\n", err)); |
---|
4195 | 6468 | return err; |
---|
4196 | 6469 | } |
---|
| 6470 | + WL_INFORM_MEM(("key applied to fw\n")); |
---|
4197 | 6471 | if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { |
---|
4198 | 6472 | WL_DBG(("set auth_type to shared key\n")); |
---|
4199 | 6473 | val = WL_AUTH_SHARED_KEY; /* shared key */ |
---|
.. | .. |
---|
4213 | 6487 | static u8 broad_bssid[6]; |
---|
4214 | 6488 | #endif /* ESCAN_RESULT_PATCH */ |
---|
4215 | 6489 | |
---|
4216 | | - |
---|
4217 | | - |
---|
4218 | 6490 | #if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX) |
---|
4219 | 6491 | static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd) |
---|
4220 | 6492 | { |
---|
.. | .. |
---|
4225 | 6497 | chanspec = wl_chspec_driver_to_host(chanspec); |
---|
4226 | 6498 | |
---|
4227 | 6499 | 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)); |
---|
4229 | 6501 | |
---|
4230 | 6502 | return isvht80; |
---|
4231 | 6503 | } |
---|
4232 | 6504 | #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(¶ms, 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, ¶ms, 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 |
---|
4233 | 6796 | |
---|
4234 | 6797 | static s32 |
---|
4235 | 6798 | wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, |
---|
.. | .. |
---|
4240 | 6803 | wl_extjoin_params_t *ext_join_params; |
---|
4241 | 6804 | struct wl_join_params join_params; |
---|
4242 | 6805 | 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 */ |
---|
4243 | 6810 | 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; |
---|
4247 | 6814 | u32 wpaie_len = 0; |
---|
4248 | 6815 | u32 chan_cnt = 0; |
---|
4249 | 6816 | struct ether_addr bssid; |
---|
4250 | 6817 | 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 */ |
---|
4252 | 6824 | int wait_cnt; |
---|
4253 | 6825 | |
---|
4254 | 6826 | 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 */ |
---|
4255 | 6850 | |
---|
4256 | 6851 | #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 | + } |
---|
4266 | 6873 | } |
---|
4267 | 6874 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */ |
---|
4268 | 6875 | |
---|
.. | .. |
---|
4277 | 6884 | return -EINVAL; |
---|
4278 | 6885 | } |
---|
4279 | 6886 | |
---|
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 | + } |
---|
4281 | 6891 | |
---|
| 6892 | + RETURN_EIO_IF_NOT_UP(cfg); |
---|
4282 | 6893 | /* |
---|
4283 | 6894 | * Cancel ongoing scan to sync up with sme state machine of cfg80211. |
---|
4284 | 6895 | */ |
---|
4285 | | -#if !defined(ESCAN_RESULT_PATCH) |
---|
4286 | 6896 | 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 | + } |
---|
4288 | 6908 | } |
---|
4289 | | -#endif |
---|
4290 | 6909 | #ifdef WL_SCHED_SCAN |
---|
| 6910 | + /* Locks are taken in wl_cfg80211_sched_scan_stop() |
---|
| 6911 | + * A start scan occuring during connect is unlikely |
---|
| 6912 | + */ |
---|
4291 | 6913 | 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 |
---|
4292 | 6918 | wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg)); |
---|
| 6919 | +#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(4, 11, 0) */ |
---|
4293 | 6920 | } |
---|
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 */ |
---|
4295 | 6927 | #if defined(ESCAN_RESULT_PATCH) |
---|
4296 | 6928 | if (sme->bssid) |
---|
4297 | 6929 | memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); |
---|
4298 | 6930 | else |
---|
4299 | 6931 | bzero(connect_req_bssid, ETHER_ADDR_LEN); |
---|
4300 | 6932 | bzero(broad_bssid, ETHER_ADDR_LEN); |
---|
4301 | | -#endif |
---|
| 6933 | +#endif // endif |
---|
4302 | 6934 | #if defined(USE_DYNAMIC_MAXPKT_RXGLOM) |
---|
4303 | 6935 | 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); |
---|
4340 | 6951 | } |
---|
4341 | 6952 | } |
---|
| 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, ðer_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); |
---|
4342 | 6964 | |
---|
4343 | 6965 | /* Clean BSSID */ |
---|
4344 | 6966 | bzero(&bssid, sizeof(bssid)); |
---|
.. | .. |
---|
4350 | 6972 | if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { |
---|
4351 | 6973 | WL_ERR(("Find p2p index from wdev(%p) failed\n", |
---|
4352 | 6974 | dev->ieee80211_ptr)); |
---|
4353 | | - return BCME_ERROR; |
---|
| 6975 | + err = BCME_ERROR; |
---|
| 6976 | + goto exit; |
---|
4354 | 6977 | } |
---|
4355 | 6978 | wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx, |
---|
4356 | 6979 | VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); |
---|
4357 | 6980 | } 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 | + |
---|
4358 | 6987 | /* 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, |
---|
4360 | 6989 | DOT11_MNG_RSN_ID)) != NULL) { |
---|
4361 | 6990 | WL_DBG((" WPA2 IE is found\n")); |
---|
4362 | 6991 | } |
---|
4363 | 6992 | /* 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, |
---|
4365 | 6994 | sme->ie_len)) != NULL) { |
---|
4366 | 6995 | WL_DBG((" WPA IE is found\n")); |
---|
4367 | 6996 | } |
---|
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; |
---|
4370 | 7006 | wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; |
---|
4371 | 7007 | wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; |
---|
4372 | 7008 | 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); |
---|
4374 | 7010 | if (unlikely(err)) { |
---|
4375 | 7011 | WL_ERR(("wpaie set error (%d)\n", err)); |
---|
4376 | | - return err; |
---|
| 7012 | + goto exit; |
---|
4377 | 7013 | } |
---|
4378 | 7014 | } else { |
---|
4379 | 7015 | 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); |
---|
4381 | 7017 | if (unlikely(err)) { |
---|
4382 | 7018 | WL_ERR(("wpaie set error (%d)\n", err)); |
---|
4383 | | - return err; |
---|
| 7019 | + goto exit; |
---|
4384 | 7020 | } |
---|
4385 | 7021 | } |
---|
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 | | - } |
---|
4391 | 7022 | 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); |
---|
4393 | 7024 | if (unlikely(err)) { |
---|
4394 | | - return err; |
---|
| 7025 | + goto exit; |
---|
4395 | 7026 | } |
---|
4396 | 7027 | } |
---|
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 | + } |
---|
4411 | 7050 | } |
---|
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 | + |
---|
4413 | 7097 | err = wl_set_wpa_version(dev, sme); |
---|
4414 | 7098 | if (unlikely(err)) { |
---|
4415 | 7099 | WL_ERR(("Invalid wpa_version\n")); |
---|
4416 | | - return err; |
---|
| 7100 | + goto exit; |
---|
4417 | 7101 | } |
---|
| 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 |
---|
4418 | 7108 | err = wl_set_auth_type(dev, sme); |
---|
4419 | 7109 | if (unlikely(err)) { |
---|
4420 | 7110 | WL_ERR(("Invalid auth type\n")); |
---|
4421 | | - return err; |
---|
| 7111 | + goto exit; |
---|
4422 | 7112 | } |
---|
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 */ |
---|
4424 | 7125 | err = wl_set_set_cipher(dev, sme); |
---|
4425 | 7126 | if (unlikely(err)) { |
---|
4426 | 7127 | WL_ERR(("Invalid ciper\n")); |
---|
4427 | | - return err; |
---|
| 7128 | + goto exit; |
---|
4428 | 7129 | } |
---|
4429 | 7130 | |
---|
4430 | 7131 | err = wl_set_key_mgmt(dev, sme); |
---|
4431 | 7132 | if (unlikely(err)) { |
---|
4432 | 7133 | WL_ERR(("Invalid key mgmt\n")); |
---|
4433 | | - return err; |
---|
| 7134 | + goto exit; |
---|
4434 | 7135 | } |
---|
4435 | 7136 | |
---|
4436 | 7137 | err = wl_set_set_sharedkey(dev, sme); |
---|
4437 | 7138 | if (unlikely(err)) { |
---|
4438 | 7139 | WL_ERR(("Invalid shared key\n")); |
---|
4439 | | - return err; |
---|
| 7140 | + goto exit; |
---|
4440 | 7141 | } |
---|
| 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 */ |
---|
4441 | 7149 | |
---|
4442 | 7150 | /* |
---|
4443 | 7151 | * Join with specific BSSID and cached SSID |
---|
.. | .. |
---|
4445 | 7153 | */ |
---|
4446 | 7154 | join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + |
---|
4447 | 7155 | 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); |
---|
4449 | 7157 | if (ext_join_params == NULL) { |
---|
4450 | 7158 | err = -ENOMEM; |
---|
4451 | 7159 | wl_clr_drv_status(cfg, CONNECTING, dev); |
---|
4452 | 7160 | goto exit; |
---|
4453 | 7161 | } |
---|
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); |
---|
4455 | 7164 | memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); |
---|
4456 | 7165 | wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID); |
---|
4457 | 7166 | ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); |
---|
4458 | 7167 | /* increate dwell time to receive probe response or detect Beacon |
---|
4459 | 7168 | * from target AP at a noisy air only during connect command |
---|
4460 | 7169 | */ |
---|
| 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 |
---|
4461 | 7185 | ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1; |
---|
4462 | 7186 | ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1; |
---|
| 7187 | +#endif /* WL_6E */ |
---|
4463 | 7188 | /* Set up join scan parameters */ |
---|
4464 | 7189 | ext_join_params->scan.scan_type = -1; |
---|
4465 | 7190 | ext_join_params->scan.nprobes = chan_cnt ? |
---|
.. | .. |
---|
4471 | 7196 | else |
---|
4472 | 7197 | memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN); |
---|
4473 | 7198 | ext_join_params->assoc.chanspec_num = chan_cnt; |
---|
4474 | | - if (chan_cnt) { |
---|
| 7199 | + |
---|
| 7200 | + if (chan_cnt && !cfg->rcc_enabled) { |
---|
4475 | 7201 | if (cfg->channel) { |
---|
4476 | 7202 | /* |
---|
4477 | 7203 | * Use the channel provided by userspace |
---|
.. | .. |
---|
4483 | 7209 | : WL_CHANSPEC_BAND_5G; |
---|
4484 | 7210 | |
---|
4485 | 7211 | /* 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; |
---|
4487 | 7213 | if (bw == INVCHANSPEC) { |
---|
4488 | 7214 | 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; |
---|
4491 | 7218 | } |
---|
4492 | 7219 | |
---|
4493 | 7220 | ctl_sb = WL_CHANSPEC_CTL_SB_NONE; |
---|
.. | .. |
---|
4498 | 7225 | wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); |
---|
4499 | 7226 | } |
---|
4500 | 7227 | } |
---|
| 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 */ |
---|
4501 | 7234 | ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); |
---|
4502 | 7235 | 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, |
---|
4504 | 7237 | ext_join_params->ssid.SSID_len)); |
---|
4505 | 7238 | } |
---|
4506 | | - wl_set_drv_status(cfg, CONNECTING, dev); |
---|
4507 | 7239 | |
---|
4508 | 7240 | if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { |
---|
4509 | 7241 | 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; |
---|
4512 | 7245 | } |
---|
| 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 */ |
---|
4513 | 7257 | err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, |
---|
4514 | 7258 | cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); |
---|
4515 | | - |
---|
4516 | 7259 | 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)); |
---|
4520 | 7268 | } 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)), |
---|
4523 | 7272 | 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)); |
---|
4524 | 7277 | } |
---|
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); |
---|
4527 | 7283 | if (err) { |
---|
4528 | 7284 | wl_clr_drv_status(cfg, CONNECTING, dev); |
---|
4529 | 7285 | if (err == BCME_UNSUPPORTED) { |
---|
4530 | 7286 | WL_DBG(("join iovar is not supported\n")); |
---|
4531 | 7287 | goto set_ssid; |
---|
4532 | 7288 | } else { |
---|
4533 | | - WL_ERR(("error (%d)\n", err)); |
---|
| 7289 | + WL_ERR(("join iovar error (%d)\n", err)); |
---|
4534 | 7290 | goto exit; |
---|
4535 | 7291 | } |
---|
4536 | 7292 | } else |
---|
4537 | 7293 | goto exit; |
---|
4538 | 7294 | |
---|
4539 | 7295 | 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)); |
---|
4541 | 7307 | join_params_size = sizeof(join_params.ssid); |
---|
4542 | 7308 | |
---|
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); |
---|
4544 | 7310 | memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); |
---|
4545 | 7311 | join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); |
---|
4546 | 7312 | wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); |
---|
.. | .. |
---|
4549 | 7315 | else |
---|
4550 | 7316 | memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); |
---|
4551 | 7317 | |
---|
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) { |
---|
4553 | 7320 | WL_ERR(("Invalid chanspec\n")); |
---|
4554 | 7321 | return -EINVAL; |
---|
4555 | 7322 | } |
---|
.. | .. |
---|
4557 | 7324 | WL_DBG(("join_param_size %zu\n", join_params_size)); |
---|
4558 | 7325 | |
---|
4559 | 7326 | 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, |
---|
4561 | 7328 | join_params.ssid.SSID_len)); |
---|
4562 | 7329 | } |
---|
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: |
---|
4565 | 7332 | if (err) { |
---|
4566 | 7333 | WL_ERR(("error (%d)\n", err)); |
---|
4567 | 7334 | 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 */ |
---|
4568 | 7340 | } |
---|
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 */ |
---|
4570 | 7346 | 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; |
---|
4571 | 7400 | } |
---|
4572 | 7401 | |
---|
4573 | 7402 | static s32 |
---|
.. | .. |
---|
4578 | 7407 | scb_val_t scbval; |
---|
4579 | 7408 | bool act = false; |
---|
4580 | 7409 | 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); |
---|
4585 | 7414 | WL_ERR(("Reason %d\n", reason_code)); |
---|
4586 | 7415 | RETURN_EIO_IF_NOT_UP(cfg); |
---|
4587 | 7416 | act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT); |
---|
4588 | 7417 | 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 | + |
---|
4589 | 7426 | #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 | + } |
---|
4594 | 7434 | act = true; |
---|
4595 | 7435 | } |
---|
4596 | 7436 | #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 | + |
---|
4597 | 7444 | 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 */ |
---|
4598 | 7451 | /* |
---|
4599 | 7452 | * Cancel ongoing scan to sync up with sme state machine of cfg80211. |
---|
4600 | 7453 | */ |
---|
4601 | | -#if !defined(ESCAN_RESULT_PATCH) |
---|
4602 | 7454 | /* Let scan aborted by F/W */ |
---|
4603 | 7455 | 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); |
---|
4605 | 7458 | } |
---|
4606 | | -#endif /* ESCAN_RESULT_PATCH */ |
---|
| 7459 | + /* Set DISCONNECTING state. We are clearing this state in all exit paths */ |
---|
4607 | 7460 | 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 | + } |
---|
4617 | 7474 | } |
---|
| 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); |
---|
4618 | 7494 | } |
---|
4619 | 7495 | #ifdef CUSTOM_SET_CPUCORE |
---|
4620 | 7496 | /* set default cpucore */ |
---|
4621 | 7497 | 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); |
---|
4625 | 7501 | } |
---|
4626 | 7502 | #endif /* CUSTOM_SET_CPUCORE */ |
---|
4627 | 7503 | |
---|
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); |
---|
4632 | 7516 | |
---|
4633 | 7517 | return err; |
---|
4634 | 7518 | } |
---|
.. | .. |
---|
4728 | 7612 | /* Just select a new current key */ |
---|
4729 | 7613 | index = (u32) key_idx; |
---|
4730 | 7614 | 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)); |
---|
4733 | 7617 | if (unlikely(err)) { |
---|
4734 | 7618 | WL_ERR(("error (%d)\n", err)); |
---|
4735 | 7619 | } |
---|
.. | .. |
---|
4747 | 7631 | s32 bssidx; |
---|
4748 | 7632 | s32 mode = wl_get_mode_by_netdev(cfg, dev); |
---|
4749 | 7633 | |
---|
| 7634 | + WL_ERR(("key index (%d)\n", key_idx)); |
---|
4750 | 7635 | if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { |
---|
4751 | 7636 | WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); |
---|
4752 | 7637 | return BCME_ERROR; |
---|
4753 | 7638 | } |
---|
4754 | | - memset(&key, 0, sizeof(key)); |
---|
| 7639 | + bzero(&key, sizeof(key)); |
---|
4755 | 7640 | key.index = (u32) key_idx; |
---|
4756 | 7641 | |
---|
4757 | 7642 | if (!ETHER_ISMULTI(mac_addr)) |
---|
.. | .. |
---|
4787 | 7672 | /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ |
---|
4788 | 7673 | if (params->seq && params->seq_len == 6) { |
---|
4789 | 7674 | /* rx iv */ |
---|
4790 | | - u8 *ivptr; |
---|
4791 | | - ivptr = (u8 *) params->seq; |
---|
| 7675 | + const u8 *ivptr; |
---|
| 7676 | + ivptr = (const u8 *) params->seq; |
---|
4792 | 7677 | key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | |
---|
4793 | 7678 | (ivptr[3] << 8) | ivptr[2]; |
---|
4794 | 7679 | key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; |
---|
4795 | 7680 | key.iv_initialized = true; |
---|
4796 | 7681 | } |
---|
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. |
---|
4820 | 7684 | WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); |
---|
4821 | 7685 | return -EINVAL; |
---|
4822 | 7686 | } |
---|
.. | .. |
---|
4829 | 7693 | WL_ERR(("WLC_SET_KEY error (%d)\n", err)); |
---|
4830 | 7694 | return err; |
---|
4831 | 7695 | } |
---|
| 7696 | + WL_INFORM_MEM(("[%s] wsec key set\n", dev->name)); |
---|
4832 | 7697 | } |
---|
4833 | 7698 | return err; |
---|
4834 | 7699 | } |
---|
.. | .. |
---|
4838 | 7703 | { |
---|
4839 | 7704 | int err; |
---|
4840 | 7705 | wl_eventmsg_buf_t ev_buf; |
---|
| 7706 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
4841 | 7707 | |
---|
4842 | | - if (dev != bcmcfg_to_prmry_ndev(g_bcm_cfg)) { |
---|
| 7708 | + if (dev != bcmcfg_to_prmry_ndev(cfg)) { |
---|
4843 | 7709 | /* roam offload is only for the primary device */ |
---|
4844 | 7710 | return -1; |
---|
4845 | 7711 | } |
---|
| 7712 | + |
---|
| 7713 | + WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev->name, enable)); |
---|
4846 | 7714 | err = wldev_iovar_setint(dev, "roam_offload", enable); |
---|
4847 | 7715 | if (err) |
---|
4848 | 7716 | return err; |
---|
.. | .. |
---|
4854 | 7722 | wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable); |
---|
4855 | 7723 | wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable); |
---|
4856 | 7724 | 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); |
---|
4858 | 7726 | if (!err) { |
---|
4859 | | - g_bcm_cfg->roam_offload = enable; |
---|
| 7727 | + cfg->roam_offload = enable; |
---|
4860 | 7728 | } |
---|
4861 | 7729 | return err; |
---|
4862 | 7730 | } |
---|
4863 | 7731 | |
---|
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) |
---|
4867 | 7734 | { |
---|
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; |
---|
4886 | 7735 | struct net_info *iter, *next; |
---|
4887 | | - int err = BCME_ERROR; |
---|
4888 | 7736 | |
---|
4889 | 7737 | if (name == NULL) { |
---|
4890 | | - return BCME_ERROR; |
---|
| 7738 | + WL_ERR(("Iface name is not provided\n")); |
---|
| 7739 | + return NULL; |
---|
4891 | 7740 | } |
---|
4892 | 7741 | |
---|
| 7742 | + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); |
---|
4893 | 7743 | for_each_ndev(cfg, iter, next) { |
---|
| 7744 | + GCC_DIAGNOSTIC_POP(); |
---|
4894 | 7745 | if (iter->ndev) { |
---|
4895 | 7746 | 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; |
---|
4898 | 7748 | } |
---|
4899 | 7749 | } |
---|
4900 | 7750 | } |
---|
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; |
---|
4905 | 7754 | } |
---|
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 */ |
---|
4907 | 7798 | |
---|
4908 | 7799 | static s32 |
---|
4909 | 7800 | wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, |
---|
.. | .. |
---|
4918 | 7809 | s32 bssidx = 0; |
---|
4919 | 7810 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
4920 | 7811 | 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)); |
---|
4922 | 7826 | RETURN_EIO_IF_NOT_UP(cfg); |
---|
4923 | 7827 | |
---|
4924 | 7828 | if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { |
---|
.. | .. |
---|
4932 | 7836 | wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); |
---|
4933 | 7837 | goto exit; |
---|
4934 | 7838 | } |
---|
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)); |
---|
4936 | 7844 | /* 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)); |
---|
4938 | 7846 | |
---|
4939 | 7847 | key.len = (u32) params->key_len; |
---|
4940 | 7848 | key.index = (u32) key_idx; |
---|
.. | .. |
---|
4946 | 7854 | memcpy(key.data, params->key, key.len); |
---|
4947 | 7855 | |
---|
4948 | 7856 | 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 | + } |
---|
4949 | 7872 | 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; |
---|
4960 | 7873 | case WLAN_CIPHER_SUITE_TKIP: |
---|
4961 | | - key.algo = CRYPTO_ALGO_TKIP; |
---|
4962 | | - val = TKIP_ENABLED; |
---|
4963 | 7874 | /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ |
---|
4964 | 7875 | if (mode == WL_MODE_BSS) { |
---|
4965 | 7876 | bcopy(&key.data[24], keybuf, sizeof(keybuf)); |
---|
.. | .. |
---|
4968 | 7879 | } |
---|
4969 | 7880 | WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); |
---|
4970 | 7881 | 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: |
---|
4990 | 7884 | 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, |
---|
4993 | 7896 | WSEC_MAX_PSK_LEN / 2, keystring, sizeof(keystring), NULL); |
---|
4994 | 7897 | if (err) { |
---|
4995 | 7898 | /* 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)); |
---|
4997 | 7900 | } |
---|
4998 | 7901 | } |
---|
4999 | 7902 | /* copy the raw hex key to the appropriate format */ |
---|
5000 | 7903 | for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { |
---|
5001 | 7904 | charptr += snprintf(charptr, sizeof(keystring), "%02x", params->key[j]); |
---|
5002 | 7905 | } |
---|
5003 | | - len = strlen(keystring); |
---|
| 7906 | + len = (u16)strlen(keystring); |
---|
5004 | 7907 | pmk.key_len = htod16(len); |
---|
5005 | 7908 | bcopy(keystring, pmk.key, len); |
---|
5006 | 7909 | 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) { |
---|
5009 | 7913 | 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; |
---|
5015 | 7931 | } |
---|
5016 | 7932 | |
---|
5017 | 7933 | /* Set the new key/index */ |
---|
.. | .. |
---|
5053 | 7969 | WL_ERR(("set wsec error (%d)\n", err)); |
---|
5054 | 7970 | return err; |
---|
5055 | 7971 | } |
---|
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 */ |
---|
5057 | 7977 | return err; |
---|
5058 | 7978 | } |
---|
5059 | 7979 | |
---|
.. | .. |
---|
5065 | 7985 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
5066 | 7986 | s32 err = 0; |
---|
5067 | 7987 | s32 bssidx; |
---|
| 7988 | + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); |
---|
5068 | 7989 | |
---|
5069 | 7990 | if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { |
---|
5070 | 7991 | WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); |
---|
.. | .. |
---|
5075 | 7996 | #ifndef MFP |
---|
5076 | 7997 | if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) |
---|
5077 | 7998 | return -EINVAL; |
---|
5078 | | -#endif |
---|
| 7999 | +#endif // endif |
---|
5079 | 8000 | |
---|
5080 | 8001 | 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)); |
---|
5082 | 8005 | |
---|
5083 | 8006 | key.flags = WL_PRIMARY_KEY; |
---|
5084 | 8007 | key.algo = CRYPTO_ALGO_OFF; |
---|
.. | .. |
---|
5103 | 8026 | return err; |
---|
5104 | 8027 | } |
---|
5105 | 8028 | |
---|
| 8029 | +/* NOTE : this function cannot work as is and is never called */ |
---|
5106 | 8030 | static s32 |
---|
5107 | 8031 | wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, |
---|
5108 | 8032 | u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, |
---|
.. | .. |
---|
5122 | 8046 | } |
---|
5123 | 8047 | WL_DBG(("key index (%d)\n", key_idx)); |
---|
5124 | 8048 | RETURN_EIO_IF_NOT_UP(cfg); |
---|
5125 | | - memset(&key, 0, sizeof(key)); |
---|
| 8049 | + bzero(&key, sizeof(key)); |
---|
5126 | 8050 | key.index = key_idx; |
---|
5127 | 8051 | swap_key_to_BE(&key); |
---|
5128 | | - memset(¶ms, 0, sizeof(params)); |
---|
| 8052 | + bzero(¶ms, sizeof(params)); |
---|
5129 | 8053 | 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; |
---|
5131 | 8055 | |
---|
5132 | 8056 | err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); |
---|
5133 | 8057 | if (unlikely(err)) { |
---|
.. | .. |
---|
5153 | 8077 | params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; |
---|
5154 | 8078 | WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); |
---|
5155 | 8079 | 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 |
---|
5156 | 8093 | default: |
---|
5157 | 8094 | WL_ERR(("Invalid algo (0x%x)\n", wsec)); |
---|
5158 | 8095 | return -EINVAL; |
---|
.. | .. |
---|
5169 | 8106 | #ifdef MFP |
---|
5170 | 8107 | return 0; |
---|
5171 | 8108 | #else |
---|
5172 | | - WL_INFORM(("Not supported\n")); |
---|
| 8109 | + WL_INFORM_MEM(("Not supported\n")); |
---|
5173 | 8110 | return -EOPNOTSUPP; |
---|
5174 | 8111 | #endif /* MFP */ |
---|
5175 | 8112 | } |
---|
5176 | 8113 | |
---|
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) |
---|
5186 | 8116 | { |
---|
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; |
---|
5188 | 8139 | 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 */ |
---|
5226 | 8143 | |
---|
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 | + } |
---|
5258 | 8147 | |
---|
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; |
---|
5274 | 8150 | |
---|
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; |
---|
5321 | 8166 | } |
---|
5322 | 8167 | } |
---|
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; |
---|
5325 | 8196 | } |
---|
5326 | 8197 | |
---|
5327 | 8198 | return err; |
---|
5328 | 8199 | } |
---|
5329 | 8200 | |
---|
| 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)) |
---|
5330 | 8380 | 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 |
---|
5331 | 8632 | wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, |
---|
5332 | 8633 | bool enabled, s32 timeout) |
---|
5333 | 8634 | { |
---|
.. | .. |
---|
5335 | 8636 | s32 err = 0; |
---|
5336 | 8637 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
5337 | 8638 | 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 */ |
---|
5339 | 8644 | RETURN_EIO_IF_NOT_UP(cfg); |
---|
| 8645 | + |
---|
5340 | 8646 | WL_DBG(("Enter\n")); |
---|
| 8647 | + mode = wl_get_mode_by_netdev(cfg, dev); |
---|
5341 | 8648 | 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))) { |
---|
5343 | 8652 | return err; |
---|
5344 | 8653 | } |
---|
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); |
---|
5347 | 8657 | |
---|
5348 | 8658 | pm = enabled ? PM_FAST : PM_OFF; |
---|
5349 | 8659 | if (_net_info->pm_block) { |
---|
.. | .. |
---|
5353 | 8663 | } |
---|
5354 | 8664 | pm = htod32(pm); |
---|
5355 | 8665 | 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 |
---|
5363 | 8679 | } |
---|
| 8680 | +#endif /* RTT_SUPPORT */ |
---|
5364 | 8681 | wl_cfg80211_update_power_mode(dev); |
---|
5365 | 8682 | return err; |
---|
5366 | 8683 | } |
---|
.. | .. |
---|
5369 | 8686 | { |
---|
5370 | 8687 | int err, pm = -1; |
---|
5371 | 8688 | |
---|
5372 | | - err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), true); |
---|
| 8689 | + err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm)); |
---|
5373 | 8690 | if (err) |
---|
5374 | | - WL_ERR(("%s:error (%d)\n", __FUNCTION__, err)); |
---|
| 8691 | + WL_ERR(("wl_cfg80211_update_power_mode: error (%d)\n", err)); |
---|
5375 | 8692 | else if (pm != -1 && dev->ieee80211_ptr) |
---|
5376 | 8693 | 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")); |
---|
5389 | 8694 | } |
---|
5390 | 8695 | |
---|
5391 | 8696 | static __used u32 wl_find_msb(u16 bit16) |
---|
.. | .. |
---|
5420 | 8725 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
5421 | 8726 | struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); |
---|
5422 | 8727 | 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 */ |
---|
5423 | 8732 | |
---|
5424 | 8733 | 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")); |
---|
5426 | 8735 | return err; |
---|
5427 | 8736 | } |
---|
5428 | 8737 | |
---|
| 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 */ |
---|
5429 | 8758 | |
---|
5430 | 8759 | return err; |
---|
5431 | 8760 | } |
---|
5432 | 8761 | |
---|
| 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); |
---|
5433 | 8769 | |
---|
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) |
---|
5435 | 8876 | static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) |
---|
5436 | 8877 | #else |
---|
5437 | 8878 | static s32 wl_cfg80211_suspend(struct wiphy *wiphy) |
---|
5438 | | -#endif |
---|
| 8879 | +#endif // endif |
---|
5439 | 8880 | { |
---|
5440 | 8881 | s32 err = BCME_OK; |
---|
5441 | 8882 | #ifdef DHD_CLEAR_ON_SUSPEND |
---|
.. | .. |
---|
5444 | 8885 | struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); |
---|
5445 | 8886 | unsigned long flags; |
---|
5446 | 8887 | 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", |
---|
5448 | 8889 | (int)cfg->status)); |
---|
5449 | 8890 | return err; |
---|
5450 | 8891 | } |
---|
.. | .. |
---|
5453 | 8894 | if (iter->ndev) |
---|
5454 | 8895 | wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); |
---|
5455 | 8896 | } |
---|
5456 | | - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); |
---|
| 8897 | + WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags); |
---|
5457 | 8898 | 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 |
---|
5462 | 8899 | cfg80211_scan_done(cfg->scan_request, true); |
---|
5463 | | -#endif |
---|
5464 | 8900 | cfg->scan_request = NULL; |
---|
5465 | 8901 | } |
---|
5466 | 8902 | for_each_ndev(cfg, iter, next) { |
---|
.. | .. |
---|
5469 | 8905 | wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev); |
---|
5470 | 8906 | } |
---|
5471 | 8907 | } |
---|
5472 | | - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); |
---|
| 8908 | + WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags); |
---|
5473 | 8909 | for_each_ndev(cfg, iter, next) { |
---|
5474 | 8910 | if (iter->ndev) { |
---|
5475 | 8911 | if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) { |
---|
.. | .. |
---|
5479 | 8915 | } |
---|
5480 | 8916 | #endif /* DHD_CLEAR_ON_SUSPEND */ |
---|
5481 | 8917 | |
---|
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 */ |
---|
5508 | 8922 | |
---|
5509 | 8923 | return err; |
---|
5510 | 8924 | } |
---|
.. | .. |
---|
5514 | 8928 | s32 err) |
---|
5515 | 8929 | { |
---|
5516 | 8930 | int i, j; |
---|
5517 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 8931 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
5518 | 8932 | struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg); |
---|
| 8933 | + int npmkids = cfg->pmk_list->pmkids.count; |
---|
5519 | 8934 | |
---|
| 8935 | + ASSERT(cfg->pmk_list->pmkids.length >= (sizeof(u16)*2)); |
---|
5520 | 8936 | if (!pmk_list) { |
---|
5521 | | - printk("pmk_list is NULL\n"); |
---|
| 8937 | + WL_INFORM_MEM(("pmk_list is NULL\n")); |
---|
5522 | 8938 | return -EINVAL; |
---|
5523 | 8939 | } |
---|
5524 | 8940 | /* pmk list is supported only for STA interface i.e. primary interface |
---|
5525 | 8941 | * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init |
---|
5526 | 8942 | */ |
---|
5527 | 8943 | if (primary_dev != dev) { |
---|
5528 | | - WL_INFORM(("Not supporting Flushing pmklist on virtual" |
---|
| 8944 | + WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual" |
---|
5529 | 8945 | " interfaces than primary interface\n")); |
---|
5530 | 8946 | return err; |
---|
5531 | 8947 | } |
---|
5532 | 8948 | |
---|
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++) { |
---|
5535 | 8951 | WL_DBG(("PMKID[%d]: %pM =\n", i, |
---|
5536 | | - &pmk_list->pmkids.pmkid[i].BSSID)); |
---|
| 8952 | + &pmk_list->pmkids.pmkid[i].bssid)); |
---|
5537 | 8953 | 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])); |
---|
5539 | 8955 | } |
---|
5540 | 8956 | } |
---|
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); |
---|
5544 | 8962 | } |
---|
| 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); |
---|
5545 | 8970 | |
---|
| 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 | + } |
---|
5546 | 9051 | return err; |
---|
5547 | 9052 | } |
---|
5548 | 9053 | |
---|
| 9054 | +/* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single |
---|
| 9055 | + * entry operation. |
---|
| 9056 | + */ |
---|
5549 | 9057 | static s32 |
---|
5550 | 9058 | wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, |
---|
5551 | 9059 | struct cfg80211_pmksa *pmksa) |
---|
.. | .. |
---|
5553 | 9061 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
5554 | 9062 | s32 err = 0; |
---|
5555 | 9063 | int i; |
---|
| 9064 | + int npmkids = cfg->pmk_list->pmkids.count; |
---|
| 9065 | + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); |
---|
5556 | 9066 | |
---|
5557 | 9067 | 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 | + } |
---|
5562 | 9085 | 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, |
---|
5566 | 9111 | 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 | + } |
---|
5569 | 9124 | } else { |
---|
5570 | 9125 | err = -EINVAL; |
---|
5571 | 9126 | } |
---|
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 | + } |
---|
5574 | 9133 | for (i = 0; i < WPA2_PMKID_LEN; i++) { |
---|
5575 | 9134 | 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])); |
---|
5578 | 9137 | } |
---|
| 9138 | +#endif /* (WL_DBG_LEVEL > 0) */ |
---|
5579 | 9139 | |
---|
5580 | 9140 | err = wl_update_pmklist(dev, cfg->pmk_list, err); |
---|
5581 | 9141 | |
---|
5582 | 9142 | return err; |
---|
5583 | 9143 | } |
---|
5584 | 9144 | |
---|
| 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 | + */ |
---|
5585 | 9234 | static s32 |
---|
5586 | 9235 | wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, |
---|
5587 | 9236 | struct cfg80211_pmksa *pmksa) |
---|
5588 | 9237 | { |
---|
5589 | 9238 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
5590 | | - |
---|
5591 | | - struct _pmkid_list pmkid = {.npmkid = 0}; |
---|
5592 | 9239 | s32 err = 0; |
---|
5593 | 9240 | int i; |
---|
5594 | | - |
---|
| 9241 | + int npmkids = cfg->pmk_list->pmkids.count; |
---|
5595 | 9242 | 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); |
---|
5598 | 9243 | |
---|
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; |
---|
5603 | 9252 | } |
---|
5604 | 9253 | |
---|
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])); |
---|
5621 | 9264 | } |
---|
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 | + |
---|
5623 | 9305 | } else { |
---|
5624 | 9306 | err = -EINVAL; |
---|
5625 | 9307 | } |
---|
| 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 | + */ |
---|
5626 | 9317 | |
---|
5627 | 9318 | err = wl_update_pmklist(dev, cfg->pmk_list, err); |
---|
5628 | 9319 | |
---|
.. | .. |
---|
5630 | 9321 | |
---|
5631 | 9322 | } |
---|
5632 | 9323 | |
---|
| 9324 | +/* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single |
---|
| 9325 | + * entry operation. |
---|
| 9326 | + */ |
---|
5633 | 9327 | static s32 |
---|
5634 | 9328 | wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) |
---|
5635 | 9329 | { |
---|
5636 | 9330 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
5637 | 9331 | s32 err = 0; |
---|
5638 | 9332 | 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; |
---|
5640 | 9337 | err = wl_update_pmklist(dev, cfg->pmk_list, err); |
---|
5641 | 9338 | 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(¶ms->bssid, ðer_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; |
---|
5685 | 9339 | } |
---|
5686 | 9340 | |
---|
5687 | 9341 | #if defined(WL_CFG80211_P2P_DEV_IF) |
---|
.. | .. |
---|
5702 | 9356 | struct ether_addr primary_mac; |
---|
5703 | 9357 | struct net_device *ndev = NULL; |
---|
5704 | 9358 | 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 */ |
---|
5705 | 9365 | |
---|
5706 | 9366 | ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); |
---|
5707 | 9367 | |
---|
| 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); |
---|
5708 | 9377 | WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n", |
---|
5709 | 9378 | ieee80211_frequency_to_channel(channel->center_freq), |
---|
5710 | 9379 | duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO")); |
---|
.. | .. |
---|
5715 | 9384 | goto exit; |
---|
5716 | 9385 | } |
---|
5717 | 9386 | |
---|
| 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 | + |
---|
5718 | 9395 | #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST |
---|
5719 | 9396 | 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); |
---|
5721 | 9398 | } |
---|
5722 | 9399 | #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ |
---|
5723 | 9400 | |
---|
.. | .. |
---|
5733 | 9410 | |
---|
5734 | 9411 | #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST |
---|
5735 | 9412 | if (wl_get_drv_status(cfg, SCANNING, ndev)) { |
---|
5736 | | - struct timer_list *_timer; |
---|
| 9413 | + timer_list_compat_t *_timer; |
---|
5737 | 9414 | WL_DBG(("scan is running. go to fake listen state\n")); |
---|
5738 | 9415 | |
---|
5739 | 9416 | if (duration > LONG_LISTEN_TIME) { |
---|
.. | .. |
---|
5746 | 9423 | del_timer_sync(&cfg->p2p->listen_timer); |
---|
5747 | 9424 | } |
---|
5748 | 9425 | |
---|
5749 | | - _timer = (struct timer_list *) &cfg->p2p->listen_timer; |
---|
| 9426 | + _timer = &cfg->p2p->listen_timer; |
---|
5750 | 9427 | wl_clr_p2p_status(cfg, LISTEN_EXPIRED); |
---|
5751 | 9428 | |
---|
5752 | 9429 | INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0); |
---|
.. | .. |
---|
5757 | 9434 | } |
---|
5758 | 9435 | #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ |
---|
5759 | 9436 | |
---|
| 9437 | +#ifdef WL_BCNRECV |
---|
| 9438 | + /* check fakeapscan in progress then abort */ |
---|
| 9439 | + wl_android_bcnrecv_stop(ndev, WL_BCNRECV_LISTENBUSY); |
---|
| 9440 | +#endif /* WL_BCNRECV */ |
---|
5760 | 9441 | #ifdef WL_CFG80211_SYNC_GON |
---|
5761 | 9442 | if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { |
---|
5762 | 9443 | /* do not enter listen mode again if we are in listen mode already for next af. |
---|
.. | .. |
---|
5799 | 9480 | wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev); |
---|
5800 | 9481 | } |
---|
5801 | 9482 | #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ |
---|
| 9483 | + |
---|
| 9484 | + if (err) { |
---|
| 9485 | + wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL); |
---|
| 9486 | + } |
---|
| 9487 | + |
---|
5802 | 9488 | /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant |
---|
5803 | 9489 | * and expire timer will send a completion to the upper layer |
---|
5804 | 9490 | */ |
---|
.. | .. |
---|
5807 | 9493 | |
---|
5808 | 9494 | exit: |
---|
5809 | 9495 | if (err == BCME_OK) { |
---|
5810 | | - WL_INFORM(("Success\n")); |
---|
| 9496 | + WL_DBG(("Success\n")); |
---|
5811 | 9497 | #if defined(WL_CFG80211_P2P_DEV_IF) |
---|
5812 | 9498 | cfg80211_ready_on_channel(cfgdev, *cookie, channel, |
---|
5813 | 9499 | duration, GFP_KERNEL); |
---|
.. | .. |
---|
5818 | 9504 | } else { |
---|
5819 | 9505 | WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); |
---|
5820 | 9506 | } |
---|
| 9507 | + mutex_unlock(&cfg->usr_sync); |
---|
5821 | 9508 | return err; |
---|
5822 | 9509 | } |
---|
5823 | 9510 | |
---|
.. | .. |
---|
5826 | 9513 | bcm_struct_cfgdev *cfgdev, u64 cookie) |
---|
5827 | 9514 | { |
---|
5828 | 9515 | s32 err = 0; |
---|
5829 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 9516 | + |
---|
| 9517 | + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
5830 | 9518 | |
---|
5831 | 9519 | #ifdef P2PLISTEN_AP_SAMECHN |
---|
5832 | 9520 | struct net_device *dev; |
---|
5833 | 9521 | #endif /* P2PLISTEN_AP_SAMECHN */ |
---|
5834 | 9522 | |
---|
5835 | 9523 | RETURN_EIO_IF_NOT_UP(cfg); |
---|
| 9524 | + |
---|
| 9525 | +#ifdef DHD_IFDEBUG |
---|
| 9526 | + PRINT_WDEV_INFO(cfgdev); |
---|
| 9527 | +#endif /* DHD_IFDEBUG */ |
---|
| 9528 | + |
---|
5836 | 9529 | #if defined(WL_CFG80211_P2P_DEV_IF) |
---|
5837 | 9530 | if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { |
---|
5838 | 9531 | WL_DBG((" enter ) on P2P dedicated discover interface\n")); |
---|
.. | .. |
---|
5854 | 9547 | wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, |
---|
5855 | 9548 | wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE)); |
---|
5856 | 9549 | } 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)); |
---|
5859 | 9553 | } |
---|
5860 | 9554 | |
---|
5861 | 9555 | return err; |
---|
.. | .. |
---|
5865 | 9559 | wl_cfg80211_afx_handler(struct work_struct *work) |
---|
5866 | 9560 | { |
---|
5867 | 9561 | struct afx_hdl *afx_instance; |
---|
5868 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 9562 | + struct bcm_cfg80211 *cfg; |
---|
5869 | 9563 | s32 ret = BCME_OK; |
---|
5870 | 9564 | |
---|
5871 | 9565 | 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 | + } |
---|
5885 | 9582 | } |
---|
5886 | 9583 | } |
---|
5887 | 9584 | } |
---|
.. | .. |
---|
5890 | 9587 | wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev) |
---|
5891 | 9588 | { |
---|
5892 | 9589 | u32 max_retry = WL_CHANNEL_SYNC_RETRY; |
---|
| 9590 | + bool is_p2p_gas = false; |
---|
5893 | 9591 | |
---|
5894 | 9592 | if (dev == NULL) |
---|
5895 | 9593 | return -1; |
---|
.. | .. |
---|
5898 | 9596 | |
---|
5899 | 9597 | wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev); |
---|
5900 | 9598 | 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 | + } |
---|
5901 | 9606 | |
---|
5902 | 9607 | /* Loop to wait until we find a peer's channel or the |
---|
5903 | 9608 | * pending action frame tx is cancelled. |
---|
.. | .. |
---|
5915 | 9620 | |
---|
5916 | 9621 | if ((cfg->afx_hdl->peer_chan != WL_INVALID) || |
---|
5917 | 9622 | !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) |
---|
| 9623 | + break; |
---|
| 9624 | + |
---|
| 9625 | + if (is_p2p_gas) |
---|
5918 | 9626 | break; |
---|
5919 | 9627 | |
---|
5920 | 9628 | if (cfg->afx_hdl->my_listen_chan) { |
---|
.. | .. |
---|
5945 | 9653 | |
---|
5946 | 9654 | struct p2p_config_af_params { |
---|
5947 | 9655 | 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 |
---|
5952 | 9660 | #ifdef WL_CFG80211_SYNC_GON |
---|
5953 | 9661 | bool extra_listen; |
---|
5954 | | -#endif |
---|
| 9662 | +#endif // endif |
---|
5955 | 9663 | bool search_channel; /* 1: search peer's channel to send af */ |
---|
5956 | 9664 | }; |
---|
| 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 */ |
---|
5957 | 9719 | |
---|
5958 | 9720 | static s32 |
---|
5959 | 9721 | wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, |
---|
.. | .. |
---|
5966 | 9728 | (wifi_p2p_pub_act_frame_t *) (action_frame->data); |
---|
5967 | 9729 | |
---|
5968 | 9730 | /* initialize default value */ |
---|
| 9731 | +#ifdef WL_CFG80211_GON_COLLISION |
---|
| 9732 | + config_af_params->drop_tx_req = false; |
---|
| 9733 | +#endif // endif |
---|
5969 | 9734 | #ifdef WL_CFG80211_SYNC_GON |
---|
5970 | 9735 | config_af_params->extra_listen = true; |
---|
5971 | | -#endif |
---|
| 9736 | +#endif // endif |
---|
5972 | 9737 | config_af_params->search_channel = false; |
---|
5973 | 9738 | config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; |
---|
5974 | | - config_af_params->mpc_onoff = -1; |
---|
5975 | 9739 | cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; |
---|
5976 | 9740 | |
---|
5977 | 9741 | switch (act_frm->subtype) { |
---|
5978 | 9742 | 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 */ |
---|
5979 | 9747 | WL_DBG(("P2P: GO_NEG_PHASE status set \n")); |
---|
5980 | 9748 | wl_set_p2p_status(cfg, GO_NEG_PHASE); |
---|
5981 | 9749 | |
---|
5982 | | - config_af_params->mpc_onoff = 0; |
---|
5983 | 9750 | config_af_params->search_channel = true; |
---|
5984 | 9751 | cfg->next_af_subtype = act_frm->subtype + 1; |
---|
5985 | 9752 | |
---|
5986 | 9753 | /* increase dwell time to wait for RESP frame */ |
---|
5987 | 9754 | af_params->dwell_time = WL_MED_DWELL_TIME; |
---|
5988 | 9755 | |
---|
| 9756 | +#ifdef WL_CFG80211_GON_COLLISION |
---|
| 9757 | + config_af_params->drop_tx_req = true; |
---|
| 9758 | +#endif /* WL_CFG80211_GON_COLLISION */ |
---|
5989 | 9759 | break; |
---|
5990 | 9760 | } |
---|
5991 | 9761 | case P2P_PAF_GON_RSP: { |
---|
.. | .. |
---|
5999 | 9769 | WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); |
---|
6000 | 9770 | wl_clr_p2p_status(cfg, GO_NEG_PHASE); |
---|
6001 | 9771 | |
---|
6002 | | - /* turn on mpc again if go nego is done */ |
---|
6003 | | - config_af_params->mpc_onoff = 1; |
---|
6004 | | - |
---|
6005 | 9772 | /* minimize dwell time */ |
---|
6006 | 9773 | af_params->dwell_time = WL_MIN_DWELL_TIME; |
---|
6007 | 9774 | |
---|
| 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 */ |
---|
6008 | 9780 | #ifdef WL_CFG80211_SYNC_GON |
---|
6009 | 9781 | config_af_params->extra_listen = false; |
---|
6010 | 9782 | #endif /* WL_CFG80211_SYNC_GON */ |
---|
.. | .. |
---|
6049 | 9821 | config_af_params->search_channel = true; |
---|
6050 | 9822 | } |
---|
6051 | 9823 | |
---|
6052 | | - config_af_params->mpc_onoff = 0; |
---|
6053 | 9824 | cfg->next_af_subtype = act_frm->subtype + 1; |
---|
6054 | 9825 | /* increase dwell time to wait for RESP frame */ |
---|
6055 | 9826 | af_params->dwell_time = WL_MED_DWELL_TIME; |
---|
.. | .. |
---|
6057 | 9828 | } |
---|
6058 | 9829 | case P2P_PAF_PROVDIS_RSP: { |
---|
6059 | 9830 | 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; |
---|
6061 | 9832 | #ifdef WL_CFG80211_SYNC_GON |
---|
6062 | 9833 | config_af_params->extra_listen = false; |
---|
6063 | 9834 | #endif /* WL_CFG80211_SYNC_GON */ |
---|
.. | .. |
---|
6077 | 9848 | void *frame, u16 frame_len) |
---|
6078 | 9849 | { |
---|
6079 | 9850 | struct wl_scan_results *bss_list; |
---|
6080 | | - struct wl_bss_info *bi = NULL; |
---|
| 9851 | + wl_bss_info_t *bi = NULL; |
---|
6081 | 9852 | bool result = false; |
---|
6082 | 9853 | s32 i; |
---|
6083 | 9854 | chanspec_t chanspec; |
---|
.. | .. |
---|
6107 | 9878 | return result; |
---|
6108 | 9879 | } |
---|
6109 | 9880 | #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 | +} |
---|
6111 | 9892 | |
---|
6112 | 9893 | static bool |
---|
6113 | 9894 | wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, |
---|
.. | .. |
---|
6125 | 9906 | struct net_info *netinfo; |
---|
6126 | 9907 | #ifdef VSDB |
---|
6127 | 9908 | ulong off_chan_started_jiffies = 0; |
---|
6128 | | -#endif |
---|
| 9909 | +#endif // endif |
---|
| 9910 | + ulong dwell_jiffies = 0; |
---|
| 9911 | + bool dwell_overflow = false; |
---|
6129 | 9912 | dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); |
---|
6130 | 9913 | |
---|
| 9914 | + int32 requested_dwell = af_params->dwell_time; |
---|
6131 | 9915 | |
---|
6132 | 9916 | /* Add the default dwell time |
---|
6133 | 9917 | * Dwell time to stay off-channel to wait for a response action frame |
---|
.. | .. |
---|
6150 | 9934 | tx_retry = 0; |
---|
6151 | 9935 | cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; |
---|
6152 | 9936 | config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY; |
---|
6153 | | - config_af_params.mpc_onoff = -1; |
---|
6154 | 9937 | config_af_params.search_channel = false; |
---|
| 9938 | +#ifdef WL_CFG80211_GON_COLLISION |
---|
| 9939 | + config_af_params.drop_tx_req = false; |
---|
| 9940 | +#endif // endif |
---|
6155 | 9941 | #ifdef WL_CFG80211_SYNC_GON |
---|
6156 | 9942 | config_af_params.extra_listen = false; |
---|
6157 | | -#endif |
---|
| 9943 | +#endif // endif |
---|
6158 | 9944 | |
---|
6159 | 9945 | /* config parameters */ |
---|
6160 | 9946 | /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */ |
---|
.. | .. |
---|
6167 | 9953 | WL_DBG(("Unknown subtype.\n")); |
---|
6168 | 9954 | } |
---|
6169 | 9955 | |
---|
| 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 */ |
---|
6170 | 9966 | } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) { |
---|
6171 | 9967 | /* service discovery process */ |
---|
6172 | 9968 | if (action == P2PSD_ACTION_ID_GAS_IREQ || |
---|
.. | .. |
---|
6179 | 9975 | cfg->next_af_subtype = action + 1; |
---|
6180 | 9976 | |
---|
6181 | 9977 | 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 | + } |
---|
6182 | 9987 | } else if (action == P2PSD_ACTION_ID_GAS_IRESP || |
---|
6183 | 9988 | action == P2PSD_ACTION_ID_GAS_CRESP) { |
---|
6184 | 9989 | /* configure service discovery response frame */ |
---|
.. | .. |
---|
6201 | 10006 | } |
---|
6202 | 10007 | } |
---|
6203 | 10008 | |
---|
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)); |
---|
6210 | 10010 | /* validate channel and p2p ies */ |
---|
6211 | 10011 | if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) && |
---|
6212 | 10012 | netinfo && netinfo->bss.ies.probe_req_ie_len) { |
---|
.. | .. |
---|
6224 | 10024 | if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { |
---|
6225 | 10025 | OSL_SLEEP(50); |
---|
6226 | 10026 | } |
---|
6227 | | -#endif |
---|
| 10027 | +#endif // endif |
---|
6228 | 10028 | |
---|
6229 | 10029 | /* if scan is ongoing, abort current scan. */ |
---|
6230 | 10030 | 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); |
---|
6232 | 10032 | } |
---|
6233 | 10033 | |
---|
6234 | 10034 | /* Abort P2P listen */ |
---|
.. | .. |
---|
6280 | 10080 | WL_ERR(("couldn't find peer's channel.\n")); |
---|
6281 | 10081 | wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, |
---|
6282 | 10082 | 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 | + */ |
---|
6284 | 10090 | } |
---|
6285 | 10091 | |
---|
6286 | 10092 | wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev); |
---|
.. | .. |
---|
6289 | 10095 | * but after the check of piggyback algorithm. |
---|
6290 | 10096 | * To take care of current piggback algo, lets abort the scan here itself. |
---|
6291 | 10097 | */ |
---|
6292 | | - wl_notify_escan_complete(cfg, dev, true, true); |
---|
| 10098 | + wl_cfg80211_cancel_scan(cfg); |
---|
6293 | 10099 | /* Suspend P2P discovery's search-listen to prevent it from |
---|
6294 | 10100 | * starting a scan or changing the channel. |
---|
6295 | 10101 | */ |
---|
.. | .. |
---|
6299 | 10105 | } |
---|
6300 | 10106 | |
---|
6301 | 10107 | /* 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 | + } |
---|
6303 | 10116 | } |
---|
6304 | 10117 | |
---|
6305 | 10118 | #ifdef VSDB |
---|
.. | .. |
---|
6310 | 10123 | |
---|
6311 | 10124 | wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true); |
---|
6312 | 10125 | |
---|
| 10126 | + dwell_jiffies = jiffies; |
---|
6313 | 10127 | /* Now send a tx action frame */ |
---|
6314 | 10128 | 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); |
---|
6315 | 10130 | |
---|
6316 | 10131 | /* 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) { |
---|
6318 | 10134 | #ifdef VSDB |
---|
6319 | 10135 | if (af_params->channel) { |
---|
6320 | 10136 | if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) > |
---|
.. | .. |
---|
6327 | 10143 | #endif /* VSDB */ |
---|
6328 | 10144 | ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? |
---|
6329 | 10145 | false : true; |
---|
| 10146 | + dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies); |
---|
6330 | 10147 | } |
---|
6331 | 10148 | |
---|
6332 | 10149 | if (ack == false) { |
---|
.. | .. |
---|
6343 | 10160 | * the dwell time, go to listen state again to get next action response frame. |
---|
6344 | 10161 | */ |
---|
6345 | 10162 | 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 */ |
---|
6346 | 10166 | wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) && |
---|
6347 | 10167 | cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) { |
---|
6348 | 10168 | s32 extar_listen_time; |
---|
.. | .. |
---|
6366 | 10186 | #endif /* WL_CFG80211_SYNC_GON */ |
---|
6367 | 10187 | wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev); |
---|
6368 | 10188 | |
---|
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; |
---|
6371 | 10190 | |
---|
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)); |
---|
6379 | 10197 | } |
---|
6380 | 10198 | |
---|
| 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 */ |
---|
6381 | 10208 | return ack; |
---|
6382 | 10209 | } |
---|
6383 | 10210 | |
---|
.. | .. |
---|
6395 | 10222 | bool channel_type_valid, |
---|
6396 | 10223 | #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */ |
---|
6397 | 10224 | 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) |
---|
6399 | 10226 | 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) |
---|
6402 | 10229 | bool dont_wait_for_ack, |
---|
6403 | | -#endif |
---|
| 10230 | +#endif // endif |
---|
6404 | 10231 | u64 *cookie) |
---|
6405 | 10232 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ |
---|
6406 | 10233 | { |
---|
.. | .. |
---|
6411 | 10238 | struct ieee80211_channel *channel = params->chan; |
---|
6412 | 10239 | const u8 *buf = params->buf; |
---|
6413 | 10240 | size_t len = params->len; |
---|
6414 | | -#endif |
---|
| 10241 | +#endif // endif |
---|
6415 | 10242 | const struct ieee80211_mgmt *mgmt; |
---|
6416 | 10243 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
6417 | 10244 | struct net_device *dev = NULL; |
---|
.. | .. |
---|
6420 | 10247 | u32 id; |
---|
6421 | 10248 | bool ack = false; |
---|
6422 | 10249 | 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 |
---|
6423 | 10257 | |
---|
6424 | 10258 | WL_DBG(("Enter \n")); |
---|
6425 | 10259 | |
---|
6426 | | - /* The CVE-2017-0706.dff patched here manually */ |
---|
6427 | 10260 | if (len > ACTION_FRAME_SIZE) { |
---|
6428 | 10261 | WL_ERR(("bad length:%zu\n", len)); |
---|
6429 | 10262 | return BCME_BADLEN; |
---|
6430 | 10263 | } |
---|
| 10264 | +#ifdef DHD_IFDEBUG |
---|
| 10265 | + PRINT_WDEV_INFO(cfgdev); |
---|
| 10266 | +#endif /* DHD_IFDEBUG */ |
---|
6431 | 10267 | |
---|
6432 | 10268 | dev = cfgdev_to_wlc_ndev(cfgdev, cfg); |
---|
6433 | 10269 | |
---|
6434 | 10270 | if (!dev) { |
---|
6435 | 10271 | WL_ERR(("dev is NULL\n")); |
---|
6436 | 10272 | return -EINVAL; |
---|
6437 | | - } |
---|
6438 | | - |
---|
6439 | | - if (len > ACTION_FRAME_SIZE) { |
---|
6440 | | - WL_ERR(("bad length:%zu\n", len)); |
---|
6441 | | - return BCME_BADLEN; |
---|
6442 | 10273 | } |
---|
6443 | 10274 | |
---|
6444 | 10275 | /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */ |
---|
.. | .. |
---|
6486 | 10317 | #if defined(P2P_IE_MISSING_FIX) |
---|
6487 | 10318 | if (!cfg->p2p_prb_noti) { |
---|
6488 | 10319 | 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")); |
---|
6491 | 10322 | } |
---|
6492 | | -#endif |
---|
| 10323 | +#endif // endif |
---|
6493 | 10324 | goto exit; |
---|
6494 | 10325 | } else if (ieee80211_is_disassoc(mgmt->frame_control) || |
---|
6495 | 10326 | ieee80211_is_deauth(mgmt->frame_control)) { |
---|
.. | .. |
---|
6500 | 10331 | if (!bcmp((const uint8 *)BSSID_BROADCAST, |
---|
6501 | 10332 | (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) { |
---|
6502 | 10333 | 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)); |
---|
6505 | 10336 | if (err < 0) |
---|
6506 | 10337 | WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); |
---|
6507 | 10338 | else |
---|
.. | .. |
---|
6509 | 10340 | } |
---|
6510 | 10341 | memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); |
---|
6511 | 10342 | 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)); |
---|
6514 | 10345 | if (err < 0) |
---|
6515 | 10346 | 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)); |
---|
6519 | 10350 | |
---|
6520 | 10351 | if (num_associated > 0 && ETHER_ISBCAST(mgmt->da)) |
---|
6521 | 10352 | wl_delay(400); |
---|
.. | .. |
---|
6535 | 10366 | * And previous off-channel action frame must be ended before new af tx. |
---|
6536 | 10367 | */ |
---|
6537 | 10368 | #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST |
---|
6538 | | - wl_notify_escan_complete(cfg, dev, true, true); |
---|
| 10369 | + wl_cfg80211_cancel_scan(cfg); |
---|
6539 | 10370 | #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); |
---|
6541 | 10379 | |
---|
| 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 | + } |
---|
6542 | 10441 | } else { |
---|
6543 | 10442 | WL_ERR(("Driver only allows MGMT packet type\n")); |
---|
6544 | 10443 | goto exit; |
---|
6545 | 10444 | } |
---|
6546 | 10445 | |
---|
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); |
---|
6548 | 10447 | |
---|
6549 | 10448 | if (af_params == NULL) |
---|
6550 | 10449 | { |
---|
.. | .. |
---|
6576 | 10475 | af_params->dwell_time = params->wait; |
---|
6577 | 10476 | #else |
---|
6578 | 10477 | af_params->dwell_time = wait; |
---|
6579 | | -#endif |
---|
| 10478 | +#endif // endif |
---|
6580 | 10479 | |
---|
6581 | 10480 | memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); |
---|
6582 | 10481 | |
---|
.. | .. |
---|
6584 | 10483 | action_frame, action_frame->len, bssidx); |
---|
6585 | 10484 | cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL); |
---|
6586 | 10485 | |
---|
6587 | | - kfree(af_params); |
---|
| 10486 | + MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE); |
---|
6588 | 10487 | exit: |
---|
6589 | 10488 | return err; |
---|
6590 | 10489 | } |
---|
6591 | 10490 | |
---|
| 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)); |
---|
6592 | 10498 | |
---|
| 10499 | + return; |
---|
| 10500 | +} |
---|
| 10501 | +#else |
---|
6593 | 10502 | static void |
---|
6594 | 10503 | wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, |
---|
6595 | | - u16 frame_type, bool reg) |
---|
| 10504 | + u16 frame, bool reg) |
---|
6596 | 10505 | { |
---|
6597 | 10506 | |
---|
6598 | | - WL_DBG(("frame_type: %x, reg: %d\n", frame_type, reg)); |
---|
| 10507 | + WL_DBG(("frame_type: %x, reg: %d\n", frame, reg)); |
---|
6599 | 10508 | |
---|
6600 | | - if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) |
---|
| 10509 | + if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) |
---|
6601 | 10510 | return; |
---|
6602 | 10511 | |
---|
6603 | 10512 | return; |
---|
6604 | 10513 | } |
---|
6605 | | - |
---|
| 10514 | +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) */ |
---|
6606 | 10515 | |
---|
6607 | 10516 | static s32 |
---|
6608 | 10517 | wl_cfg80211_change_bss(struct wiphy *wiphy, |
---|
.. | .. |
---|
6611 | 10520 | { |
---|
6612 | 10521 | s32 err = 0; |
---|
6613 | 10522 | s32 ap_isolate = 0; |
---|
6614 | | -#ifdef PCIE_FULL_DONGLE |
---|
6615 | 10523 | s32 ifidx = DHD_BAD_IF; |
---|
6616 | | -#endif |
---|
6617 | | -#if defined(PCIE_FULL_DONGLE) |
---|
6618 | 10524 | dhd_pub_t *dhd; |
---|
6619 | 10525 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
6620 | 10526 | dhd = (dhd_pub_t *)(cfg->pub); |
---|
6621 | 10527 | #if defined(WL_ENABLE_P2P_IF) |
---|
6622 | 10528 | if (cfg->p2p_net == dev) |
---|
6623 | 10529 | dev = bcmcfg_to_prmry_ndev(cfg); |
---|
6624 | | -#endif |
---|
6625 | | -#endif |
---|
| 10530 | +#endif // endif |
---|
6626 | 10531 | |
---|
6627 | 10532 | if (params->use_cts_prot >= 0) { |
---|
6628 | 10533 | } |
---|
.. | .. |
---|
6638 | 10543 | |
---|
6639 | 10544 | if (params->ap_isolate >= 0) { |
---|
6640 | 10545 | ap_isolate = params->ap_isolate; |
---|
6641 | | -#ifdef PCIE_FULL_DONGLE |
---|
6642 | 10546 | ifidx = dhd_net2idx(dhd->info, dev); |
---|
6643 | 10547 | |
---|
6644 | 10548 | if (ifidx != DHD_BAD_IF) { |
---|
.. | .. |
---|
6646 | 10550 | } else { |
---|
6647 | 10551 | WL_ERR(("Failed to set ap_isolate\n")); |
---|
6648 | 10552 | } |
---|
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); |
---|
6651 | 10558 | if (unlikely(err)) |
---|
6652 | 10559 | { |
---|
6653 | 10560 | WL_ERR(("set ap_isolate Error (%d)\n", err)); |
---|
6654 | 10561 | } |
---|
6655 | | -#endif /* PCIE_FULL_DONGLE */ |
---|
| 10562 | +#endif /* BCMSDIO */ |
---|
6656 | 10563 | } |
---|
6657 | 10564 | |
---|
6658 | 10565 | if (params->ht_opmode >= 0) { |
---|
6659 | 10566 | } |
---|
6660 | 10567 | |
---|
6661 | | - |
---|
6662 | 10568 | return err; |
---|
6663 | 10569 | } |
---|
6664 | 10570 | |
---|
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) |
---|
6676 | 10573 | { |
---|
6677 | | - s32 _chan; |
---|
6678 | | - chanspec_t chspec = 0; |
---|
6679 | | - chanspec_t fw_chspec = 0; |
---|
6680 | 10574 | 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 | | - |
---|
6685 | 10575 | s32 err = BCME_OK; |
---|
6686 | 10576 | s32 bw_cap = 0; |
---|
6687 | 10577 | struct { |
---|
6688 | 10578 | u32 band; |
---|
6689 | 10579 | u32 bw_cap; |
---|
6690 | 10580 | } 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; |
---|
6691 | 10585 | 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 */ |
---|
6695 | 10586 | |
---|
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", ¶m, 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 */ |
---|
6699 | 10658 | |
---|
6700 | 10659 | dev = ndev_to_wlc_ndev(dev, cfg); |
---|
6701 | 10660 | _chan = ieee80211_frequency_to_channel(chan->center_freq); |
---|
6702 | 10661 | WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", |
---|
6703 | 10662 | dev->ifindex, channel_type, _chan)); |
---|
6704 | 10663 | |
---|
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", ¶m, 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) { |
---|
6759 | 10679 | bw = WL_CHANSPEC_BW_20; |
---|
6760 | | - |
---|
| 10680 | + goto set_channel; |
---|
| 10681 | + } |
---|
6761 | 10682 | } |
---|
| 10683 | + } |
---|
| 10684 | +#endif /* APSTA_RESTRICTED_CHANNEL */ |
---|
6762 | 10685 | |
---|
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 | + |
---|
6765 | 10692 | set_channel: |
---|
6766 | 10693 | chspec = wf_channel2chspec(_chan, bw); |
---|
6767 | 10694 | if (wf_chspec_valid(chspec)) { |
---|
.. | .. |
---|
6771 | 10698 | fw_chspec)) == BCME_BADCHAN) { |
---|
6772 | 10699 | if (bw == WL_CHANSPEC_BW_80) |
---|
6773 | 10700 | 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)); |
---|
6776 | 10703 | if (err < 0) { |
---|
6777 | 10704 | WL_ERR(("WLC_SET_CHANNEL error %d" |
---|
6778 | 10705 | "chip may not be supporting this channel\n", err)); |
---|
.. | .. |
---|
6780 | 10707 | } else if (err) { |
---|
6781 | 10708 | WL_ERR(("failed to set chanspec error %d\n", err)); |
---|
6782 | 10709 | } |
---|
| 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 */ |
---|
6783 | 10724 | } else { |
---|
6784 | 10725 | WL_ERR(("failed to convert host chanspec to fw chanspec\n")); |
---|
6785 | 10726 | err = BCME_ERROR; |
---|
.. | .. |
---|
6814 | 10755 | } |
---|
6815 | 10756 | } |
---|
6816 | 10757 | #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 | + } |
---|
6817 | 10766 | return err; |
---|
6818 | 10767 | } |
---|
6819 | 10768 | |
---|
.. | .. |
---|
6822 | 10771 | wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg) |
---|
6823 | 10772 | { |
---|
6824 | 10773 | struct net_info *_net_info, *next; |
---|
| 10774 | + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); |
---|
6825 | 10775 | list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) { |
---|
| 10776 | + GCC_DIAGNOSTIC_POP(); |
---|
6826 | 10777 | if (_net_info->ndev && |
---|
6827 | 10778 | test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state)) |
---|
6828 | 10779 | return _net_info->ndev; |
---|
6829 | 10780 | } |
---|
| 10781 | + |
---|
6830 | 10782 | return NULL; |
---|
6831 | 10783 | } |
---|
6832 | 10784 | #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 */ |
---|
6833 | 10817 | |
---|
6834 | 10818 | static s32 |
---|
6835 | 10819 | wl_validate_opensecurity(struct net_device *dev, s32 bssidx, bool privacy) |
---|
.. | .. |
---|
6872 | 10856 | return 0; |
---|
6873 | 10857 | } |
---|
6874 | 10858 | |
---|
| 10859 | +#define MAX_FILS_IND_IE_LEN 1024u |
---|
6875 | 10860 | 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) |
---|
6877 | 10918 | { |
---|
6878 | 10919 | s32 len = 0; |
---|
6879 | 10920 | s32 err = BCME_OK; |
---|
.. | .. |
---|
6882 | 10923 | u32 pval = 0; |
---|
6883 | 10924 | u32 gval = 0; |
---|
6884 | 10925 | 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; |
---|
6889 | 10930 | int cnt = 0; |
---|
6890 | 10931 | #ifdef MFP |
---|
6891 | 10932 | int mfp = 0; |
---|
6892 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 10933 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
6893 | 10934 | #endif /* MFP */ |
---|
6894 | 10935 | |
---|
6895 | 10936 | u16 suite_count; |
---|
.. | .. |
---|
6902 | 10943 | WL_DBG(("Enter \n")); |
---|
6903 | 10944 | len = wpa2ie->len - WPA2_VERSION_LEN; |
---|
6904 | 10945 | /* 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]; |
---|
6906 | 10947 | switch (mcast->type) { |
---|
6907 | 10948 | case WPA_CIPHER_NONE: |
---|
6908 | 10949 | gval = 0; |
---|
.. | .. |
---|
6917 | 10958 | case WPA_CIPHER_AES_CCM: |
---|
6918 | 10959 | gval = AES_ENABLED; |
---|
6919 | 10960 | 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; |
---|
6920 | 10969 | default: |
---|
6921 | 10970 | WL_ERR(("No Security Info\n")); |
---|
6922 | 10971 | break; |
---|
.. | .. |
---|
6925 | 10974 | return BCME_BADLEN; |
---|
6926 | 10975 | |
---|
6927 | 10976 | /* check the unicast cipher */ |
---|
6928 | | - ucast = (wpa_suite_ucast_t *)&mcast[1]; |
---|
| 10977 | + ucast = (const wpa_suite_ucast_t *)&mcast[1]; |
---|
6929 | 10978 | suite_count = ltoh16_ua(&ucast->count); |
---|
6930 | 10979 | switch (ucast->list[0].type) { |
---|
6931 | 10980 | case WPA_CIPHER_NONE: |
---|
.. | .. |
---|
6941 | 10990 | case WPA_CIPHER_AES_CCM: |
---|
6942 | 10991 | pval = AES_ENABLED; |
---|
6943 | 10992 | 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; |
---|
6944 | 11001 | default: |
---|
6945 | 11002 | WL_ERR(("No Security Info\n")); |
---|
6946 | 11003 | } |
---|
.. | .. |
---|
6950 | 11007 | /* FOR WPS , set SEC_OW_ENABLED */ |
---|
6951 | 11008 | wsec = (pval | gval | SES_OW_ENABLED); |
---|
6952 | 11009 | /* 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]; |
---|
6954 | 11011 | suite_count = cnt = ltoh16_ua(&mgmt->count); |
---|
6955 | 11012 | while (cnt--) { |
---|
| 11013 | + if (!bcmp(mgmt->list[cnt].oui, WPA2_OUI, WPA2_OUI_LEN)) { |
---|
6956 | 11014 | switch (mgmt->list[cnt].type) { |
---|
6957 | 11015 | case RSN_AKM_NONE: |
---|
6958 | | - wpa_auth |= WPA_AUTH_NONE; |
---|
| 11016 | + wpa_auth |= WPA_AUTH_NONE; |
---|
6959 | 11017 | break; |
---|
6960 | 11018 | case RSN_AKM_UNSPECIFIED: |
---|
6961 | | - wpa_auth |= WPA2_AUTH_UNSPECIFIED; |
---|
| 11019 | + wpa_auth |= WPA2_AUTH_UNSPECIFIED; |
---|
6962 | 11020 | break; |
---|
6963 | 11021 | 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; |
---|
6972 | 11023 | 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 */ |
---|
6973 | 11045 | #endif /* MFP */ |
---|
6974 | 11046 | default: |
---|
6975 | 11047 | WL_ERR(("No Key Mgmt Info\n")); |
---|
6976 | 11048 | } |
---|
| 11049 | + } else if (!bcmp(mgmt->list[cnt].oui, WFA_OUI, WFA_OUI_LEN)) |
---|
| 11050 | + wpa_auth |= WPA2_WFA_AUTH_DPP; |
---|
6977 | 11051 | } |
---|
6978 | 11052 | |
---|
6979 | 11053 | 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); |
---|
6982 | 11056 | |
---|
6983 | 11057 | if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) { |
---|
6984 | 11058 | wme_bss_disable = 0; |
---|
.. | .. |
---|
7016 | 11090 | |
---|
7017 | 11091 | len -= RSN_CAP_LEN; |
---|
7018 | 11092 | 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); |
---|
7020 | 11095 | cnt = ltoh16_ua(&pmkid->count); |
---|
7021 | 11096 | if (cnt != 0) { |
---|
7022 | 11097 | WL_ERR(("AP has non-zero PMKID count. Wrong!\n")); |
---|
.. | .. |
---|
7029 | 11104 | #ifdef MFP |
---|
7030 | 11105 | len -= WPA2_PMKID_COUNT_LEN; |
---|
7031 | 11106 | 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; |
---|
7040 | 11111 | } |
---|
7041 | | -#endif |
---|
| 11112 | +#endif // endif |
---|
7042 | 11113 | |
---|
7043 | 11114 | /* set auth */ |
---|
7044 | 11115 | err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); |
---|
.. | .. |
---|
7055 | 11126 | } |
---|
7056 | 11127 | |
---|
7057 | 11128 | #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; |
---|
7067 | 11130 | #endif /* MFP */ |
---|
7068 | 11131 | |
---|
7069 | 11132 | /* set upper-layer auth */ |
---|
.. | .. |
---|
7077 | 11140 | } |
---|
7078 | 11141 | |
---|
7079 | 11142 | 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) |
---|
7081 | 11144 | { |
---|
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; |
---|
7085 | 11148 | u16 auth = 0; /* d11 open authentication */ |
---|
7086 | 11149 | u16 count; |
---|
7087 | 11150 | s32 err = BCME_OK; |
---|
.. | .. |
---|
7100 | 11163 | len -= WPA_IE_TAG_FIXED_LEN; |
---|
7101 | 11164 | /* check for multicast cipher suite */ |
---|
7102 | 11165 | if (len < WPA_SUITE_LEN) { |
---|
7103 | | - WL_INFORM(("no multicast cipher suite\n")); |
---|
| 11166 | + WL_INFORM_MEM(("no multicast cipher suite\n")); |
---|
7104 | 11167 | goto exit; |
---|
7105 | 11168 | } |
---|
7106 | 11169 | |
---|
7107 | 11170 | /* pick up multicast cipher */ |
---|
7108 | | - mcast = (wpa_suite_mcast_t *)&wpaie[1]; |
---|
| 11171 | + mcast = (const wpa_suite_mcast_t *)&wpaie[1]; |
---|
7109 | 11172 | len -= WPA_SUITE_LEN; |
---|
7110 | 11173 | if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) { |
---|
7111 | 11174 | if (IS_WPA_CIPHER(mcast->type)) { |
---|
.. | .. |
---|
7132 | 11195 | } |
---|
7133 | 11196 | /* Check for unicast suite(s) */ |
---|
7134 | 11197 | if (len < WPA_IE_SUITE_COUNT_LEN) { |
---|
7135 | | - WL_INFORM(("no unicast suite\n")); |
---|
| 11198 | + WL_INFORM_MEM(("no unicast suite\n")); |
---|
7136 | 11199 | goto exit; |
---|
7137 | 11200 | } |
---|
7138 | 11201 | /* 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]; |
---|
7140 | 11203 | count = ltoh16_ua(&ucast->count); |
---|
7141 | 11204 | len -= WPA_IE_SUITE_COUNT_LEN; |
---|
7142 | 11205 | for (i = 0; i < count && len >= WPA_SUITE_LEN; |
---|
.. | .. |
---|
7168 | 11231 | len -= (count - i) * WPA_SUITE_LEN; |
---|
7169 | 11232 | /* Check for auth key management suite(s) */ |
---|
7170 | 11233 | 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")); |
---|
7172 | 11235 | goto exit; |
---|
7173 | 11236 | } |
---|
7174 | 11237 | /* 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]; |
---|
7176 | 11239 | count = ltoh16_ua(&mgmt->count); |
---|
7177 | 11240 | len -= WPA_IE_SUITE_COUNT_LEN; |
---|
7178 | 11241 | for (i = 0; i < count && len >= WPA_SUITE_LEN; |
---|
.. | .. |
---|
7222 | 11285 | return 0; |
---|
7223 | 11286 | } |
---|
7224 | 11287 | |
---|
| 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 */ |
---|
7225 | 11531 | |
---|
7226 | 11532 | static s32 |
---|
7227 | 11533 | wl_cfg80211_bcn_validate_sec( |
---|
.. | .. |
---|
7231 | 11537 | s32 bssidx, |
---|
7232 | 11538 | bool privacy) |
---|
7233 | 11539 | { |
---|
7234 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 11540 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
7235 | 11541 | wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr); |
---|
7236 | 11542 | |
---|
7237 | 11543 | if (!bss) { |
---|
.. | .. |
---|
7250 | 11556 | WL_DBG(("SoftAP: validating security")); |
---|
7251 | 11557 | /* If wpa2_ie or wpa_ie is present validate it */ |
---|
7252 | 11558 | |
---|
| 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 */ |
---|
7253 | 11568 | if ((ies->wpa2_ie || ies->wpa_ie) && |
---|
7254 | 11569 | ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || |
---|
7255 | 11570 | wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) { |
---|
.. | .. |
---|
7257 | 11572 | return BCME_ERROR; |
---|
7258 | 11573 | } |
---|
7259 | 11574 | |
---|
| 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 | + |
---|
7260 | 11581 | bss->security_mode = true; |
---|
7261 | 11582 | 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); |
---|
7263 | 11585 | bss->rsn_ie = NULL; |
---|
7264 | 11586 | } |
---|
7265 | 11587 | 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); |
---|
7267 | 11590 | bss->wpa_ie = NULL; |
---|
7268 | 11591 | } |
---|
7269 | 11592 | if (bss->wps_ie) { |
---|
7270 | | - kfree(bss->wps_ie); |
---|
| 11593 | + MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2); |
---|
7271 | 11594 | 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); |
---|
7272 | 11599 | } |
---|
7273 | 11600 | if (ies->wpa_ie != NULL) { |
---|
7274 | 11601 | /* WPAIE */ |
---|
7275 | 11602 | 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 | + } |
---|
7279 | 11611 | } else if (ies->wpa2_ie != NULL) { |
---|
7280 | 11612 | /* RSNIE */ |
---|
7281 | 11613 | 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 | + } |
---|
7285 | 11622 | } |
---|
| 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 */ |
---|
7286 | 11638 | if (!ies->wpa2_ie && !ies->wpa_ie) { |
---|
7287 | 11639 | wl_validate_opensecurity(dev, bssidx, privacy); |
---|
7288 | 11640 | bss->security_mode = false; |
---|
7289 | 11641 | } |
---|
7290 | 11642 | |
---|
7291 | 11643 | 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 | + } |
---|
7293 | 11648 | } |
---|
7294 | 11649 | } |
---|
7295 | 11650 | |
---|
.. | .. |
---|
7297 | 11652 | |
---|
7298 | 11653 | } |
---|
7299 | 11654 | |
---|
7300 | | -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) |
---|
| 11655 | +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) |
---|
7301 | 11656 | static s32 wl_cfg80211_bcn_set_params( |
---|
7302 | 11657 | struct cfg80211_ap_settings *info, |
---|
7303 | 11658 | struct net_device *dev, |
---|
7304 | 11659 | u32 dev_role, s32 bssidx) |
---|
7305 | 11660 | { |
---|
7306 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 11661 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
7307 | 11662 | s32 err = BCME_OK; |
---|
7308 | 11663 | |
---|
7309 | 11664 | WL_DBG(("interval (%d) \ndtim_period (%d) \n", |
---|
7310 | 11665 | info->beacon_interval, info->dtim_period)); |
---|
7311 | 11666 | |
---|
7312 | 11667 | 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) { |
---|
7315 | 11670 | WL_ERR(("Beacon Interval Set Error, %d\n", err)); |
---|
7316 | 11671 | return err; |
---|
7317 | 11672 | } |
---|
7318 | 11673 | } |
---|
7319 | 11674 | |
---|
7320 | 11675 | 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) { |
---|
7323 | 11678 | WL_ERR(("DTIM Interval Set Error, %d\n", err)); |
---|
7324 | 11679 | return err; |
---|
7325 | 11680 | } |
---|
7326 | 11681 | } |
---|
7327 | 11682 | |
---|
7328 | 11683 | if ((info->ssid) && (info->ssid_len > 0) && |
---|
7329 | | - (info->ssid_len <= 32)) { |
---|
| 11684 | + (info->ssid_len <= DOT11_MAX_SSID_LEN)) { |
---|
7330 | 11685 | WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len)); |
---|
7331 | 11686 | if (dev_role == NL80211_IFTYPE_AP) { |
---|
7332 | 11687 | /* Store the hostapd SSID */ |
---|
7333 | | - memset(cfg->hostapd_ssid.SSID, 0x00, 32); |
---|
| 11688 | + bzero(cfg->hostapd_ssid.SSID, DOT11_MAX_SSID_LEN); |
---|
7334 | 11689 | 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; |
---|
7336 | 11691 | } else { |
---|
7337 | 11692 | /* P2P GO */ |
---|
7338 | | - memset(cfg->p2p->ssid.SSID, 0x00, 32); |
---|
| 11693 | + bzero(cfg->p2p->ssid.SSID, DOT11_MAX_SSID_LEN); |
---|
7339 | 11694 | 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; |
---|
7341 | 11696 | } |
---|
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)); |
---|
7348 | 11697 | } |
---|
7349 | 11698 | |
---|
7350 | 11699 | return err; |
---|
7351 | 11700 | } |
---|
7352 | | -#endif |
---|
| 11701 | +#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */ |
---|
7353 | 11702 | |
---|
7354 | 11703 | 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) |
---|
7356 | 11705 | { |
---|
7357 | 11706 | s32 err = BCME_OK; |
---|
7358 | 11707 | |
---|
7359 | | - memset(ies, 0, sizeof(struct parsed_ies)); |
---|
| 11708 | + bzero(ies, sizeof(struct parsed_ies)); |
---|
7360 | 11709 | |
---|
7361 | 11710 | /* find the WPSIE */ |
---|
7362 | 11711 | if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) { |
---|
.. | .. |
---|
7373 | 11722 | ies->wpa2_ie_len = ies->wpa2_ie->len; |
---|
7374 | 11723 | } |
---|
7375 | 11724 | |
---|
| 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 | + |
---|
7376 | 11732 | /* find the WPA_IE */ |
---|
7377 | 11733 | if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) { |
---|
7378 | 11734 | WL_DBG((" WPA found\n")); |
---|
.. | .. |
---|
7382 | 11738 | return err; |
---|
7383 | 11739 | |
---|
7384 | 11740 | } |
---|
| 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; |
---|
7385 | 11752 | |
---|
| 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 |
---|
7386 | 11834 | static s32 |
---|
7387 | 11835 | wl_cfg80211_bcn_bringup_ap( |
---|
7388 | 11836 | struct net_device *dev, |
---|
7389 | 11837 | struct parsed_ies *ies, |
---|
7390 | 11838 | u32 dev_role, s32 bssidx) |
---|
7391 | 11839 | { |
---|
7392 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 11840 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
7393 | 11841 | struct wl_join_params join_params; |
---|
7394 | 11842 | bool is_bssup = false; |
---|
7395 | 11843 | s32 infra = 1; |
---|
7396 | 11844 | s32 join_params_size = 0; |
---|
7397 | | - s32 ap = 1; |
---|
7398 | | - s32 pm; |
---|
7399 | 11845 | 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 */ |
---|
7400 | 11852 | s32 err = BCME_OK; |
---|
7401 | 11853 | 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 |
---|
7402 | 11859 | |
---|
7403 | 11860 | is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE); |
---|
7404 | 11861 | if (is_rsdb_supported < 0) |
---|
7405 | 11862 | return (-ENODEV); |
---|
7406 | 11863 | |
---|
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)); |
---|
7408 | 11865 | |
---|
7409 | 11866 | /* 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); |
---|
7411 | 11878 | |
---|
7412 | 11879 | 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); |
---|
7414 | 11881 | 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); |
---|
7417 | 11883 | if (err < 0) { |
---|
7418 | | - WL_ERR(("SET INFRA error %d\n", err)); |
---|
| 11884 | + WL_ERR(("MPC setting failed, ret=%d\n", err)); |
---|
7419 | 11885 | goto exit; |
---|
7420 | 11886 | } |
---|
7421 | | - |
---|
7422 | 11887 | err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid, |
---|
7423 | 11888 | sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, |
---|
7424 | 11889 | bssidx, &cfg->ioctl_buf_sync); |
---|
.. | .. |
---|
7427 | 11892 | goto exit; |
---|
7428 | 11893 | } |
---|
7429 | 11894 | |
---|
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 */ |
---|
7432 | 11905 | |
---|
7433 | | - if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) { |
---|
| 11906 | + if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) { |
---|
7434 | 11907 | WL_ERR(("GO Bring up error %d\n", err)); |
---|
7435 | 11908 | goto exit; |
---|
7436 | 11909 | } |
---|
7437 | 11910 | } else |
---|
7438 | 11911 | 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) { |
---|
7442 | 11913 | |
---|
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")); |
---|
7477 | 11919 | goto exit; |
---|
7478 | 11920 | } |
---|
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 | | - |
---|
7495 | 11921 | } |
---|
7496 | 11922 | |
---|
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)); |
---|
7498 | 11960 | if (unlikely(err)) { |
---|
7499 | 11961 | WL_ERR(("WLC_UP error (%d)\n", err)); |
---|
7500 | 11962 | goto exit; |
---|
7501 | 11963 | } |
---|
| 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 */ |
---|
7502 | 11990 | |
---|
7503 | 11991 | err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec); |
---|
7504 | 11992 | if (unlikely(err)) { |
---|
.. | .. |
---|
7511 | 11999 | sizeof(struct wl_wsec_key), cfg->ioctl_buf, |
---|
7512 | 12000 | WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); |
---|
7513 | 12001 | /* 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)); |
---|
7515 | 12003 | if (unlikely(err)) { |
---|
7516 | 12004 | WL_ERR(("WLC_SET_KEY error (%d)\n", err)); |
---|
7517 | 12005 | goto exit; |
---|
7518 | 12006 | } |
---|
7519 | 12007 | } |
---|
7520 | 12008 | |
---|
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) { |
---|
7543 | 12018 | goto exit; |
---|
7544 | 12019 | } |
---|
7545 | 12020 | } |
---|
| 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; |
---|
7546 | 12049 | } |
---|
7547 | 12050 | |
---|
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")); |
---|
7550 | 12076 | |
---|
7551 | 12077 | 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 | + } |
---|
7554 | 12095 | return err; |
---|
7555 | 12096 | } |
---|
7556 | 12097 | |
---|
7557 | | -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) |
---|
| 12098 | +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS) |
---|
7558 | 12099 | s32 |
---|
7559 | 12100 | wl_cfg80211_parse_ap_ies( |
---|
7560 | 12101 | struct net_device *dev, |
---|
.. | .. |
---|
7562 | 12103 | struct parsed_ies *ies) |
---|
7563 | 12104 | { |
---|
7564 | 12105 | struct parsed_ies prb_ies; |
---|
7565 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 12106 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
7566 | 12107 | dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); |
---|
7567 | | - u8 *vndr = NULL; |
---|
| 12108 | + const u8 *vndr = NULL; |
---|
7568 | 12109 | u32 vndr_ie_len = 0; |
---|
7569 | 12110 | s32 err = BCME_OK; |
---|
7570 | 12111 | |
---|
7571 | 12112 | /* Parse Beacon IEs */ |
---|
7572 | | - if (wl_cfg80211_parse_ies((u8 *)info->tail, |
---|
| 12113 | + if (wl_cfg80211_parse_ies((const u8 *)info->tail, |
---|
7573 | 12114 | info->tail_len, ies) < 0) { |
---|
7574 | 12115 | WL_ERR(("Beacon get IEs failed \n")); |
---|
7575 | 12116 | err = -EINVAL; |
---|
7576 | 12117 | goto fail; |
---|
7577 | 12118 | } |
---|
7578 | 12119 | |
---|
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; |
---|
7581 | 12122 | |
---|
7582 | 12123 | if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { |
---|
7583 | 12124 | /* 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; |
---|
7586 | 12127 | 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)); |
---|
7590 | 12131 | } |
---|
7591 | 12132 | } |
---|
7592 | | - |
---|
7593 | 12133 | /* 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) { |
---|
7595 | 12135 | WL_ERR(("PROBE RESP get IEs failed \n")); |
---|
7596 | 12136 | err = -EINVAL; |
---|
7597 | 12137 | } |
---|
7598 | | - |
---|
7599 | 12138 | fail: |
---|
7600 | 12139 | |
---|
7601 | 12140 | return err; |
---|
.. | .. |
---|
7607 | 12146 | struct cfg80211_beacon_data *info, |
---|
7608 | 12147 | s32 bssidx) |
---|
7609 | 12148 | { |
---|
7610 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 12149 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
7611 | 12150 | dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); |
---|
7612 | | - u8 *vndr = NULL; |
---|
| 12151 | + const u8 *vndr = NULL; |
---|
7613 | 12152 | u32 vndr_ie_len = 0; |
---|
7614 | 12153 | s32 err = BCME_OK; |
---|
7615 | 12154 | |
---|
.. | .. |
---|
7622 | 12161 | WL_DBG(("Applied Vndr IEs for Beacon \n")); |
---|
7623 | 12162 | } |
---|
7624 | 12163 | |
---|
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; |
---|
7627 | 12166 | |
---|
7628 | 12167 | if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { |
---|
7629 | 12168 | /* 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; |
---|
7632 | 12171 | 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)); |
---|
7636 | 12175 | } |
---|
7637 | 12176 | } |
---|
7638 | 12177 | |
---|
7639 | 12178 | /* Set Probe Response IEs to FW */ |
---|
7640 | 12179 | if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx, |
---|
7641 | 12180 | 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")); |
---|
7643 | 12182 | } else { |
---|
7644 | 12183 | WL_DBG(("Applied Vndr IEs for Probe Resp \n")); |
---|
7645 | 12184 | } |
---|
7646 | 12185 | |
---|
| 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 | + |
---|
7647 | 12197 | return err; |
---|
7648 | 12198 | } |
---|
7649 | | -#endif |
---|
| 12199 | +#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */ |
---|
7650 | 12200 | |
---|
7651 | 12201 | static s32 wl_cfg80211_hostapd_sec( |
---|
7652 | 12202 | struct net_device *dev, |
---|
.. | .. |
---|
7654 | 12204 | s32 bssidx) |
---|
7655 | 12205 | { |
---|
7656 | 12206 | bool update_bss = 0; |
---|
7657 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 12207 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
7658 | 12208 | wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr); |
---|
7659 | 12209 | |
---|
7660 | 12210 | if (!bss) { |
---|
.. | .. |
---|
7666 | 12216 | if (bss->wps_ie && |
---|
7667 | 12217 | memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) { |
---|
7668 | 12218 | 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 | + } |
---|
7671 | 12224 | } else if (bss->wps_ie == NULL) { |
---|
7672 | 12225 | 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 | + } |
---|
7674 | 12230 | } |
---|
7675 | 12231 | |
---|
| 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 */ |
---|
7676 | 12322 | if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) { |
---|
7677 | 12323 | if (!bss->security_mode) { |
---|
7678 | 12324 | /* change from open mode to security mode */ |
---|
7679 | 12325 | update_bss = true; |
---|
7680 | 12326 | 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 | + } |
---|
7684 | 12335 | } 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 | + } |
---|
7688 | 12344 | } |
---|
7689 | 12345 | } else if (bss->wpa_ie) { |
---|
7690 | 12346 | /* change from WPA2 mode to WPA mode */ |
---|
7691 | 12347 | if (ies->wpa_ie != NULL) { |
---|
7692 | 12348 | 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 | + } |
---|
7698 | 12359 | } else if (memcmp(bss->rsn_ie, |
---|
7699 | 12360 | ies->wpa2_ie, ies->wpa2_ie->len |
---|
7700 | 12361 | + WPA_RSN_IE_TAG_FIXED_LEN)) { |
---|
7701 | 12362 | 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 | + } |
---|
7706 | 12373 | bss->wpa_ie = NULL; |
---|
7707 | 12374 | } |
---|
7708 | 12375 | } |
---|
7709 | 12376 | if (update_bss) { |
---|
7710 | 12377 | bss->security_mode = true; |
---|
7711 | | - wl_cfgp2p_bss(cfg, dev, bssidx, 0); |
---|
| 12378 | + wl_cfg80211_bss_up(cfg, dev, bssidx, 0); |
---|
7712 | 12379 | if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || |
---|
7713 | 12380 | wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) { |
---|
7714 | 12381 | return BCME_ERROR; |
---|
7715 | 12382 | } |
---|
7716 | | - wl_cfgp2p_bss(cfg, dev, bssidx, 1); |
---|
| 12383 | + wl_cfg80211_bss_up(cfg, dev, bssidx, 1); |
---|
7717 | 12384 | } |
---|
7718 | 12385 | } |
---|
7719 | 12386 | } else { |
---|
.. | .. |
---|
7755 | 12422 | |
---|
7756 | 12423 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) |
---|
7757 | 12424 | 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 */ |
---|
7758 | 12428 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */ |
---|
7759 | | - |
---|
7760 | 12429 | WL_DBG(("Entry\n")); |
---|
7761 | 12430 | if (mac_addr == NULL) { |
---|
7762 | 12431 | WL_DBG(("mac_addr is NULL ignore it\n")); |
---|
.. | .. |
---|
7776 | 12445 | } |
---|
7777 | 12446 | |
---|
7778 | 12447 | 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)); |
---|
7781 | 12450 | if (err < 0) |
---|
7782 | 12451 | WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); |
---|
7783 | 12452 | else |
---|
7784 | 12453 | num_associated = assoc_maclist->count; |
---|
7785 | 12454 | |
---|
7786 | 12455 | 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 */ |
---|
7795 | 12495 | |
---|
7796 | 12496 | if (num_associated > 0 && ETHER_ISBCAST(mac_addr)) |
---|
7797 | 12497 | wl_delay(400); |
---|
.. | .. |
---|
7813 | 12513 | struct net_device *dev, |
---|
7814 | 12514 | u8 *mac, |
---|
7815 | 12515 | struct station_parameters *params) |
---|
7816 | | -#endif |
---|
| 12516 | +#endif // endif |
---|
7817 | 12517 | { |
---|
7818 | | - int err; |
---|
7819 | | -#ifdef DHD_LOSSLESS_ROAMING |
---|
| 12518 | + int err = BCME_OK; |
---|
7820 | 12519 | 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 */ |
---|
7822 | 12523 | |
---|
7823 | 12524 | WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x " |
---|
7824 | 12525 | "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac), |
---|
7825 | 12526 | 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 | + } |
---|
7826 | 12534 | |
---|
7827 | 12535 | /* Processing only authorize/de-authorize flag for now */ |
---|
7828 | 12536 | if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) { |
---|
.. | .. |
---|
7831 | 12539 | } |
---|
7832 | 12540 | |
---|
7833 | 12541 | 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)) { |
---|
7840 | 12544 | 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 | + } |
---|
7841 | 12549 | return err; |
---|
7842 | 12550 | } |
---|
7843 | 12551 | |
---|
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)) { |
---|
7850 | 12554 | 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 | + } |
---|
7851 | 12562 | #ifdef DHD_LOSSLESS_ROAMING |
---|
7852 | 12563 | 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 | + |
---|
7854 | 12575 | return err; |
---|
7855 | 12576 | } |
---|
7856 | 12577 | #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ |
---|
7857 | 12578 | |
---|
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) |
---|
7859 | 12633 | static s32 |
---|
7860 | 12634 | wl_cfg80211_start_ap( |
---|
7861 | 12635 | struct wiphy *wiphy, |
---|
.. | .. |
---|
7868 | 12642 | s32 bssidx = 0; |
---|
7869 | 12643 | u32 dev_role = 0; |
---|
7870 | 12644 | 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 | + |
---|
7871 | 12654 | 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); |
---|
7876 | 12659 | } |
---|
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) { |
---|
7886 | 12663 | WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); |
---|
7887 | 12664 | return BCME_ERROR; |
---|
7888 | 12665 | } |
---|
7889 | 12666 | |
---|
7890 | 12667 | if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) { |
---|
7891 | 12668 | 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; |
---|
7893 | 12671 | 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 */ |
---|
7894 | 12684 | #ifdef ARP_OFFLOAD_SUPPORT |
---|
7895 | 12685 | /* 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 | + } |
---|
7898 | 12690 | #endif /* ARP_OFFLOAD_SUPPORT */ |
---|
7899 | 12691 | } else { |
---|
7900 | 12692 | /* only AP or GO role need to be handled here. */ |
---|
.. | .. |
---|
7902 | 12694 | goto fail; |
---|
7903 | 12695 | } |
---|
7904 | 12696 | |
---|
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)) { |
---|
7906 | 12708 | err = -EINVAL; |
---|
7907 | 12709 | goto fail; |
---|
7908 | 12710 | } |
---|
7909 | 12711 | |
---|
7910 | | -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) |
---|
| 12712 | +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS)) |
---|
7911 | 12713 | if ((err = wl_cfg80211_set_channel(wiphy, dev, |
---|
7912 | 12714 | dev->ieee80211_ptr->preset_chandef.chan, |
---|
7913 | | - dev->ieee80211_ptr->preset_chandef) < 0)) { |
---|
| 12715 | + NL80211_CHAN_HT20) < 0)) { |
---|
7914 | 12716 | WL_ERR(("Set channel failed \n")); |
---|
7915 | 12717 | goto fail; |
---|
7916 | 12718 | } |
---|
7917 | | -#endif |
---|
| 12719 | +#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */ |
---|
7918 | 12720 | |
---|
7919 | 12721 | if ((err = wl_cfg80211_bcn_set_params(info, dev, |
---|
7920 | 12722 | dev_role, bssidx)) < 0) { |
---|
.. | .. |
---|
7927 | 12729 | WL_ERR(("Set IEs failed \n")); |
---|
7928 | 12730 | goto fail; |
---|
7929 | 12731 | } |
---|
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); |
---|
7935 | 12736 | } |
---|
| 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 | + |
---|
7936 | 12751 | if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, |
---|
7937 | 12752 | dev_role, bssidx)) < 0) { |
---|
7938 | 12753 | WL_ERR(("Beacon bring up AP/GO failed \n")); |
---|
7939 | 12754 | goto fail; |
---|
7940 | 12755 | } |
---|
| 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 */ |
---|
7941 | 12763 | |
---|
| 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); |
---|
7942 | 12771 | WL_DBG(("** AP/GO Created **\n")); |
---|
| 12772 | + |
---|
7943 | 12773 | #ifdef WL_CFG80211_ACL |
---|
7944 | 12774 | /* Enfoce Admission Control. */ |
---|
7945 | 12775 | if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) { |
---|
7946 | 12776 | WL_ERR(("Set ACL failed\n")); |
---|
7947 | 12777 | } |
---|
7948 | 12778 | #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 */ |
---|
7949 | 12802 | |
---|
7950 | 12803 | /* Set IEs to FW */ |
---|
7951 | 12804 | if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0) |
---|
.. | .. |
---|
7954 | 12807 | /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ |
---|
7955 | 12808 | if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) { |
---|
7956 | 12809 | 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); |
---|
7958 | 12811 | if (pbc) { |
---|
7959 | 12812 | WL_DBG(("set WLC_E_PROBREQ_MSG\n")); |
---|
7960 | 12813 | wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); |
---|
7961 | 12814 | } |
---|
7962 | 12815 | } |
---|
7963 | 12816 | |
---|
| 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 | + |
---|
7964 | 12852 | fail: |
---|
7965 | 12853 | if (err) { |
---|
7966 | 12854 | 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); |
---|
7968 | 12857 | if (dev_role == NL80211_IFTYPE_AP) { |
---|
7969 | 12858 | 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 */ |
---|
7970 | 12876 | } |
---|
| 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 | + |
---|
7971 | 12884 | } |
---|
7972 | 12885 | |
---|
7973 | 12886 | return err; |
---|
.. | .. |
---|
7980 | 12893 | { |
---|
7981 | 12894 | int err = 0; |
---|
7982 | 12895 | u32 dev_role = 0; |
---|
7983 | | - int infra = 0; |
---|
7984 | 12896 | int ap = 0; |
---|
7985 | 12897 | s32 bssidx = 0; |
---|
7986 | 12898 | struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); |
---|
7987 | | - struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); |
---|
7988 | 12899 | s32 is_rsdb_supported = BCME_ERROR; |
---|
7989 | 12900 | dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); |
---|
7990 | 12901 | |
---|
7991 | 12902 | WL_DBG(("Enter \n")); |
---|
7992 | 12903 | |
---|
| 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 | + } |
---|
7993 | 12909 | is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE); |
---|
7994 | 12910 | if (is_rsdb_supported < 0) |
---|
7995 | 12911 | 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 | + |
---|
7996 | 12917 | if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) { |
---|
7997 | 12918 | dev_role = NL80211_IFTYPE_AP; |
---|
7998 | 12919 | 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 */ |
---|
7999 | 12929 | } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { |
---|
8000 | 12930 | dev_role = NL80211_IFTYPE_P2P_GO; |
---|
8001 | 12931 | 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 */ |
---|
8002 | 12941 | } else { |
---|
8003 | 12942 | WL_ERR(("no AP/P2P GO interface is operational.\n")); |
---|
8004 | 12943 | return -EINVAL; |
---|
.. | .. |
---|
8009 | 12948 | return BCME_ERROR; |
---|
8010 | 12949 | } |
---|
8011 | 12950 | |
---|
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)) { |
---|
8013 | 12952 | WL_ERR(("role integrity check failed \n")); |
---|
8014 | 12953 | err = -EINVAL; |
---|
8015 | 12954 | goto exit; |
---|
8016 | 12955 | } |
---|
8017 | 12956 | |
---|
| 12957 | + /* Free up resources */ |
---|
| 12958 | + wl_cfg80211_cleanup_if(dev); |
---|
| 12959 | + |
---|
8018 | 12960 | /* Clear AP/GO connected status */ |
---|
8019 | 12961 | 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) { |
---|
8022 | 12963 | WL_ERR(("bss down error %d\n", err)); |
---|
8023 | 12964 | } |
---|
8024 | 12965 | |
---|
8025 | 12966 | 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 */ |
---|
8050 | 12984 | |
---|
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; |
---|
8084 | 12991 | goto exit; |
---|
8085 | 12992 | } |
---|
8086 | 12993 | } |
---|
8087 | 12994 | |
---|
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 */ |
---|
8091 | 13000 | |
---|
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 */ |
---|
8093 | 13009 | } else { |
---|
8094 | 13010 | WL_DBG(("Stopping P2P GO \n")); |
---|
| 13011 | +#if defined(OEM_ANDROID) |
---|
8095 | 13012 | DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub), |
---|
8096 | 13013 | DHD_EVENT_TIMEOUT_MS*3); |
---|
8097 | 13014 | DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub)); |
---|
| 13015 | +#endif // endif |
---|
8098 | 13016 | } |
---|
8099 | 13017 | |
---|
| 13018 | + SUPP_LOG(("AP/GO Link down\n")); |
---|
8100 | 13019 | 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 */ |
---|
8101 | 13034 | |
---|
8102 | 13035 | if (dev_role == NL80211_IFTYPE_AP) { |
---|
8103 | 13036 | /* clear the AP mode */ |
---|
.. | .. |
---|
8118 | 13051 | u32 dev_role = 0; |
---|
8119 | 13052 | s32 bssidx = 0; |
---|
8120 | 13053 | 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 |
---|
8121 | 13059 | |
---|
8122 | 13060 | 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 */ |
---|
8134 | 13061 | |
---|
8135 | 13062 | if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { |
---|
8136 | 13063 | WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); |
---|
.. | .. |
---|
8139 | 13066 | |
---|
8140 | 13067 | if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { |
---|
8141 | 13068 | 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; |
---|
8142 | 13074 | } |
---|
8143 | 13075 | |
---|
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)) { |
---|
8145 | 13077 | err = -EINVAL; |
---|
8146 | 13078 | goto fail; |
---|
8147 | 13079 | } |
---|
.. | .. |
---|
8158 | 13090 | goto fail; |
---|
8159 | 13091 | } |
---|
8160 | 13092 | |
---|
| 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 | + |
---|
8161 | 13118 | /* Set IEs to FW */ |
---|
8162 | 13119 | if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) { |
---|
8163 | 13120 | WL_ERR(("Set IEs failed \n")); |
---|
.. | .. |
---|
8172 | 13129 | } |
---|
8173 | 13130 | /* Enable Probe Req filter, WPS-AP certification 4.2.13 */ |
---|
8174 | 13131 | 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); |
---|
8176 | 13133 | WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc)); |
---|
8177 | 13134 | if (pbc) |
---|
8178 | 13135 | wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); |
---|
.. | .. |
---|
8182 | 13139 | } |
---|
8183 | 13140 | |
---|
8184 | 13141 | fail: |
---|
| 13142 | + if (err) { |
---|
| 13143 | + wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL); |
---|
| 13144 | + } |
---|
8185 | 13145 | return err; |
---|
8186 | 13146 | } |
---|
8187 | 13147 | #else |
---|
.. | .. |
---|
8198 | 13158 | bcm_tlv_t *ssid_ie; |
---|
8199 | 13159 | bool pbc = 0; |
---|
8200 | 13160 | bool privacy; |
---|
| 13161 | + bool is_bss_up = 0; |
---|
8201 | 13162 | dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); |
---|
8202 | 13163 | |
---|
8203 | 13164 | WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", |
---|
.. | .. |
---|
8225 | 13186 | dhd->op_mode |= DHD_FLAG_HOSTAP_MODE; |
---|
8226 | 13187 | } |
---|
8227 | 13188 | |
---|
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)) { |
---|
8229 | 13190 | err = -ENODEV; |
---|
8230 | 13191 | goto fail; |
---|
8231 | 13192 | } |
---|
.. | .. |
---|
8243 | 13204 | DOT11_MNG_SSID_ID)) != NULL) { |
---|
8244 | 13205 | if (dev_role == NL80211_IFTYPE_AP) { |
---|
8245 | 13206 | /* 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); |
---|
8249 | 13211 | } else { |
---|
8250 | 13212 | /* 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); |
---|
8254 | 13217 | } |
---|
8255 | 13218 | } |
---|
8256 | 13219 | |
---|
.. | .. |
---|
8279 | 13242 | } else { |
---|
8280 | 13243 | WL_DBG(("Applied Vndr IEs for ProbeRsp \n")); |
---|
8281 | 13244 | } |
---|
8282 | | -#endif |
---|
| 13245 | +#endif // endif |
---|
| 13246 | + |
---|
| 13247 | + is_bss_up = wl_cfg80211_bss_isup(dev, bssidx); |
---|
8283 | 13248 | |
---|
8284 | 13249 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) |
---|
8285 | 13250 | privacy = info->privacy; |
---|
8286 | 13251 | #else |
---|
8287 | 13252 | privacy = 0; |
---|
8288 | | -#endif |
---|
8289 | | - if (!wl_cfgp2p_bss_isup(dev, bssidx) && |
---|
| 13253 | +#endif // endif |
---|
| 13254 | + if (!is_bss_up && |
---|
8290 | 13255 | (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx, privacy) < 0)) |
---|
8291 | 13256 | { |
---|
8292 | 13257 | WL_ERR(("Beacon set security failed \n")); |
---|
.. | .. |
---|
8296 | 13261 | |
---|
8297 | 13262 | /* Set BI and DTIM period */ |
---|
8298 | 13263 | 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) { |
---|
8301 | 13266 | WL_ERR(("Beacon Interval Set Error, %d\n", err)); |
---|
8302 | 13267 | return err; |
---|
8303 | 13268 | } |
---|
8304 | 13269 | } |
---|
8305 | 13270 | 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) { |
---|
8308 | 13273 | WL_ERR(("DTIM Interval Set Error, %d\n", err)); |
---|
8309 | 13274 | return err; |
---|
8310 | 13275 | } |
---|
8311 | 13276 | } |
---|
8312 | 13277 | |
---|
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 | + { |
---|
8314 | 13282 | 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")); |
---|
8315 | 13289 | goto fail; |
---|
8316 | 13290 | } |
---|
8317 | 13291 | |
---|
.. | .. |
---|
8333 | 13307 | } |
---|
8334 | 13308 | |
---|
8335 | 13309 | WL_DBG(("** ADD/SET beacon done **\n")); |
---|
| 13310 | + wl_set_drv_status(cfg, CONNECTED, dev); |
---|
8336 | 13311 | |
---|
8337 | 13312 | fail: |
---|
8338 | 13313 | if (err) { |
---|
8339 | 13314 | WL_ERR(("ADD/SET beacon failed\n")); |
---|
8340 | | - wldev_iovar_setint(dev, "mpc", 1); |
---|
8341 | 13315 | if (dev_role == NL80211_IFTYPE_AP) { |
---|
8342 | 13316 | /* clear the AP mode */ |
---|
8343 | 13317 | dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE; |
---|
.. | .. |
---|
8346 | 13320 | return err; |
---|
8347 | 13321 | |
---|
8348 | 13322 | } |
---|
8349 | | -#endif |
---|
8350 | 13323 | |
---|
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) |
---|
8357 | 13326 | { |
---|
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; |
---|
8381 | 13331 | 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); |
---|
8390 | 13333 | |
---|
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")); |
---|
8393 | 13338 | return -EINVAL; |
---|
8394 | 13339 | } |
---|
8395 | 13340 | |
---|
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)); |
---|
8407 | 13343 | } |
---|
8408 | 13344 | |
---|
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); |
---|
8410 | 13347 | |
---|
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; |
---|
8413 | 13356 | } |
---|
8414 | 13357 | |
---|
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)); |
---|
8445 | 13361 | } |
---|
8446 | 13362 | |
---|
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; |
---|
8456 | 13373 | } |
---|
8457 | 13374 | |
---|
8458 | 13375 | return 0; |
---|
8459 | 13376 | } |
---|
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 */ |
---|
8483 | 13378 | |
---|
8484 | 13379 | #ifdef WL_SUPPORT_ACS |
---|
8485 | 13380 | /* |
---|
.. | .. |
---|
8543 | 13438 | cca_stats_n_flags *results; |
---|
8544 | 13439 | char *buf; |
---|
8545 | 13440 | int retry, err; |
---|
| 13441 | + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); |
---|
8546 | 13442 | |
---|
8547 | | - buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL); |
---|
| 13443 | + buf = (char *)MALLOCZ(cfg->osh, sizeof(char) * WLC_IOCTL_MAXLEN); |
---|
8548 | 13444 | if (unlikely(!buf)) { |
---|
8549 | 13445 | WL_ERR(("%s: buf alloc failed\n", __func__)); |
---|
8550 | 13446 | return -ENOMEM; |
---|
.. | .. |
---|
8569 | 13465 | |
---|
8570 | 13466 | results = (cca_stats_n_flags *)(buf); |
---|
8571 | 13467 | wl_parse_dump_obss(results->buf, survey); |
---|
8572 | | - kfree(buf); |
---|
| 13468 | + MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN); |
---|
8573 | 13469 | |
---|
8574 | 13470 | return 0; |
---|
8575 | 13471 | exit: |
---|
8576 | | - kfree(buf); |
---|
| 13472 | + MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN); |
---|
8577 | 13473 | return err; |
---|
8578 | 13474 | } |
---|
8579 | 13475 | |
---|
.. | .. |
---|
8613 | 13509 | } |
---|
8614 | 13510 | |
---|
8615 | 13511 | 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 | | - |
---|
8625 | 13512 | /* Set interface up, explicitly. */ |
---|
8626 | 13513 | 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)); |
---|
8628 | 13515 | if (err < 0) { |
---|
8629 | 13516 | WL_ERR(("set interface up failed, error = %d\n", err)); |
---|
8630 | 13517 | } |
---|
.. | .. |
---|
8634 | 13521 | retry = IOCTL_RETRY_COUNT; |
---|
8635 | 13522 | while (retry--) { |
---|
8636 | 13523 | 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)); |
---|
8639 | 13526 | if (err >= 0) { |
---|
8640 | 13527 | break; |
---|
8641 | 13528 | } |
---|
.. | .. |
---|
8648 | 13535 | noise = CHAN_NOISE_DUMMY; |
---|
8649 | 13536 | } |
---|
8650 | 13537 | |
---|
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)); |
---|
8653 | 13540 | if (unlikely(!survey)) { |
---|
8654 | 13541 | WL_ERR(("%s: alloc failed\n", __func__)); |
---|
8655 | 13542 | return -ENOMEM; |
---|
.. | .. |
---|
8684 | 13571 | info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME | |
---|
8685 | 13572 | SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX | |
---|
8686 | 13573 | SURVEY_INFO_CHANNEL_TIME_TX; |
---|
8687 | | - kfree(survey); |
---|
| 13574 | + MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey)); |
---|
8688 | 13575 | |
---|
8689 | 13576 | return 0; |
---|
8690 | 13577 | exit: |
---|
8691 | | - kfree(survey); |
---|
| 13578 | + MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey)); |
---|
8692 | 13579 | return err; |
---|
8693 | 13580 | } |
---|
8694 | 13581 | #endif /* WL_SUPPORT_ACS */ |
---|
.. | .. |
---|
8702 | 13589 | .stop_p2p_device = wl_cfgp2p_stop_p2p_device, |
---|
8703 | 13590 | #endif /* WL_CFG80211_P2P_DEV_IF */ |
---|
8704 | 13591 | .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)) */ |
---|
8705 | 13595 | .set_wiphy_params = wl_cfg80211_set_wiphy_params, |
---|
8706 | 13596 | .join_ibss = wl_cfg80211_join_ibss, |
---|
8707 | 13597 | .leave_ibss = wl_cfg80211_leave_ibss, |
---|
.. | .. |
---|
8724 | 13614 | .remain_on_channel = wl_cfg80211_remain_on_channel, |
---|
8725 | 13615 | .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel, |
---|
8726 | 13616 | .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 |
---|
8727 | 13620 | .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, |
---|
| 13621 | +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) */ |
---|
8728 | 13622 | .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) |
---|
8730 | 13624 | .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) |
---|
8733 | 13627 | .set_beacon = wl_cfg80211_add_set_beacon, |
---|
8734 | 13628 | .add_beacon = wl_cfg80211_add_set_beacon, |
---|
| 13629 | + .del_beacon = wl_cfg80211_del_beacon, |
---|
8735 | 13630 | #else |
---|
8736 | 13631 | .change_beacon = wl_cfg80211_change_beacon, |
---|
8737 | 13632 | .start_ap = wl_cfg80211_start_ap, |
---|
8738 | 13633 | .stop_ap = wl_cfg80211_stop_ap, |
---|
8739 | | -#endif |
---|
| 13634 | +#endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */ |
---|
8740 | 13635 | #ifdef WL_SCHED_SCAN |
---|
8741 | 13636 | .sched_scan_start = wl_cfg80211_sched_scan_start, |
---|
8742 | 13637 | .sched_scan_stop = wl_cfg80211_sched_scan_stop, |
---|
.. | .. |
---|
8747 | 13642 | .change_station = wl_cfg80211_change_station, |
---|
8748 | 13643 | .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, |
---|
8749 | 13644 | #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) |
---|
8751 | 13646 | .tdls_mgmt = wl_cfg80211_tdls_mgmt, |
---|
8752 | 13647 | .tdls_oper = wl_cfg80211_tdls_oper, |
---|
8753 | | -#endif |
---|
| 13648 | +#endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */ |
---|
8754 | 13649 | #ifdef WL_SUPPORT_ACS |
---|
8755 | 13650 | .dump_survey = wl_cfg80211_dump_survey, |
---|
8756 | 13651 | #endif /* WL_SUPPORT_ACS */ |
---|
.. | .. |
---|
8761 | 13656 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) |
---|
8762 | 13657 | .set_rekey_data = wl_cfg80211_set_rekey_data, |
---|
8763 | 13658 | #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 */ |
---|
8765 | 13676 | }; |
---|
8766 | 13677 | |
---|
8767 | 13678 | s32 wl_mode_to_nl80211_iftype(s32 mode) |
---|
.. | .. |
---|
8782 | 13693 | return err; |
---|
8783 | 13694 | } |
---|
8784 | 13695 | |
---|
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) |
---|
8794 | 13699 | { |
---|
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 | + } |
---|
8806 | 13713 | } |
---|
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) { |
---|
8828 | 13718 | WL_ERR(("set country Failed :%d\n", ret)); |
---|
8829 | 13719 | } |
---|
8830 | | - |
---|
8831 | | -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) |
---|
8832 | 13720 | return ret; |
---|
8833 | | -#else |
---|
8834 | | - return; |
---|
8835 | | -#endif /* kernel version < 3.9.0 */ |
---|
8836 | 13721 | } |
---|
8837 | | -#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ |
---|
8838 | 13722 | |
---|
8839 | 13723 | #ifdef CONFIG_PM |
---|
8840 | 13724 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) |
---|
.. | .. |
---|
8850 | 13734 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */ |
---|
8851 | 13735 | #endif /* CONFIG_PM */ |
---|
8852 | 13736 | |
---|
| 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 */ |
---|
8853 | 13763 | static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context) |
---|
8854 | 13764 | { |
---|
8855 | 13765 | s32 err = 0; |
---|
.. | .. |
---|
8859 | 13769 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ |
---|
8860 | 13770 | #endif /* CONFIG_PM */ |
---|
8861 | 13771 | |
---|
8862 | | -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) |
---|
| 13772 | +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS)) |
---|
8863 | 13773 | dhd_pub_t *dhd = (dhd_pub_t *)context; |
---|
8864 | 13774 | BCM_REFERENCE(dhd); |
---|
8865 | 13775 | |
---|
.. | .. |
---|
8868 | 13778 | err = -ENODEV; |
---|
8869 | 13779 | return err; |
---|
8870 | 13780 | } |
---|
8871 | | -#endif |
---|
| 13781 | +#endif // endif |
---|
8872 | 13782 | |
---|
8873 | 13783 | wdev->wiphy = |
---|
8874 | 13784 | wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211)); |
---|
.. | .. |
---|
8886 | 13796 | wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; |
---|
8887 | 13797 | wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; |
---|
8888 | 13798 | wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; |
---|
| 13799 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) |
---|
8889 | 13800 | 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)) */ |
---|
8890 | 13804 | #endif /* WL_SCHED_SCAN */ |
---|
8891 | 13805 | wdev->wiphy->interface_modes = |
---|
8892 | 13806 | BIT(NL80211_IFTYPE_STATION) |
---|
.. | .. |
---|
8925 | 13839 | #endif /* !WL_POWERSAVE_DISABLED */ |
---|
8926 | 13840 | wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | |
---|
8927 | 13841 | 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) |
---|
8929 | 13843 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | |
---|
8930 | | -#endif |
---|
| 13844 | +#endif // endif |
---|
8931 | 13845 | 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)) |
---|
8934 | 13847 | /* |
---|
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. |
---|
8943 | 13853 | */ |
---|
8944 | | - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; |
---|
8945 | | -#endif |
---|
8946 | 13854 | |
---|
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) |
---|
8948 | 13861 | wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | |
---|
8949 | 13862 | WIPHY_FLAG_OFFCHAN_TX; |
---|
8950 | | -#endif |
---|
| 13863 | +#endif // endif |
---|
8951 | 13864 | #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ |
---|
8952 | 13865 | 4, 0)) |
---|
8953 | 13866 | /* From 3.4 kernel ownards AP_SME flag can be advertised |
---|
.. | .. |
---|
8958 | 13871 | #ifdef WL_CFG80211_ACL |
---|
8959 | 13872 | /* Configure ACL capabilities. */ |
---|
8960 | 13873 | wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT; |
---|
8961 | | -#endif |
---|
| 13874 | +#endif // endif |
---|
8962 | 13875 | |
---|
8963 | | -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) |
---|
| 13876 | +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS)) |
---|
8964 | 13877 | /* Supplicant distinguish between the SoftAP mode and other |
---|
8965 | 13878 | * modes (e.g. P2P, WPS, HS2.0) when it builds the probe |
---|
8966 | 13879 | * response frame from Supplicant MR1 and Kernel 3.4.0 or |
---|
.. | .. |
---|
8972 | 13885 | wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; |
---|
8973 | 13886 | wdev->wiphy->probe_resp_offload = 0; |
---|
8974 | 13887 | } |
---|
8975 | | -#endif |
---|
| 13888 | +#endif // endif |
---|
8976 | 13889 | #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */ |
---|
8977 | 13890 | |
---|
8978 | | -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) |
---|
| 13891 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS) |
---|
8979 | 13892 | wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; |
---|
8980 | | -#endif |
---|
| 13893 | +#endif // endif |
---|
8981 | 13894 | |
---|
8982 | 13895 | #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF) |
---|
8983 | 13896 | /* |
---|
.. | .. |
---|
8989 | 13902 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) |
---|
8990 | 13903 | wdev->wiphy->wowlan = &brcm_wowlan_support; |
---|
8991 | 13904 | /* 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 | + */ |
---|
8994 | 13909 | brcm_wowlan_config = kmalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL); |
---|
8995 | 13910 | if (brcm_wowlan_config) { |
---|
8996 | 13911 | brcm_wowlan_config->disconnect = true; |
---|
.. | .. |
---|
9002 | 13917 | brcm_wowlan_config->tcp = NULL; |
---|
9003 | 13918 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) |
---|
9004 | 13919 | brcm_wowlan_config->nd_config = NULL; |
---|
9005 | | -#endif |
---|
| 13920 | +#endif // endif |
---|
9006 | 13921 | } else { |
---|
9007 | 13922 | 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")); |
---|
9009 | 13924 | } |
---|
9010 | 13925 | wdev->wiphy->wowlan_config = brcm_wowlan_config; |
---|
9011 | 13926 | #else |
---|
.. | .. |
---|
9024 | 13939 | wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; |
---|
9025 | 13940 | #else |
---|
9026 | 13941 | wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; |
---|
9027 | | -#endif |
---|
| 13942 | +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0) */ |
---|
9028 | 13943 | 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")); |
---|
9031 | 13947 | err = wl_cfgvendor_attach(wdev->wiphy, dhd); |
---|
9032 | 13948 | if (unlikely(err < 0)) { |
---|
9033 | 13949 | WL_ERR(("Couldn not attach vendor commands (%d)\n", err)); |
---|
9034 | 13950 | } |
---|
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 | + |
---|
9036 | 13999 | /* Now we can register wiphy with cfg80211 module */ |
---|
9037 | 14000 | err = wiphy_register(wdev->wiphy); |
---|
9038 | 14001 | if (unlikely(err < 0)) { |
---|
9039 | 14002 | WL_ERR(("Couldn not register wiphy device (%d)\n", err)); |
---|
9040 | 14003 | wiphy_free(wdev->wiphy); |
---|
9041 | 14004 | } |
---|
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 |
---|
9047 | 14005 | |
---|
9048 | 14006 | return err; |
---|
9049 | 14007 | } |
---|
.. | .. |
---|
9059 | 14017 | if (wdev->wiphy) { |
---|
9060 | 14018 | wiphy = wdev->wiphy; |
---|
9061 | 14019 | |
---|
9062 | | -#if defined(WL_VENDOR_EXT_SUPPORT) |
---|
| 14020 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) |
---|
9063 | 14021 | 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) */ |
---|
9066 | 14023 | #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")); |
---|
9069 | 14026 | wdev->wiphy->wowlan = NULL; |
---|
9070 | | - if (wdev->wiphy->wowlan_config) { |
---|
9071 | | - kfree(wdev->wiphy->wowlan_config); |
---|
9072 | | - wdev->wiphy->wowlan_config = NULL; |
---|
9073 | | - } |
---|
9074 | 14027 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ |
---|
9075 | | -#endif /* CONFIG_PM */ |
---|
9076 | 14028 | wiphy_unregister(wdev->wiphy); |
---|
9077 | 14029 | wdev->wiphy->dev.parent = NULL; |
---|
9078 | 14030 | wdev->wiphy = NULL; |
---|
9079 | 14031 | } |
---|
9080 | 14032 | |
---|
9081 | 14033 | wl_delete_all_netinfo(cfg); |
---|
9082 | | - if (wiphy) |
---|
| 14034 | + if (wiphy) { |
---|
| 14035 | + MFREE(cfg->osh, wdev, sizeof(*wdev)); |
---|
9083 | 14036 | wiphy_free(wiphy); |
---|
| 14037 | + } |
---|
9084 | 14038 | |
---|
9085 | 14039 | /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg", |
---|
9086 | 14040 | * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! |
---|
9087 | 14041 | */ |
---|
9088 | 14042 | } |
---|
9089 | 14043 | |
---|
9090 | | -static s32 wl_inform_bss(struct bcm_cfg80211 *cfg) |
---|
| 14044 | +s32 wl_inform_bss(struct bcm_cfg80211 *cfg) |
---|
9091 | 14045 | { |
---|
9092 | 14046 | 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 */ |
---|
9094 | 14048 | s32 err = 0; |
---|
9095 | 14049 | s32 i; |
---|
9096 | 14050 | |
---|
9097 | 14051 | 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(); |
---|
9099 | 14057 | bi = next_bss(bss_list, bi); |
---|
9100 | 14058 | for_each_bss(bss_list, bi, i) { |
---|
| 14059 | +#ifdef ESCAN_CHANNEL_CACHE |
---|
| 14060 | + add_roam_cache(cfg, bi); |
---|
| 14061 | +#endif /* ESCAN_CHANNEL_CACHE */ |
---|
9101 | 14062 | 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 | + } |
---|
9104 | 14066 | } |
---|
| 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 */ |
---|
9105 | 14073 | return err; |
---|
9106 | 14074 | } |
---|
9107 | 14075 | |
---|
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) |
---|
9109 | 14077 | { |
---|
9110 | 14078 | struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); |
---|
9111 | 14079 | struct ieee80211_mgmt *mgmt; |
---|
.. | .. |
---|
9115 | 14083 | struct wl_scan_req *sr = wl_to_sr(cfg); |
---|
9116 | 14084 | struct beacon_proberesp *beacon_proberesp; |
---|
9117 | 14085 | 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; |
---|
9118 | 14094 | s32 mgmt_type; |
---|
9119 | 14095 | s32 signal; |
---|
9120 | 14096 | u32 freq; |
---|
9121 | 14097 | s32 err = 0; |
---|
9122 | 14098 | gfp_t aflags; |
---|
| 14099 | + u8 tmp_buf[IEEE80211_MAX_SSID_LEN + 1]; |
---|
9123 | 14100 | |
---|
9124 | 14101 | if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { |
---|
9125 | 14102 | WL_DBG(("Beacon is larger than buffer. Discarding\n")); |
---|
9126 | 14103 | return err; |
---|
9127 | 14104 | } |
---|
| 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 | + |
---|
9128 | 14111 | 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); |
---|
9131 | 14114 | if (unlikely(!notif_bss_info)) { |
---|
9132 | 14115 | WL_ERR(("notif_bss_info alloc failed\n")); |
---|
9133 | 14116 | return -ENOMEM; |
---|
.. | .. |
---|
9136 | 14119 | notif_bss_info->channel = |
---|
9137 | 14120 | wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); |
---|
9138 | 14121 | |
---|
| 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 */ |
---|
9139 | 14127 | if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) |
---|
9140 | 14128 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; |
---|
9141 | 14129 | else |
---|
9142 | 14130 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; |
---|
9143 | 14131 | if (!band) { |
---|
9144 | 14132 | 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); |
---|
9146 | 14135 | return -EINVAL; |
---|
9147 | 14136 | } |
---|
9148 | 14137 | notif_bss_info->rssi = wl_rssi_offset(dtoh16(bi->RSSI)); |
---|
.. | .. |
---|
9159 | 14148 | beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); |
---|
9160 | 14149 | beacon_proberesp->capab_info = cpu_to_le16(bi->capability); |
---|
9161 | 14150 | 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); |
---|
9163 | 14152 | wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length); |
---|
9164 | 14153 | wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX - |
---|
9165 | 14154 | offsetof(struct wl_cfg80211_bss_info, frame_buf)); |
---|
9166 | 14155 | notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, |
---|
9167 | 14156 | 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) |
---|
9169 | 14158 | freq = ieee80211_channel_to_frequency(notif_bss_info->channel); |
---|
9170 | 14159 | (void)band->band; |
---|
9171 | 14160 | #else |
---|
9172 | 14161 | freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); |
---|
9173 | | -#endif |
---|
| 14162 | +#endif // endif |
---|
9174 | 14163 | if (freq == 0) { |
---|
9175 | 14164 | 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); |
---|
9177 | 14167 | return -EINVAL; |
---|
9178 | 14168 | } |
---|
9179 | 14169 | channel = ieee80211_get_channel(wiphy, freq); |
---|
9180 | 14170 | if (unlikely(!channel)) { |
---|
9181 | 14171 | 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); |
---|
9183 | 14174 | return -EINVAL; |
---|
9184 | 14175 | } |
---|
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, |
---|
9188 | 14181 | mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type, |
---|
9189 | 14182 | notif_bss_info->frame_len)); |
---|
9190 | 14183 | |
---|
9191 | 14184 | 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 */ |
---|
9192 | 14191 | 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; |
---|
9197 | 14194 | #else |
---|
| 14195 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0)) |
---|
9198 | 14196 | struct timespec ts; |
---|
| 14197 | +#else |
---|
| 14198 | + struct timespec64 ts; |
---|
| 14199 | +#endif // endif |
---|
9199 | 14200 | get_monotonic_boottime(&ts); |
---|
9200 | | -#endif |
---|
9201 | 14201 | mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) |
---|
9202 | 14202 | + 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 */ |
---|
9209 | 14204 | } |
---|
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 |
---|
9212 | 14209 | cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, |
---|
9213 | 14210 | le16_to_cpu(notif_bss_info->frame_len), signal, aflags); |
---|
| 14211 | +#endif /* WL_SUPPORT_BSS_BOOTTIME */ |
---|
9214 | 14212 | 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; |
---|
9218 | 14217 | } |
---|
9219 | 14218 | |
---|
| 14219 | + CFG80211_PUT_BSS(wiphy, cbss); |
---|
9220 | 14220 | |
---|
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, ¬if_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, ¬if_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); |
---|
9227 | 14274 | return err; |
---|
9228 | 14275 | } |
---|
9229 | 14276 | |
---|
.. | .. |
---|
9232 | 14279 | u32 event = ntoh32(e->event_type); |
---|
9233 | 14280 | u32 status = ntoh32(e->status); |
---|
9234 | 14281 | 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 */ |
---|
9235 | 14286 | |
---|
9236 | 14287 | WL_DBG(("event %d, status %d flags %x\n", event, status, flags)); |
---|
9237 | 14288 | if (event == WLC_E_SET_SSID) { |
---|
9238 | 14289 | 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 */ |
---|
9239 | 14321 | if (!wl_is_ibssmode(cfg, ndev)) |
---|
9240 | 14322 | return true; |
---|
9241 | 14323 | } |
---|
.. | .. |
---|
9257 | 14339 | event == WLC_E_DISASSOC_IND || |
---|
9258 | 14340 | event == WLC_E_DISASSOC || |
---|
9259 | 14341 | 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))); |
---|
9263 | 14343 | return true; |
---|
9264 | 14344 | } else if (event == WLC_E_LINK) { |
---|
9265 | 14345 | 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))); |
---|
9269 | 14347 | return true; |
---|
9270 | 14348 | } |
---|
9271 | 14349 | } |
---|
.. | .. |
---|
9282 | 14360 | return true; |
---|
9283 | 14361 | if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) |
---|
9284 | 14362 | return true; |
---|
| 14363 | + if (event == WLC_E_ASSOC_RESP_IE && status != WLC_E_STATUS_SUCCESS) |
---|
| 14364 | + return true; |
---|
9285 | 14365 | |
---|
9286 | 14366 | return false; |
---|
9287 | 14367 | } |
---|
9288 | 14368 | |
---|
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 |
---|
9294 | 14370 | 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, |
---|
9296 | 14501 | const wl_event_msg_t *e, void *data) |
---|
9297 | 14502 | { |
---|
9298 | 14503 | s32 err = 0; |
---|
.. | .. |
---|
9300 | 14505 | u32 reason = ntoh32(e->reason); |
---|
9301 | 14506 | u32 len = ntoh32(e->datalen); |
---|
9302 | 14507 | |
---|
9303 | | -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) |
---|
9304 | 14508 | bool isfree = false; |
---|
9305 | 14509 | u8 *mgmt_frame; |
---|
9306 | 14510 | u8 bsscfgidx = e->bsscfgidx; |
---|
.. | .. |
---|
9314 | 14518 | struct ether_addr bssid; |
---|
9315 | 14519 | struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); |
---|
9316 | 14520 | channel_info_t ci; |
---|
9317 | | -#else |
---|
9318 | | - struct station_info sinfo; |
---|
9319 | | -#endif |
---|
9320 | 14521 | |
---|
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) |
---|
9337 | 14522 | WL_DBG(("Enter \n")); |
---|
9338 | 14523 | if (!len && (event == WLC_E_DEAUTH)) { |
---|
9339 | 14524 | len = 2; /* reason code field */ |
---|
.. | .. |
---|
9360 | 14545 | NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync); |
---|
9361 | 14546 | memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN); |
---|
9362 | 14547 | 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); |
---|
9364 | 14549 | switch (event) { |
---|
9365 | 14550 | case WLC_E_ASSOC_IND: |
---|
9366 | 14551 | fc = FC_ASSOC_REQ; |
---|
.. | .. |
---|
9382 | 14567 | goto exit; |
---|
9383 | 14568 | } |
---|
9384 | 14569 | 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)))) { |
---|
9386 | 14571 | kfree(body); |
---|
9387 | 14572 | return err; |
---|
9388 | 14573 | } |
---|
.. | .. |
---|
9398 | 14583 | kfree(body); |
---|
9399 | 14584 | return -EINVAL; |
---|
9400 | 14585 | } |
---|
9401 | | -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) |
---|
| 14586 | +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) |
---|
9402 | 14587 | freq = ieee80211_channel_to_frequency(channel); |
---|
9403 | 14588 | (void)band->band; |
---|
9404 | 14589 | #else |
---|
9405 | 14590 | 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, |
---|
9409 | 14593 | &mgmt_frame, &len, body); |
---|
9410 | 14594 | if (err < 0) |
---|
9411 | 14595 | goto exit; |
---|
9412 | 14596 | isfree = true; |
---|
9413 | 14597 | |
---|
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); |
---|
9424 | 14602 | } 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); |
---|
9430 | 14605 | } 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); |
---|
9436 | 14608 | } |
---|
9437 | 14609 | |
---|
9438 | | -exit: |
---|
| 14610 | + exit: |
---|
9439 | 14611 | if (isfree) |
---|
9440 | 14612 | kfree(mgmt_frame); |
---|
9441 | 14613 | if (body) |
---|
9442 | 14614 | 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); |
---|
9443 | 14692 | #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ |
---|
9444 | | - sinfo.filled = 0; |
---|
9445 | 14693 | 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; |
---|
9447 | 14702 | /* Linux ver >= 4.0 assoc_req_ies_len is used instead of |
---|
9448 | 14703 | * STATION_INFO_ASSOC_REQ_IES flag |
---|
9449 | 14704 | */ |
---|
.. | .. |
---|
9456 | 14711 | } |
---|
9457 | 14712 | sinfo.assoc_req_ies = data; |
---|
9458 | 14713 | sinfo.assoc_req_ies_len = len; |
---|
| 14714 | + WL_INFORM_MEM(("[%s] new sta event for "MACDBG "\n", |
---|
| 14715 | + ndev->name, MAC2STRDBG(e->addr.octet))); |
---|
9459 | 14716 | 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))); |
---|
9461 | 14728 | 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 */ |
---|
9464 | 14733 | } |
---|
9465 | | -#endif |
---|
| 14734 | +#endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ |
---|
9466 | 14735 | return err; |
---|
9467 | 14736 | } |
---|
9468 | 14737 | |
---|
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) |
---|
9472 | 14750 | { |
---|
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; |
---|
9484 | 14786 | } |
---|
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 | + |
---|
9487 | 14796 | return 0; |
---|
9488 | 14797 | } |
---|
| 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 */ |
---|
9489 | 14813 | |
---|
9490 | 14814 | static s32 |
---|
9491 | 14815 | wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev, |
---|
.. | .. |
---|
9504 | 14828 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */ |
---|
9505 | 14829 | |
---|
9506 | 14830 | 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)); |
---|
9508 | 14832 | } |
---|
9509 | 14833 | if (event == WLC_E_START) { |
---|
9510 | | - WL_DBG(("started IBSS network\n")); |
---|
| 14834 | + WL_INFORM_MEM(("[%s] started IBSS network\n", ndev->name)); |
---|
9511 | 14835 | } |
---|
9512 | 14836 | if (event == WLC_E_JOIN || event == WLC_E_START || |
---|
9513 | 14837 | (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) { |
---|
.. | .. |
---|
9530 | 14854 | MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid))); |
---|
9531 | 14855 | return err; |
---|
9532 | 14856 | } |
---|
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))); |
---|
9535 | 14860 | wl_get_assoc_ies(cfg, ndev); |
---|
9536 | 14861 | wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID); |
---|
9537 | 14862 | wl_update_bss_info(cfg, ndev, false); |
---|
.. | .. |
---|
9539 | 14864 | cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL); |
---|
9540 | 14865 | #else |
---|
9541 | 14866 | cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL); |
---|
9542 | | -#endif |
---|
| 14867 | +#endif // endif |
---|
9543 | 14868 | } |
---|
9544 | 14869 | else { |
---|
9545 | 14870 | /* 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))); |
---|
9548 | 14873 | wl_link_up(cfg); |
---|
9549 | 14874 | wl_get_assoc_ies(cfg, ndev); |
---|
9550 | 14875 | wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID); |
---|
.. | .. |
---|
9553 | 14878 | cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL); |
---|
9554 | 14879 | #else |
---|
9555 | 14880 | cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL); |
---|
9556 | | -#endif |
---|
| 14881 | +#endif // endif |
---|
9557 | 14882 | wl_set_drv_status(cfg, CONNECTED, ndev); |
---|
9558 | 14883 | active = true; |
---|
9559 | 14884 | wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT); |
---|
.. | .. |
---|
9565 | 14890 | wl_init_prof(cfg, ndev); |
---|
9566 | 14891 | } |
---|
9567 | 14892 | 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")); |
---|
9569 | 14894 | } |
---|
9570 | 14895 | else { |
---|
9571 | 14896 | WL_DBG(("no action (IBSS mode)\n")); |
---|
9572 | 14897 | } |
---|
9573 | 14898 | 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 | + } |
---|
9574 | 15393 | } |
---|
9575 | 15394 | |
---|
9576 | 15395 | static s32 |
---|
.. | .. |
---|
9581 | 15400 | struct net_device *ndev = NULL; |
---|
9582 | 15401 | s32 err = 0; |
---|
9583 | 15402 | u32 event = ntoh32(e->event_type); |
---|
| 15403 | + u32 datalen = ntoh32(e->datalen); |
---|
9584 | 15404 | struct wiphy *wiphy = NULL; |
---|
9585 | 15405 | struct cfg80211_bss *bss = NULL; |
---|
9586 | 15406 | struct wlc_ssid *ssid = NULL; |
---|
9587 | 15407 | 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 */ |
---|
9588 | 15425 | |
---|
9589 | 15426 | 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); |
---|
9590 | 15432 | |
---|
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) { |
---|
9592 | 15439 | 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) { |
---|
9594 | 15441 | 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 | + |
---|
9598 | 15457 | 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); |
---|
9600 | 15459 | return 0; |
---|
9601 | 15460 | } |
---|
| 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 |
---|
9602 | 15471 | if (wl_is_linkup(cfg, e, ndev)) { |
---|
9603 | 15472 | wl_link_up(cfg); |
---|
9604 | 15473 | act = true; |
---|
9605 | 15474 | 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 | + } |
---|
9609 | 15486 | |
---|
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 && |
---|
9616 | 15501 | #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; |
---|
9620 | 15506 | } |
---|
| 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); |
---|
9621 | 15519 | #endif /* DHD_LOSSLESS_ROAMING */ |
---|
9622 | 15520 | |
---|
| 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 | + } |
---|
9623 | 15530 | } |
---|
| 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 | + } |
---|
9624 | 15543 | wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); |
---|
9625 | 15544 | wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID); |
---|
9626 | | - |
---|
| 15545 | +#if defined(IGUANA_LEGACY_CHIPS) |
---|
9627 | 15546 | } 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 | + } |
---|
9628 | 15616 | #ifdef DHD_LOSSLESS_ROAMING |
---|
9629 | 15617 | wl_del_roam_timeout(cfg); |
---|
9630 | | -#endif |
---|
| 15618 | +#endif // endif |
---|
9631 | 15619 | #ifdef P2PLISTEN_AP_SAMECHN |
---|
9632 | 15620 | if (ndev == bcmcfg_to_prmry_ndev(cfg)) { |
---|
9633 | 15621 | wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0); |
---|
.. | .. |
---|
9637 | 15625 | #endif /* P2PLISTEN_AP_SAMECHN */ |
---|
9638 | 15626 | wl_cfg80211_cancel_scan(cfg); |
---|
9639 | 15627 | |
---|
| 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 */ |
---|
9640 | 15633 | /* 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); |
---|
9652 | 15643 | } |
---|
9653 | 15644 | } |
---|
9654 | 15645 | |
---|
9655 | 15646 | if (wl_get_drv_status(cfg, CONNECTED, ndev)) { |
---|
9656 | 15647 | scb_val_t scbval; |
---|
9657 | 15648 | 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}}; |
---|
9660 | 15652 | |
---|
9661 | | - if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) |
---|
| 15653 | + if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) { |
---|
9662 | 15654 | 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 */ |
---|
9670 | 15668 | |
---|
9671 | 15669 | /* roam offload does not sync BSSID always, get it from dongle */ |
---|
9672 | 15670 | 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 | + } |
---|
9677 | 15679 | } |
---|
9678 | 15680 | } |
---|
9679 | 15681 | 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 | + } |
---|
9685 | 15698 | } |
---|
| 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 */ |
---|
9686 | 15710 | 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); |
---|
9688 | 15716 | /* To make sure disconnect, explictly send dissassoc |
---|
9689 | 15717 | * for BSSID 00:00:00:00:00:00 issue |
---|
9690 | 15718 | */ |
---|
9691 | 15719 | scbval.val = WLAN_REASON_DEAUTH_LEAVING; |
---|
9692 | | - |
---|
| 15720 | + WL_INFORM_MEM(("clear fw state\n")); |
---|
9693 | 15721 | memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); |
---|
9694 | 15722 | 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)); |
---|
9697 | 15725 | if (err < 0) { |
---|
9698 | 15726 | WL_ERR(("WLC_DISASSOC error %d\n", err)); |
---|
9699 | 15727 | err = 0; |
---|
9700 | 15728 | } |
---|
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); |
---|
9706 | 15729 | } |
---|
| 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); |
---|
9707 | 15833 | } |
---|
9708 | 15834 | 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 | + } |
---|
9710 | 15853 | #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 | + */ |
---|
9715 | 15863 | #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 | + } |
---|
9717 | 15866 | } |
---|
9718 | 15867 | wl_clr_drv_status(cfg, DISCONNECTING, ndev); |
---|
9719 | 15868 | |
---|
9720 | 15869 | /* if link down, bsscfg is diabled */ |
---|
9721 | 15870 | if (ndev != bcmcfg_to_prmry_ndev(cfg)) |
---|
9722 | 15871 | 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 */ |
---|
9724 | 15881 | } 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 | + |
---|
9727 | 15899 | /* Clean up any pending scan request */ |
---|
9728 | 15900 | 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 | + } |
---|
9730 | 15914 | 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 | + } |
---|
9731 | 15918 | } else { |
---|
9732 | | - WL_DBG(("%s nothing\n", __FUNCTION__)); |
---|
| 15919 | + WL_DBG(("wl_notify_connect_status nothing\n")); |
---|
9733 | 15920 | } |
---|
9734 | | - } |
---|
9735 | | - else { |
---|
| 15921 | +#if defined(OEM_ANDROID) |
---|
| 15922 | + DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub); |
---|
| 15923 | +#endif // endif |
---|
| 15924 | + } else { |
---|
9736 | 15925 | WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev))); |
---|
9737 | 15926 | } |
---|
9738 | 15927 | return err; |
---|
9739 | 15928 | } |
---|
9740 | 15929 | |
---|
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) |
---|
9742 | 15932 | { |
---|
9743 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 15933 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
9744 | 15934 | if (pid > 0) |
---|
9745 | 15935 | cfg->rmc_event_pid = pid; |
---|
9746 | 15936 | WL_DBG(("set pid for rmc event : pid=%d\n", pid)); |
---|
9747 | 15937 | } |
---|
| 15938 | +#endif /* WL_RELMCAST */ |
---|
9748 | 15939 | |
---|
| 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 */ |
---|
9749 | 15984 | #ifdef WL_RELMCAST |
---|
9750 | 15985 | static s32 |
---|
9751 | 15986 | wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, |
---|
.. | .. |
---|
9804 | 16039 | } |
---|
9805 | 16040 | #endif /* GSCAN_SUPPORT */ |
---|
9806 | 16041 | |
---|
| 16042 | +#ifdef RSSI_MONITOR_SUPPORT |
---|
9807 | 16043 | static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, |
---|
9808 | 16044 | const wl_event_msg_t *e, void *data) |
---|
9809 | 16045 | { |
---|
.. | .. |
---|
9812 | 16048 | u32 datalen = be32_to_cpu(e->datalen); |
---|
9813 | 16049 | struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); |
---|
9814 | 16050 | struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); |
---|
| 16051 | + |
---|
9815 | 16052 | if (datalen) { |
---|
9816 | 16053 | wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data; |
---|
9817 | 16054 | if (evt_data->version == RSSI_MONITOR_VERSION) { |
---|
.. | .. |
---|
9830 | 16067 | #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */ |
---|
9831 | 16068 | return BCME_OK; |
---|
9832 | 16069 | } |
---|
| 16070 | +#endif /* RSSI_MONITOR_SUPPORT */ |
---|
9833 | 16071 | |
---|
9834 | 16072 | static s32 |
---|
9835 | 16073 | wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, |
---|
.. | .. |
---|
9842 | 16080 | u32 status = be32_to_cpu(e->status); |
---|
9843 | 16081 | #ifdef DHD_LOSSLESS_ROAMING |
---|
9844 | 16082 | 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 */ |
---|
9846 | 16087 | WL_DBG(("Enter \n")); |
---|
9847 | 16088 | |
---|
9848 | 16089 | ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); |
---|
.. | .. |
---|
9857 | 16098 | |
---|
9858 | 16099 | if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) { |
---|
9859 | 16100 | 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 | | - } |
---|
9865 | 16101 | #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)) { |
---|
9867 | 16109 | 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)) { |
---|
9868 | 16117 | wl_del_roam_timeout(cfg); |
---|
9869 | 16118 | } |
---|
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 |
---|
9884 | 16135 | */ |
---|
9885 | 16136 | 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); |
---|
9887 | 16141 | } |
---|
9888 | 16142 | } |
---|
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 */ |
---|
9893 | 16144 | } else { |
---|
9894 | 16145 | wl_bss_connect_done(cfg, ndev, e, data, true); |
---|
9895 | 16146 | } |
---|
9896 | 16147 | act = true; |
---|
9897 | 16148 | wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); |
---|
9898 | 16149 | 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 | + } |
---|
9899 | 16154 | } |
---|
9900 | 16155 | #ifdef DHD_LOSSLESS_ROAMING |
---|
9901 | 16156 | else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) { |
---|
9902 | 16157 | wl_del_roam_timeout(cfg); |
---|
9903 | 16158 | } |
---|
9904 | | -#endif |
---|
| 16159 | +#endif // endif |
---|
9905 | 16160 | return err; |
---|
9906 | 16161 | } |
---|
| 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 */ |
---|
9907 | 16261 | |
---|
9908 | 16262 | #ifdef QOS_MAP_SET |
---|
9909 | 16263 | /* get user priority table */ |
---|
9910 | 16264 | uint8 * |
---|
9911 | | -wl_get_up_table(void) |
---|
| 16265 | +wl_get_up_table(dhd_pub_t * dhdp, int idx) |
---|
9912 | 16266 | { |
---|
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; |
---|
9914 | 16278 | } |
---|
9915 | 16279 | #endif /* QOS_MAP_SET */ |
---|
9916 | 16280 | |
---|
9917 | | -#ifdef DHD_LOSSLESS_ROAMING |
---|
| 16281 | +#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON) |
---|
9918 | 16282 | static s32 |
---|
9919 | 16283 | wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, |
---|
9920 | 16284 | const wl_event_msg_t *e, void *data) |
---|
9921 | 16285 | { |
---|
9922 | | - s32 err = 0; |
---|
9923 | | - |
---|
| 16286 | + struct wl_security *sec; |
---|
| 16287 | + struct net_device *ndev; |
---|
9924 | 16288 | 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 | + } |
---|
9925 | 16322 | |
---|
9926 | 16323 | dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC; |
---|
9927 | 16324 | /* Restore flow control */ |
---|
9928 | 16325 | dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF); |
---|
9929 | 16326 | |
---|
9930 | 16327 | mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS)); |
---|
9931 | | - |
---|
9932 | | - return err; |
---|
9933 | | -} |
---|
9934 | 16328 | #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 */ |
---|
9935 | 16394 | |
---|
9936 | 16395 | static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) |
---|
9937 | 16396 | { |
---|
.. | .. |
---|
9961 | 16420 | conn_info->resp_ie_len = 0; |
---|
9962 | 16421 | bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); |
---|
9963 | 16422 | } |
---|
| 16423 | + |
---|
9964 | 16424 | if (assoc_info.req_len) { |
---|
9965 | 16425 | 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); |
---|
9967 | 16427 | if (unlikely(err)) { |
---|
9968 | 16428 | WL_ERR(("could not get assoc req (%d)\n", err)); |
---|
9969 | 16429 | return err; |
---|
9970 | 16430 | } |
---|
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)); |
---|
9972 | 16438 | if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { |
---|
9973 | 16439 | conn_info->req_ie_len -= ETHER_ADDR_LEN; |
---|
9974 | 16440 | } |
---|
.. | .. |
---|
9982 | 16448 | } else { |
---|
9983 | 16449 | conn_info->req_ie_len = 0; |
---|
9984 | 16450 | } |
---|
| 16451 | + |
---|
9985 | 16452 | if (assoc_info.resp_len) { |
---|
9986 | 16453 | 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); |
---|
9988 | 16455 | if (unlikely(err)) { |
---|
9989 | 16456 | WL_ERR(("could not get assoc resp (%d)\n", err)); |
---|
9990 | 16457 | return err; |
---|
9991 | 16458 | } |
---|
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); |
---|
9993 | 16466 | if (conn_info->resp_ie_len <= MAX_REQ_LINE) { |
---|
9994 | 16467 | memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len); |
---|
9995 | 16468 | } else { |
---|
.. | .. |
---|
10004 | 16477 | DOT11_MNG_QOS_MAP_ID)) != NULL) { |
---|
10005 | 16478 | WL_DBG((" QoS map set IE found in assoc response\n")); |
---|
10006 | 16479 | 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); |
---|
10008 | 16481 | } |
---|
10009 | 16482 | wl_set_up_table(cfg->up_table, qos_map_ie); |
---|
10010 | 16483 | } else { |
---|
10011 | | - kfree(cfg->up_table); |
---|
10012 | | - cfg->up_table = NULL; |
---|
| 16484 | + MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX); |
---|
10013 | 16485 | } |
---|
10014 | 16486 | #endif /* QOS_MAP_SET */ |
---|
10015 | 16487 | } else { |
---|
.. | .. |
---|
10017 | 16489 | } |
---|
10018 | 16490 | WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, |
---|
10019 | 16491 | conn_info->resp_ie_len)); |
---|
10020 | | - |
---|
| 16492 | +#ifdef REVERSE_AIFSN |
---|
| 16493 | + DHD_REVERSE_AIFSN(cfg->pub, ndev); |
---|
| 16494 | +#endif /* REVERSE_AIFSN */ |
---|
10021 | 16495 | return err; |
---|
10022 | 16496 | } |
---|
10023 | 16497 | |
---|
10024 | 16498 | 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) |
---|
10026 | 16500 | { |
---|
10027 | | - struct bcm_cfg80211 *cfg; |
---|
10028 | | - s32 bssidx = -1; |
---|
10029 | 16501 | chanspec_t chanspec = 0, chspec; |
---|
| 16502 | + struct bcm_cfg80211 *cfg = |
---|
| 16503 | + (struct bcm_cfg80211 *)wiphy_priv(dev->ieee80211_ptr->wiphy); |
---|
10030 | 16504 | |
---|
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; |
---|
10035 | 16508 | |
---|
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; |
---|
10040 | 16518 | |
---|
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; |
---|
10049 | 16527 | |
---|
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); |
---|
10052 | 16530 | |
---|
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]); |
---|
10057 | 16535 | |
---|
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); |
---|
10064 | 16538 | } |
---|
| 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)); |
---|
10065 | 16556 | return 0; |
---|
10066 | 16557 | } |
---|
10067 | 16558 | |
---|
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) |
---|
10069 | 16561 | { |
---|
10070 | | - struct wl_bss_info *bi; |
---|
| 16562 | + struct cfg80211_bss *bss; |
---|
| 16563 | + wl_bss_info_t *bi; |
---|
10071 | 16564 | struct wlc_ssid *ssid; |
---|
10072 | | - struct bcm_tlv *tim; |
---|
| 16565 | + const struct bcm_tlv *tim; |
---|
10073 | 16566 | s32 beacon_interval; |
---|
10074 | 16567 | s32 dtim_period; |
---|
10075 | 16568 | size_t ie_len; |
---|
10076 | | - u8 *ie; |
---|
| 16569 | + const u8 *ie; |
---|
10077 | 16570 | u8 *curbssid; |
---|
10078 | 16571 | s32 err = 0; |
---|
10079 | 16572 | struct wiphy *wiphy; |
---|
10080 | 16573 | u32 channel; |
---|
10081 | 16574 | char *buf; |
---|
| 16575 | + u32 freq, band; |
---|
10082 | 16576 | |
---|
10083 | 16577 | wiphy = bcmcfg_to_wiphy(cfg); |
---|
10084 | 16578 | |
---|
10085 | 16579 | ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID); |
---|
10086 | 16580 | 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); |
---|
10091 | 16584 | if (!buf) { |
---|
10092 | 16585 | WL_ERR(("buffer alloc failed.\n")); |
---|
10093 | 16586 | return BCME_NOMEM; |
---|
10094 | 16587 | } |
---|
| 16588 | + mutex_lock(&cfg->usr_sync); |
---|
10095 | 16589 | *(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); |
---|
10098 | 16591 | if (unlikely(err)) { |
---|
10099 | 16592 | WL_ERR(("Could not get bss info %d\n", err)); |
---|
10100 | 16593 | goto update_bss_info_out; |
---|
10101 | 16594 | } |
---|
10102 | | - bi = (struct wl_bss_info *)(buf + 4); |
---|
| 16595 | + bi = (wl_bss_info_t *)(buf + 4); |
---|
10103 | 16596 | channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); |
---|
10104 | 16597 | wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN); |
---|
10105 | 16598 | |
---|
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; |
---|
10114 | 16609 | |
---|
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 | + |
---|
10118 | 16639 | tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM); |
---|
10119 | 16640 | if (tim) { |
---|
10120 | 16641 | dtim_period = tim->data[1]; |
---|
.. | .. |
---|
10125 | 16646 | * so we speficially query dtim information. |
---|
10126 | 16647 | */ |
---|
10127 | 16648 | 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)); |
---|
10130 | 16651 | if (unlikely(err)) { |
---|
10131 | 16652 | WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); |
---|
10132 | 16653 | goto update_bss_info_out; |
---|
.. | .. |
---|
10141 | 16662 | WL_ERR(("Failed with error %d\n", err)); |
---|
10142 | 16663 | } |
---|
10143 | 16664 | |
---|
10144 | | - kfree(buf); |
---|
| 16665 | + MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX); |
---|
10145 | 16666 | mutex_unlock(&cfg->usr_sync); |
---|
10146 | 16667 | return err; |
---|
10147 | 16668 | } |
---|
.. | .. |
---|
10153 | 16674 | struct wl_connect_info *conn_info = wl_to_conn(cfg); |
---|
10154 | 16675 | s32 err = 0; |
---|
10155 | 16676 | 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) |
---|
10157 | 16680 | struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); |
---|
10158 | 16681 | struct ieee80211_supported_band *band; |
---|
10159 | 16682 | struct ieee80211_channel *notify_channel = NULL; |
---|
10160 | | - u32 *channel; |
---|
10161 | 16683 | 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) |
---|
10164 | 16692 | 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 */ |
---|
10168 | 16702 | #ifdef WLFBT |
---|
10169 | 16703 | uint32 data_len = 0; |
---|
10170 | 16704 | if (data) |
---|
10171 | 16705 | data_len = ntoh32(e->datalen); |
---|
10172 | 16706 | #endif /* WLFBT */ |
---|
10173 | 16707 | |
---|
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 | + |
---|
10175 | 16755 | wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID); |
---|
10176 | 16756 | 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 | + } |
---|
10178 | 16761 | wl_update_pmklist(ndev, cfg->pmk_list, err); |
---|
10179 | 16762 | |
---|
10180 | | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) |
---|
10181 | | - /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */ |
---|
10182 | 16763 | 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 */ |
---|
10183 | 16766 | if (*channel <= CH_MAX_2G_CHANNEL) |
---|
10184 | 16767 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; |
---|
10185 | 16768 | else |
---|
10186 | 16769 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; |
---|
10187 | 16770 | freq = ieee80211_channel_to_frequency(*channel, band->band); |
---|
10188 | 16771 | notify_channel = ieee80211_get_channel(wiphy, freq); |
---|
10189 | | -#endif |
---|
| 16772 | +#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */ |
---|
10190 | 16773 | #ifdef WLFBT |
---|
10191 | 16774 | /* back up the given FBT key for the further supplicant request, |
---|
10192 | 16775 | * currently not checking the FBT is enabled for current BSS in DHD, |
---|
.. | .. |
---|
10196 | 16779 | memcpy(cfg->fbt_key, data, FBT_KEYLEN); |
---|
10197 | 16780 | } |
---|
10198 | 16781 | #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)); |
---|
10201 | 16791 | |
---|
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)); |
---|
10205 | 16796 | roam_info.channel = notify_channel; |
---|
10206 | 16797 | roam_info.bssid = curbssid; |
---|
10207 | 16798 | roam_info.req_ie = conn_info->req_ie; |
---|
10208 | 16799 | roam_info.req_ie_len = conn_info->req_ie_len; |
---|
10209 | 16800 | roam_info.resp_ie = conn_info->resp_ie; |
---|
10210 | 16801 | 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 |
---|
10212 | 16813 | cfg80211_roamed(ndev, &roam_info, GFP_KERNEL); |
---|
10213 | 16814 | #else |
---|
10214 | 16815 | 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) |
---|
10216 | 16817 | notify_channel, |
---|
10217 | | -#endif |
---|
| 16818 | +#endif // endif |
---|
10218 | 16819 | curbssid, |
---|
10219 | 16820 | conn_info->req_ie, conn_info->req_ie_len, |
---|
10220 | 16821 | 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 */ |
---|
10223 | 16823 | |
---|
| 16824 | + memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN); |
---|
10224 | 16825 | wl_set_drv_status(cfg, CONNECTED, ndev); |
---|
10225 | 16826 | |
---|
| 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 */ |
---|
10226 | 16854 | return err; |
---|
10227 | 16855 | } |
---|
10228 | 16856 | |
---|
| 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 */ |
---|
10229 | 16984 | static s32 |
---|
10230 | 16985 | wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, |
---|
10231 | 16986 | const wl_event_msg_t *e, void *data, bool completed) |
---|
10232 | 16987 | { |
---|
10233 | 16988 | struct wl_connect_info *conn_info = wl_to_conn(cfg); |
---|
10234 | 16989 | 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 |
---|
10238 | 16990 | 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 */ |
---|
10239 | 16998 | 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 | + |
---|
10240 | 17005 | if (!sec) { |
---|
10241 | 17006 | WL_ERR(("sec is NULL\n")); |
---|
10242 | 17007 | return -ENODEV; |
---|
.. | .. |
---|
10245 | 17010 | #ifdef ESCAN_RESULT_PATCH |
---|
10246 | 17011 | if (wl_get_drv_status(cfg, CONNECTED, ndev)) { |
---|
10247 | 17012 | 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", |
---|
10249 | 17015 | ntoh32(e->event_type), ntoh32(e->status))); |
---|
10250 | 17016 | return err; |
---|
10251 | 17017 | } |
---|
.. | .. |
---|
10255 | 17021 | WL_DBG(("copy bssid\n")); |
---|
10256 | 17022 | memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); |
---|
10257 | 17023 | } |
---|
10258 | | - |
---|
10259 | 17024 | #else |
---|
10260 | 17025 | if (cfg->scan_request) { |
---|
10261 | | - wl_notify_escan_complete(cfg, ndev, true, true); |
---|
| 17026 | + wl_cfg80211_cancel_scan(cfg); |
---|
10262 | 17027 | } |
---|
10263 | 17028 | #endif /* ESCAN_RESULT_PATCH */ |
---|
10264 | 17029 | if (wl_get_drv_status(cfg, CONNECTING, ndev)) { |
---|
10265 | 17030 | wl_cfg80211_scan_abort(cfg); |
---|
10266 | | - wl_clr_drv_status(cfg, CONNECTING, ndev); |
---|
10267 | 17031 | if (completed) { |
---|
10268 | 17032 | wl_get_assoc_ies(cfg, ndev); |
---|
10269 | 17033 | wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), |
---|
10270 | 17034 | WL_PROF_BSSID); |
---|
10271 | 17035 | 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); |
---|
10273 | 17042 | wl_update_pmklist(ndev, cfg->pmk_list, err); |
---|
10274 | 17043 | 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 */ |
---|
10275 | 17049 | if (ndev != bcmcfg_to_prmry_ndev(cfg)) { |
---|
10276 | 17050 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) |
---|
10277 | 17051 | init_completion(&cfg->iface_disable); |
---|
10278 | 17052 | #else |
---|
10279 | 17053 | /* reinitialize completion to clear previous count */ |
---|
10280 | 17054 | INIT_COMPLETION(cfg->iface_disable); |
---|
10281 | | -#endif |
---|
| 17055 | +#endif // endif |
---|
10282 | 17056 | } |
---|
10283 | 17057 | #ifdef CUSTOM_SET_CPUCORE |
---|
10284 | | - if (wl_get_chan_isvht80(ndev, dhd)) { |
---|
| 17058 | + if (wl_get_chan_isvht80(ndev, dhdp)) { |
---|
10285 | 17059 | 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 */ |
---|
10287 | 17061 | 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); |
---|
10290 | 17064 | } |
---|
10291 | 17065 | #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); |
---|
10293 | 17072 | } |
---|
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 | + } |
---|
10307 | 17120 | 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))); |
---|
10309 | 17153 | } |
---|
10310 | 17154 | #ifdef CONFIG_TCPACK_FASTTX |
---|
10311 | | - if (wl_get_chan_isvht80(ndev, dhd)) |
---|
| 17155 | + if (wl_get_chan_isvht80(ndev, dhdp)) |
---|
10312 | 17156 | wldev_iovar_setint(ndev, "tcpack_fast_tx", 0); |
---|
10313 | 17157 | else |
---|
10314 | 17158 | wldev_iovar_setint(ndev, "tcpack_fast_tx", 1); |
---|
.. | .. |
---|
10327 | 17171 | |
---|
10328 | 17172 | ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); |
---|
10329 | 17173 | |
---|
| 17174 | + WL_INFORM_MEM(("[%s] mic fail event - " MACDBG " \n", |
---|
| 17175 | + ndev->name, MAC2STRDBG(e->addr.octet))); |
---|
10330 | 17176 | mutex_lock(&cfg->usr_sync); |
---|
10331 | 17177 | if (flags & WLC_EVENT_MSG_GROUP) |
---|
10332 | 17178 | key_type = NL80211_KEYTYPE_GROUP; |
---|
10333 | 17179 | else |
---|
10334 | 17180 | key_type = NL80211_KEYTYPE_PAIRWISE; |
---|
10335 | 17181 | |
---|
| 17182 | + wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL); |
---|
10336 | 17183 | cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1, |
---|
10337 | 17184 | NULL, GFP_KERNEL); |
---|
10338 | 17185 | mutex_unlock(&cfg->usr_sync); |
---|
.. | .. |
---|
10358 | 17205 | } |
---|
10359 | 17206 | #endif /* BT_WIFI_HANDOVER */ |
---|
10360 | 17207 | |
---|
10361 | | -#ifdef PNO_SUPPORT |
---|
10362 | 17208 | 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) |
---|
10566 | 17212 | { |
---|
10567 | 17213 | struct dot11_management_header *hdr; |
---|
10568 | 17214 | u32 totlen = 0; |
---|
.. | .. |
---|
10583 | 17229 | break; |
---|
10584 | 17230 | } |
---|
10585 | 17231 | totlen += DOT11_MGMT_HDR_LEN + prebody_len; |
---|
10586 | | - *pheader = kzalloc(totlen, GFP_KERNEL); |
---|
| 17232 | + *pheader = (u8 *)MALLOCZ(cfg->osh, totlen); |
---|
10587 | 17233 | if (*pheader == NULL) { |
---|
10588 | 17234 | WL_ERR(("memory alloc failed \n")); |
---|
10589 | 17235 | return -ENOMEM; |
---|
.. | .. |
---|
10602 | 17248 | return err; |
---|
10603 | 17249 | } |
---|
10604 | 17250 | |
---|
| 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 */ |
---|
10605 | 17301 | |
---|
10606 | 17302 | 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) |
---|
10608 | 17304 | { |
---|
| 17305 | + s32 err = 0; |
---|
| 17306 | + |
---|
10609 | 17307 | if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) { |
---|
10610 | 17308 | if (timer_pending(&cfg->p2p->listen_timer)) { |
---|
10611 | 17309 | del_timer_sync(&cfg->p2p->listen_timer); |
---|
.. | .. |
---|
10624 | 17322 | wl_get_p2p_status(cfg, ACTION_TX_NOACK))) |
---|
10625 | 17323 | wl_set_p2p_status(cfg, ACTION_TX_COMPLETED); |
---|
10626 | 17324 | |
---|
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). |
---|
10630 | 17332 | */ |
---|
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 | + } |
---|
10633 | 17343 | } |
---|
10634 | 17344 | #ifdef WL_CFG80211_SYNC_GON |
---|
10635 | 17345 | else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) { |
---|
.. | .. |
---|
10640 | 17350 | #endif /* WL_CFG80211_SYNC_GON */ |
---|
10641 | 17351 | } |
---|
10642 | 17352 | |
---|
| 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 */ |
---|
10643 | 17417 | |
---|
10644 | 17418 | int wl_cfg80211_get_ioctl_version(void) |
---|
10645 | 17419 | { |
---|
.. | .. |
---|
10661 | 17435 | wifi_p2p_pub_act_frame_t *act_frm = NULL; |
---|
10662 | 17436 | wifi_p2p_action_frame_t *p2p_act_frm = NULL; |
---|
10663 | 17437 | 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; |
---|
10667 | 17440 | 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))); |
---|
10674 | 17449 | return -EINVAL; |
---|
10675 | 17450 | } |
---|
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); |
---|
10680 | 17461 | 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 | + } |
---|
10681 | 17476 | |
---|
| 17477 | +#ifdef WL_6E |
---|
| 17478 | + if (CHSPEC_IS6G(ntoh16(rxframe->channel))) { |
---|
| 17479 | + band = wiphy->bands[IEEE80211_BAND_6GHZ]; |
---|
| 17480 | + } else |
---|
| 17481 | +#endif /* WL_6E */ |
---|
10682 | 17482 | if (channel <= CH_MAX_2G_CHANNEL) |
---|
10683 | 17483 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; |
---|
10684 | 17484 | else |
---|
.. | .. |
---|
10687 | 17487 | WL_ERR(("No valid band")); |
---|
10688 | 17488 | return -EINVAL; |
---|
10689 | 17489 | } |
---|
10690 | | -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) |
---|
| 17490 | +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) |
---|
10691 | 17491 | freq = ieee80211_channel_to_frequency(channel); |
---|
10692 | 17492 | (void)band->band; |
---|
10693 | 17493 | #else |
---|
10694 | 17494 | freq = ieee80211_channel_to_frequency(channel, band->band); |
---|
10695 | | -#endif |
---|
| 17495 | +#endif // endif |
---|
10696 | 17496 | 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]; |
---|
10699 | 17498 | |
---|
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); |
---|
10701 | 17507 | if (err < 0) |
---|
10702 | 17508 | 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, |
---|
10705 | 17511 | &mgmt_frame, &mgmt_frame_len, |
---|
10706 | 17512 | (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); |
---|
10707 | 17513 | if (err < 0) { |
---|
.. | .. |
---|
10731 | 17537 | wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); |
---|
10732 | 17538 | |
---|
10733 | 17539 | /* Stop waiting for next AF. */ |
---|
10734 | | - wl_stop_wait_next_action_frame(cfg, ndev); |
---|
| 17540 | + wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx); |
---|
10735 | 17541 | } |
---|
10736 | 17542 | } |
---|
10737 | 17543 | (void) sd_act_frm; |
---|
10738 | 17544 | #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 |
---|
10743 | 17559 | if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) { |
---|
10744 | 17560 | cfg->tdls_mgmt_frame = mgmt_frame; |
---|
10745 | 17561 | cfg->tdls_mgmt_frame_len = mgmt_frame_len; |
---|
10746 | 17562 | cfg->tdls_mgmt_freq = freq; |
---|
10747 | 17563 | return 0; |
---|
10748 | 17564 | } |
---|
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 */ |
---|
10753 | 17567 | #ifdef QOS_MAP_SET |
---|
10754 | 17568 | } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) { |
---|
10755 | 17569 | /* update QoS map set table */ |
---|
.. | .. |
---|
10759 | 17573 | DOT11_MNG_QOS_MAP_ID)) != NULL) { |
---|
10760 | 17574 | WL_DBG((" QoS map set IE found in QoS action frame\n")); |
---|
10761 | 17575 | 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); |
---|
10763 | 17577 | } |
---|
10764 | 17578 | wl_set_up_table(cfg->up_table, qos_map_ie); |
---|
10765 | 17579 | } else { |
---|
10766 | | - kfree(cfg->up_table); |
---|
10767 | | - cfg->up_table = NULL; |
---|
| 17580 | + MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX); |
---|
10768 | 17581 | } |
---|
10769 | 17582 | #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 */ |
---|
10770 | 17599 | } else { |
---|
10771 | 17600 | /* |
---|
10772 | 17601 | * if we got normal action frame and ndev is p2p0, |
---|
10773 | 17602 | * we have to change ndev from p2p0 to wlan0 |
---|
10774 | 17603 | */ |
---|
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 */ |
---|
10776 | 17611 | |
---|
10777 | 17612 | if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { |
---|
10778 | 17613 | u8 action = 0; |
---|
.. | .. |
---|
10785 | 17620 | wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev); |
---|
10786 | 17621 | |
---|
10787 | 17622 | /* Stop waiting for next AF. */ |
---|
10788 | | - wl_stop_wait_next_action_frame(cfg, ndev); |
---|
| 17623 | + wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx); |
---|
10789 | 17624 | } |
---|
10790 | 17625 | } |
---|
10791 | 17626 | } |
---|
10792 | 17627 | |
---|
10793 | 17628 | 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 */ |
---|
10794 | 17647 | |
---|
10795 | 17648 | if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) { |
---|
10796 | 17649 | if (cfg->next_af_subtype == act_frm->subtype) { |
---|
.. | .. |
---|
10803 | 17656 | } |
---|
10804 | 17657 | |
---|
10805 | 17658 | /* 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; |
---|
10807 | 17668 | } |
---|
10808 | 17669 | } |
---|
10809 | 17670 | } |
---|
10810 | 17671 | |
---|
10811 | 17672 | wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], |
---|
10812 | 17673 | 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 | | - } |
---|
10820 | 17674 | if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { |
---|
10821 | 17675 | WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); |
---|
10822 | 17676 | wl_clr_p2p_status(cfg, GO_NEG_PHASE); |
---|
.. | .. |
---|
10846 | 17700 | return 0; |
---|
10847 | 17701 | } |
---|
10848 | 17702 | 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); |
---|
10850 | 17705 | WL_DBG((" wps_ie exist pbc = %d\n", pbc)); |
---|
10851 | 17706 | /* if pbc method, send prob_req mgmt frame to upper layer */ |
---|
10852 | 17707 | if (!pbc) |
---|
10853 | 17708 | return 0; |
---|
10854 | 17709 | } else |
---|
10855 | 17710 | 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 */ |
---|
10856 | 17752 | } else { |
---|
10857 | 17753 | mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); |
---|
10858 | 17754 | |
---|
.. | .. |
---|
10865 | 17761 | WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ? |
---|
10866 | 17762 | "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG")); |
---|
10867 | 17763 | |
---|
| 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 */ |
---|
10868 | 17778 | |
---|
10869 | 17779 | /* Filter any P2P probe reqs arriving during the |
---|
10870 | 17780 | * GO-NEG Phase |
---|
.. | .. |
---|
10872 | 17782 | if (cfg->p2p && |
---|
10873 | 17783 | #if defined(P2P_IE_MISSING_FIX) |
---|
10874 | 17784 | cfg->p2p_prb_noti && |
---|
10875 | | -#endif |
---|
| 17785 | +#endif // endif |
---|
10876 | 17786 | wl_get_p2p_status(cfg, GO_NEG_PHASE)) { |
---|
10877 | 17787 | WL_DBG(("Filtering P2P probe_req while " |
---|
10878 | 17788 | "being in GO-Neg state\n")); |
---|
.. | .. |
---|
10885 | 17795 | WL_DBG(("Rx Managment frame For P2P Discovery Interface \n")); |
---|
10886 | 17796 | else |
---|
10887 | 17797 | WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name)); |
---|
10888 | | - |
---|
10889 | 17798 | #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)) |
---|
10892 | 17801 | cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC); |
---|
10893 | 17802 | #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ |
---|
10894 | 17803 | defined(WL_COMPAT_WIRELESS) |
---|
10895 | 17804 | cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); |
---|
10896 | 17805 | #else |
---|
10897 | 17806 | 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) */ |
---|
10899 | 17808 | |
---|
10900 | 17809 | WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", |
---|
10901 | 17810 | mgmt_frame_len, ntoh32(e->datalen), channel, freq)); |
---|
10902 | 17811 | 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); |
---|
10933 | 17814 | } |
---|
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); |
---|
11034 | 17815 | return err; |
---|
11035 | 17816 | } |
---|
11036 | | -#endif /* WL_SCHED_SCAN */ |
---|
11037 | 17817 | |
---|
11038 | 17818 | static void wl_init_conf(struct wl_conf *conf) |
---|
11039 | 17819 | { |
---|
.. | .. |
---|
11050 | 17830 | unsigned long flags; |
---|
11051 | 17831 | struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev); |
---|
11052 | 17832 | |
---|
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); |
---|
11056 | 17841 | } |
---|
11057 | 17842 | |
---|
11058 | 17843 | static void wl_init_event_handler(struct bcm_cfg80211 *cfg) |
---|
11059 | 17844 | { |
---|
11060 | | - memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler)); |
---|
| 17845 | + bzero(cfg->evt_handler, sizeof(cfg->evt_handler)); |
---|
11061 | 17846 | |
---|
11062 | 17847 | cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; |
---|
11063 | 17848 | cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; |
---|
.. | .. |
---|
11079 | 17864 | cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; |
---|
11080 | 17865 | cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; |
---|
11081 | 17866 | 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; |
---|
11082 | 17869 | #ifdef PNO_SUPPORT |
---|
11083 | 17870 | cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; |
---|
11084 | 17871 | #endif /* PNO_SUPPORT */ |
---|
.. | .. |
---|
11086 | 17873 | cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; |
---|
11087 | 17874 | cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; |
---|
11088 | 17875 | 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; |
---|
11090 | 17876 | cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; |
---|
11091 | 17877 | cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; |
---|
11092 | 17878 | cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event; |
---|
11093 | 17879 | cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event; |
---|
11094 | 17880 | cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event; |
---|
11095 | 17881 | #endif /* GSCAN_SUPPORT */ |
---|
| 17882 | +#ifdef RSSI_MONITOR_SUPPORT |
---|
11096 | 17883 | cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event; |
---|
| 17884 | +#endif /* RSSI_MONITOR_SUPPORT */ |
---|
11097 | 17885 | #ifdef WLTDLS |
---|
11098 | 17886 | cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler; |
---|
11099 | 17887 | #endif /* WLTDLS */ |
---|
11100 | 17888 | 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 */ |
---|
11101 | 17892 | #ifdef WL_RELMCAST |
---|
11102 | 17893 | cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status; |
---|
11103 | | -#endif |
---|
| 17894 | +#endif /* WL_RELMCAST */ |
---|
11104 | 17895 | #ifdef BT_WIFI_HANDOVER |
---|
11105 | 17896 | cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req; |
---|
11106 | | -#endif |
---|
| 17897 | +#endif // endif |
---|
11107 | 17898 | #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; |
---|
11110 | 17901 | #endif /* WL_NAN */ |
---|
11111 | 17902 | 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) |
---|
11113 | 17908 | 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 | + |
---|
11115 | 17945 | } |
---|
11116 | 17946 | |
---|
11117 | 17947 | #if defined(STATIC_WL_PRIV_STRUCT) |
---|
11118 | | -static void |
---|
| 17948 | +static int |
---|
11119 | 17949 | wl_init_escan_result_buf(struct bcm_cfg80211 *cfg) |
---|
11120 | 17950 | { |
---|
| 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 |
---|
11121 | 17971 | cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub, |
---|
11122 | 17972 | 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 | + } |
---|
11123 | 17977 | bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE); |
---|
| 17978 | +#endif /* DUAL_ESCAN_RESULT_BUFFER */ |
---|
| 17979 | + |
---|
| 17980 | + return 0; |
---|
11124 | 17981 | } |
---|
11125 | 17982 | |
---|
11126 | 17983 | static void |
---|
11127 | 17984 | wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg) |
---|
11128 | 17985 | { |
---|
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 | + } |
---|
11130 | 17991 | |
---|
| 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 */ |
---|
11131 | 18001 | } |
---|
11132 | 18002 | #endif /* STATIC_WL_PRIV_STRUCT */ |
---|
11133 | 18003 | |
---|
.. | .. |
---|
11135 | 18005 | { |
---|
11136 | 18006 | WL_DBG(("Enter \n")); |
---|
11137 | 18007 | |
---|
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); |
---|
11139 | 18010 | if (unlikely(!cfg->scan_results)) { |
---|
11140 | 18011 | WL_ERR(("Scan results alloc failed\n")); |
---|
11141 | 18012 | goto init_priv_mem_out; |
---|
11142 | 18013 | } |
---|
11143 | | - cfg->conf = (void *)kzalloc(sizeof(*cfg->conf), GFP_KERNEL); |
---|
| 18014 | + cfg->conf = (struct wl_conf *)MALLOCZ(cfg->osh, sizeof(*cfg->conf)); |
---|
11144 | 18015 | if (unlikely(!cfg->conf)) { |
---|
11145 | 18016 | WL_ERR(("wl_conf alloc failed\n")); |
---|
11146 | 18017 | goto init_priv_mem_out; |
---|
11147 | 18018 | } |
---|
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)); |
---|
11150 | 18021 | if (unlikely(!cfg->scan_req_int)) { |
---|
11151 | 18022 | WL_ERR(("Scan req alloc failed\n")); |
---|
11152 | 18023 | goto init_priv_mem_out; |
---|
11153 | 18024 | } |
---|
11154 | | - cfg->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); |
---|
| 18025 | + cfg->ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN); |
---|
11155 | 18026 | if (unlikely(!cfg->ioctl_buf)) { |
---|
11156 | 18027 | WL_ERR(("Ioctl buf alloc failed\n")); |
---|
11157 | 18028 | goto init_priv_mem_out; |
---|
11158 | 18029 | } |
---|
11159 | | - cfg->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); |
---|
| 18030 | + cfg->escan_ioctl_buf = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN); |
---|
11160 | 18031 | if (unlikely(!cfg->escan_ioctl_buf)) { |
---|
11161 | 18032 | WL_ERR(("Ioctl buf alloc failed\n")); |
---|
11162 | 18033 | goto init_priv_mem_out; |
---|
11163 | 18034 | } |
---|
11164 | | - cfg->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); |
---|
| 18035 | + cfg->extra_buf = (void *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX); |
---|
11165 | 18036 | if (unlikely(!cfg->extra_buf)) { |
---|
11166 | 18037 | WL_ERR(("Extra buf alloc failed\n")); |
---|
11167 | 18038 | goto init_priv_mem_out; |
---|
11168 | 18039 | } |
---|
11169 | | - cfg->pmk_list = (void *)kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL); |
---|
| 18040 | + cfg->pmk_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->pmk_list)); |
---|
11170 | 18041 | if (unlikely(!cfg->pmk_list)) { |
---|
11171 | 18042 | WL_ERR(("pmk list alloc failed\n")); |
---|
11172 | 18043 | goto init_priv_mem_out; |
---|
11173 | 18044 | } |
---|
11174 | 18045 | #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)); |
---|
11176 | 18047 | if (unlikely(!cfg->conn_info)) { |
---|
11177 | | - WL_ERR(("cfg->conn_info alloc failed\n")); |
---|
| 18048 | + WL_ERR(("cfg->conn_info alloc failed\n")); |
---|
11178 | 18049 | goto init_priv_mem_out; |
---|
11179 | 18050 | } |
---|
11180 | | - cfg->ie = (void *)kzalloc(sizeof(*cfg->ie), GFP_KERNEL); |
---|
| 18051 | + cfg->ie = (void *)MALLOC(cfg->osh, sizeof(*cfg->ie)); |
---|
11181 | 18052 | if (unlikely(!cfg->ie)) { |
---|
11182 | | - WL_ERR(("cfg->ie alloc failed\n")); |
---|
| 18053 | + WL_ERR(("cfg->ie alloc failed\n")); |
---|
11183 | 18054 | goto init_priv_mem_out; |
---|
11184 | 18055 | } |
---|
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 | + } |
---|
11186 | 18060 | #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)); |
---|
11188 | 18062 | if (unlikely(!cfg->afx_hdl)) { |
---|
11189 | | - WL_ERR(("afx hdl alloc failed\n")); |
---|
| 18063 | + WL_ERR(("afx hdl alloc failed\n")); |
---|
11190 | 18064 | goto init_priv_mem_out; |
---|
11191 | 18065 | } else { |
---|
11192 | 18066 | init_completion(&cfg->act_frm_scan); |
---|
.. | .. |
---|
11196 | 18070 | } |
---|
11197 | 18071 | #ifdef WLTDLS |
---|
11198 | 18072 | if (cfg->tdls_mgmt_frame) { |
---|
11199 | | - kfree(cfg->tdls_mgmt_frame); |
---|
| 18073 | + MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len); |
---|
11200 | 18074 | cfg->tdls_mgmt_frame = NULL; |
---|
| 18075 | + cfg->tdls_mgmt_frame_len = 0; |
---|
11201 | 18076 | } |
---|
11202 | 18077 | #endif /* WLTDLS */ |
---|
11203 | 18078 | return 0; |
---|
.. | .. |
---|
11210 | 18085 | |
---|
11211 | 18086 | static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg) |
---|
11212 | 18087 | { |
---|
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)); |
---|
11227 | 18095 | #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)); |
---|
11232 | 18098 | wl_deinit_escan_result_buf(cfg); |
---|
11233 | 18099 | #endif /* STATIC_WL_PRIV_STRUCT */ |
---|
11234 | 18100 | if (cfg->afx_hdl) { |
---|
11235 | 18101 | 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)); |
---|
11238 | 18103 | } |
---|
11239 | 18104 | |
---|
11240 | 18105 | } |
---|
.. | .. |
---|
11244 | 18109 | int ret = 0; |
---|
11245 | 18110 | WL_DBG(("Enter \n")); |
---|
11246 | 18111 | |
---|
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 | + } |
---|
11249 | 18118 | |
---|
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) { |
---|
11252 | 18120 | 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 */ |
---|
11253 | 18128 | return ret; |
---|
11254 | 18129 | } |
---|
11255 | 18130 | |
---|
11256 | 18131 | static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg) |
---|
11257 | 18132 | { |
---|
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 */ |
---|
11260 | 18145 | } |
---|
11261 | 18146 | |
---|
11262 | | -void wl_terminate_event_handler(void) |
---|
| 18147 | +void wl_terminate_event_handler(struct net_device *dev) |
---|
11263 | 18148 | { |
---|
11264 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 18149 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
11265 | 18150 | |
---|
11266 | 18151 | if (cfg) { |
---|
11267 | 18152 | wl_destroy_event_handler(cfg); |
---|
11268 | 18153 | wl_flush_eq(cfg); |
---|
11269 | 18154 | } |
---|
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); |
---|
11337 | 18155 | } |
---|
11338 | 18156 | |
---|
11339 | 18157 | #ifdef DHD_LOSSLESS_ROAMING |
---|
.. | .. |
---|
11349 | 18167 | |
---|
11350 | 18168 | } |
---|
11351 | 18169 | |
---|
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 |
---|
11357 | 18170 | static void wl_roam_timeout(unsigned long data) |
---|
11358 | 18171 | { |
---|
11359 | 18172 | struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; |
---|
11360 | | -#endif |
---|
11361 | 18173 | dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); |
---|
11362 | 18174 | |
---|
11363 | 18175 | WL_ERR(("roam timer expired\n")); |
---|
.. | .. |
---|
11368 | 18180 | |
---|
11369 | 18181 | #endif /* DHD_LOSSLESS_ROAMING */ |
---|
11370 | 18182 | |
---|
| 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 | + |
---|
11371 | 18301 | static s32 |
---|
11372 | 18302 | wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, |
---|
11373 | 18303 | unsigned long state, void *ptr) |
---|
.. | .. |
---|
11377 | 18307 | #else |
---|
11378 | 18308 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
---|
11379 | 18309 | #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; |
---|
11382 | 18312 | |
---|
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")); |
---|
11386 | 18316 | 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 | + } |
---|
11387 | 18336 | |
---|
11388 | 18337 | switch (state) { |
---|
11389 | 18338 | case NETDEV_DOWN: |
---|
.. | .. |
---|
11422 | 18371 | break; |
---|
11423 | 18372 | } |
---|
11424 | 18373 | case NETDEV_UNREGISTER: |
---|
| 18374 | + wl_cfg80211_clear_per_bss_ies(cfg, wdev); |
---|
11425 | 18375 | /* after calling list_del_rcu(&wdev->list) */ |
---|
11426 | | - wl_cfg80211_clear_per_bss_ies(cfg, |
---|
11427 | | - wl_get_bssidx_by_wdev(cfg, wdev)); |
---|
11428 | 18376 | wl_dealloc_netinfo_by_wdev(cfg, wdev); |
---|
11429 | 18377 | break; |
---|
11430 | 18378 | case NETDEV_GOING_DOWN: |
---|
.. | .. |
---|
11435 | 18383 | * wdev_cleanup_work call WARN_ON and make the scan done forcibly. |
---|
11436 | 18384 | */ |
---|
11437 | 18385 | if (wl_get_drv_status(cfg, SCANNING, dev)) |
---|
11438 | | - wl_notify_escan_complete(cfg, dev, true, true); |
---|
| 18386 | + wl_cfg80211_cancel_scan(cfg); |
---|
11439 | 18387 | break; |
---|
11440 | 18388 | } |
---|
11441 | 18389 | return NOTIFY_DONE; |
---|
.. | .. |
---|
11451 | 18399 | */ |
---|
11452 | 18400 | static bool wl_cfg80211_netdev_notifier_registered = FALSE; |
---|
11453 | 18401 | |
---|
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, ¶ms_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 | | - |
---|
11973 | 18402 | static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable) |
---|
11974 | 18403 | { |
---|
11975 | 18404 | u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED); |
---|
11976 | 18405 | bool p2p_connected = wl_cfgp2p_vif_created(cfg); |
---|
11977 | 18406 | struct net_info *iter, *next; |
---|
11978 | | - int err; |
---|
11979 | 18407 | |
---|
11980 | 18408 | if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT)) |
---|
11981 | 18409 | return; |
---|
11982 | 18410 | |
---|
11983 | 18411 | WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n", |
---|
11984 | 18412 | enable, p2p_connected, connected_cnt)); |
---|
11985 | | - |
---|
11986 | 18413 | /* Disable FW roam when we have a concurrent P2P connection */ |
---|
11987 | 18414 | if (enable && p2p_connected && connected_cnt > 1) { |
---|
| 18415 | + |
---|
11988 | 18416 | /* 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(); |
---|
11995 | 18419 | 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; |
---|
12003 | 18426 | } |
---|
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")); |
---|
12008 | 18429 | } |
---|
12009 | 18430 | } |
---|
12010 | 18431 | } |
---|
12011 | | -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
12012 | | - 4 && __GNUC_MINOR__ >= 6)) |
---|
12013 | | -_Pragma("GCC diagnostic pop") |
---|
12014 | | -#endif |
---|
12015 | 18432 | } |
---|
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(); |
---|
12023 | 18436 | 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) { |
---|
12025 | 18440 | 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 | + } |
---|
12029 | 18445 | 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")); |
---|
12032 | 18447 | } |
---|
12033 | 18448 | } |
---|
12034 | 18449 | } |
---|
12035 | 18450 | } |
---|
12036 | | -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
12037 | | - 4 && __GNUC_MINOR__ >= 6)) |
---|
12038 | | -_Pragma("GCC diagnostic pop") |
---|
12039 | | -#endif |
---|
12040 | 18451 | } |
---|
12041 | 18452 | |
---|
12042 | 18453 | return; |
---|
.. | .. |
---|
12054 | 18465 | if (connected_cnt <= 1) { |
---|
12055 | 18466 | return; |
---|
12056 | 18467 | } |
---|
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(); |
---|
12062 | 18469 | for_each_ndev(cfg, iter, next) { |
---|
| 18470 | + GCC_DIAGNOSTIC_POP(); |
---|
12063 | 18471 | /* p2p discovery iface ndev could be null */ |
---|
12064 | 18472 | if (iter->ndev) { |
---|
12065 | 18473 | chanspec = 0; |
---|
.. | .. |
---|
12082 | 18490 | } |
---|
12083 | 18491 | } |
---|
12084 | 18492 | } |
---|
12085 | | -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
12086 | | - 4 && __GNUC_MINOR__ >= 6)) |
---|
12087 | | -_Pragma("GCC diagnostic pop") |
---|
12088 | | -#endif |
---|
12089 | 18493 | WL_ERR(("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel")); |
---|
12090 | 18494 | return; |
---|
12091 | 18495 | } |
---|
12092 | 18496 | |
---|
| 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 | +} |
---|
12093 | 18539 | |
---|
12094 | 18540 | static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, |
---|
12095 | 18541 | enum wl_status state, bool set) |
---|
.. | .. |
---|
12098 | 18544 | s32 err = BCME_OK; |
---|
12099 | 18545 | u32 mode; |
---|
12100 | 18546 | u32 chan = 0; |
---|
12101 | | - struct net_info *iter, *next; |
---|
12102 | 18547 | 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 */ |
---|
12104 | 18552 | 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")); |
---|
12106 | 18554 | return 0; |
---|
12107 | 18555 | } |
---|
12108 | 18556 | WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n", |
---|
.. | .. |
---|
12113 | 18561 | mode = wl_get_mode_by_netdev(cfg, _net_info->ndev); |
---|
12114 | 18562 | if (set) { |
---|
12115 | 18563 | wl_cfg80211_concurrent_roam(cfg, 1); |
---|
12116 | | - |
---|
| 18564 | + wl_cfg80211_determine_vsdb_mode(cfg); |
---|
12117 | 18565 | if (mode == WL_MODE_AP) { |
---|
12118 | | - |
---|
12119 | 18566 | if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false)) |
---|
12120 | 18567 | WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); |
---|
12121 | 18568 | } |
---|
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)); |
---|
12177 | 18578 | |
---|
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); |
---|
12241 | 18580 | } |
---|
| 18581 | + wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT); |
---|
12242 | 18582 | #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)) { |
---|
12250 | 18584 | err = wldev_iovar_setint(primary_dev, "tdls_enable", 0); |
---|
12251 | 18585 | } |
---|
12252 | 18586 | #endif /* defined(WLTDLS) */ |
---|
12253 | 18587 | |
---|
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 */ |
---|
12256 | 18605 | chan = 0; |
---|
12257 | 18606 | /* clear chan information when the net device is disconnected */ |
---|
12258 | 18607 | wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); |
---|
12259 | 18608 | 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); |
---|
12284 | 18625 | } |
---|
12285 | | - } |
---|
12286 | 18626 | } |
---|
12287 | | -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
12288 | | - 4 && __GNUC_MINOR__ >= 6)) |
---|
12289 | | -_Pragma("GCC diagnostic pop") |
---|
12290 | | -#endif |
---|
12291 | 18627 | wl_cfg80211_concurrent_roam(cfg, 0); |
---|
12292 | 18628 | #if defined(WLTDLS) |
---|
12293 | | - if (!cfg->vsdb_mode) { |
---|
| 18629 | + if (!wl_cfg80211_is_concurrent_mode(primary_dev)) { |
---|
12294 | 18630 | err = wldev_iovar_setint(primary_dev, "tdls_enable", 1); |
---|
12295 | 18631 | } |
---|
12296 | 18632 | #endif /* defined(WLTDLS) */ |
---|
12297 | 18633 | |
---|
| 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 */ |
---|
12298 | 18646 | } |
---|
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 | | - |
---|
12318 | 18647 | return err; |
---|
12319 | 18648 | } |
---|
12320 | 18649 | |
---|
.. | .. |
---|
12324 | 18653 | int err = 0; |
---|
12325 | 18654 | |
---|
12326 | 18655 | /* 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); |
---|
12334 | 18657 | |
---|
12335 | 18658 | return err; |
---|
12336 | 18659 | } |
---|
12337 | 18660 | #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) */ |
---|
12338 | 18670 | |
---|
12339 | 18671 | static s32 wl_init_priv(struct bcm_cfg80211 *cfg) |
---|
12340 | 18672 | { |
---|
.. | .. |
---|
12344 | 18676 | |
---|
12345 | 18677 | cfg->scan_request = NULL; |
---|
12346 | 18678 | cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); |
---|
| 18679 | +#ifdef DISABLE_BUILTIN_ROAM |
---|
12347 | 18680 | cfg->roam_on = false; |
---|
| 18681 | +#else |
---|
| 18682 | + cfg->roam_on = true; |
---|
| 18683 | +#endif /* DISABLE_BUILTIN_ROAM */ |
---|
12348 | 18684 | cfg->active_scan = true; |
---|
12349 | 18685 | cfg->rf_blocked = false; |
---|
12350 | 18686 | cfg->vsdb_mode = false; |
---|
12351 | | -#if defined(BCMSDIO) || defined(BCMDBUS) |
---|
| 18687 | +#if defined(BCMSDIO) |
---|
12352 | 18688 | cfg->wlfc_on = false; |
---|
12353 | | -#endif /* defined(BCMSDIO) || defined(BCMDBUS) */ |
---|
| 18689 | +#endif /* defined(BCMSDIO) */ |
---|
12354 | 18690 | cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT; |
---|
12355 | 18691 | cfg->disable_roam_event = false; |
---|
12356 | | - cfg->cfgdev_bssidx = -1; |
---|
12357 | 18692 | /* register interested state */ |
---|
12358 | 18693 | set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state); |
---|
12359 | 18694 | spin_lock_init(&cfg->cfgdrv_lock); |
---|
.. | .. |
---|
12370 | 18705 | wl_init_event_handler(cfg); |
---|
12371 | 18706 | mutex_init(&cfg->usr_sync); |
---|
12372 | 18707 | 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 */ |
---|
12374 | 18719 | err = wl_init_scan(cfg); |
---|
12375 | 18720 | if (err) |
---|
12376 | 18721 | return err; |
---|
.. | .. |
---|
12380 | 18725 | return err; |
---|
12381 | 18726 | } |
---|
12382 | 18727 | #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 |
---|
12383 | 18734 | wl_init_conf(cfg->conf); |
---|
12384 | 18735 | wl_init_prof(cfg, ndev); |
---|
12385 | 18736 | wl_link_down(cfg); |
---|
12386 | 18737 | 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; |
---|
12388 | 18745 | return err; |
---|
12389 | 18746 | } |
---|
12390 | 18747 | |
---|
.. | .. |
---|
12397 | 18754 | del_timer_sync(&cfg->scan_timeout); |
---|
12398 | 18755 | #ifdef DHD_LOSSLESS_ROAMING |
---|
12399 | 18756 | 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 |
---|
12401 | 18761 | wl_deinit_priv_mem(cfg); |
---|
12402 | 18762 | if (wl_cfg80211_netdev_notifier_registered) { |
---|
12403 | 18763 | wl_cfg80211_netdev_notifier_registered = FALSE; |
---|
.. | .. |
---|
12405 | 18765 | } |
---|
12406 | 18766 | } |
---|
12407 | 18767 | |
---|
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) |
---|
12410 | 18770 | { |
---|
12411 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
12412 | | - |
---|
12413 | 18771 | WL_TRACE(("Enter \n")); |
---|
12414 | 18772 | |
---|
12415 | 18773 | if (wl_cfgp2p_register_ndev(cfg) < 0) { |
---|
.. | .. |
---|
12420 | 18778 | return 0; |
---|
12421 | 18779 | } |
---|
12422 | 18780 | |
---|
12423 | | -static s32 wl_cfg80211_detach_p2p(void) |
---|
| 18781 | +static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg) |
---|
12424 | 18782 | { |
---|
12425 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 18783 | +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT |
---|
12426 | 18784 | struct wireless_dev *wdev; |
---|
| 18785 | +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ |
---|
12427 | 18786 | |
---|
12428 | 18787 | WL_DBG(("Enter \n")); |
---|
12429 | 18788 | if (!cfg) { |
---|
12430 | 18789 | WL_ERR(("Invalid Ptr\n")); |
---|
12431 | 18790 | return -EINVAL; |
---|
12432 | | - } else |
---|
12433 | | - wdev = cfg->p2p_wdev; |
---|
12434 | | - |
---|
12435 | | - if (!wdev) { |
---|
12436 | | - WL_ERR(("Invalid Ptr\n")); |
---|
12437 | | - return -EINVAL; |
---|
12438 | 18791 | } |
---|
| 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 */ |
---|
12439 | 18801 | |
---|
12440 | 18802 | wl_cfgp2p_unregister_ndev(cfg); |
---|
12441 | 18803 | |
---|
12442 | 18804 | cfg->p2p_wdev = NULL; |
---|
12443 | 18805 | cfg->p2p_net = NULL; |
---|
| 18806 | +#ifndef WL_NEWCFG_PRIVCMD_SUPPORT |
---|
12444 | 18807 | WL_DBG(("Freeing 0x%p \n", wdev)); |
---|
12445 | | - kfree(wdev); |
---|
| 18808 | + MFREE(cfg->osh, wdev, sizeof(*wdev)); |
---|
| 18809 | +#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ |
---|
12446 | 18810 | |
---|
12447 | 18811 | return 0; |
---|
12448 | 18812 | } |
---|
12449 | | -#endif |
---|
| 18813 | +#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */ |
---|
12450 | 18814 | |
---|
12451 | | -s32 wl_cfg80211_attach_post(struct net_device *ndev) |
---|
| 18815 | +static s32 wl_cfg80211_attach_post(struct net_device *ndev) |
---|
12452 | 18816 | { |
---|
12453 | | - struct bcm_cfg80211 * cfg = NULL; |
---|
| 18817 | + struct bcm_cfg80211 * cfg; |
---|
12454 | 18818 | s32 err = 0; |
---|
12455 | 18819 | s32 ret = 0; |
---|
12456 | 18820 | WL_TRACE(("In\n")); |
---|
.. | .. |
---|
12458 | 18822 | WL_ERR(("ndev is invaild\n")); |
---|
12459 | 18823 | return -ENODEV; |
---|
12460 | 18824 | } |
---|
12461 | | - cfg = g_bcm_cfg; |
---|
| 18825 | + cfg = wl_get_cfg(ndev); |
---|
12462 | 18826 | if (unlikely(!cfg)) { |
---|
12463 | 18827 | WL_ERR(("cfg is invaild\n")); |
---|
12464 | 18828 | return -EINVAL; |
---|
.. | .. |
---|
12505 | 18869 | return err; |
---|
12506 | 18870 | } |
---|
12507 | 18871 | |
---|
| 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 | + |
---|
12508 | 18909 | s32 wl_cfg80211_attach(struct net_device *ndev, void *context) |
---|
12509 | 18910 | { |
---|
12510 | 18911 | struct wireless_dev *wdev; |
---|
12511 | 18912 | struct bcm_cfg80211 *cfg; |
---|
12512 | 18913 | s32 err = 0; |
---|
12513 | 18914 | struct device *dev; |
---|
| 18915 | + u16 bssidx = 0; |
---|
| 18916 | + u16 ifidx = 0; |
---|
| 18917 | + dhd_pub_t *dhd = (struct dhd_pub *)(context); |
---|
12514 | 18918 | |
---|
12515 | 18919 | WL_TRACE(("In\n")); |
---|
12516 | 18920 | if (!ndev) { |
---|
.. | .. |
---|
12520 | 18924 | WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev())); |
---|
12521 | 18925 | dev = wl_cfg80211_get_parent_dev(); |
---|
12522 | 18926 | |
---|
12523 | | - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); |
---|
| 18927 | + wdev = (struct wireless_dev *)MALLOCZ(dhd->osh, sizeof(*wdev)); |
---|
12524 | 18928 | if (unlikely(!wdev)) { |
---|
12525 | 18929 | WL_ERR(("Could not allocate wireless device\n")); |
---|
12526 | 18930 | return -ENOMEM; |
---|
12527 | 18931 | } |
---|
12528 | 18932 | err = wl_setup_wiphy(wdev, dev, context); |
---|
12529 | 18933 | if (unlikely(err)) { |
---|
12530 | | - kfree(wdev); |
---|
| 18934 | + MFREE(dhd->osh, wdev, sizeof(*wdev)); |
---|
12531 | 18935 | return -ENOMEM; |
---|
12532 | 18936 | } |
---|
12533 | 18937 | 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); |
---|
12535 | 18939 | cfg->wdev = wdev; |
---|
12536 | 18940 | cfg->pub = context; |
---|
| 18941 | + cfg->osh = dhd->osh; |
---|
12537 | 18942 | 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); |
---|
12538 | 18948 | spin_lock_init(&cfg->net_list_sync); |
---|
12539 | 18949 | ndev->ieee80211_ptr = wdev; |
---|
12540 | 18950 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); |
---|
12541 | 18951 | wdev->netdev = ndev; |
---|
12542 | 18952 | 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); |
---|
12544 | 18954 | if (err) { |
---|
12545 | 18955 | WL_ERR(("Failed to alloc net_info (%d)\n", err)); |
---|
12546 | 18956 | goto cfg80211_attach_out; |
---|
.. | .. |
---|
12562 | 18972 | WL_ERR(("Failed to setup debugfs %d\n", err)); |
---|
12563 | 18973 | goto cfg80211_attach_out; |
---|
12564 | 18974 | } |
---|
12565 | | -#endif |
---|
| 18975 | +#endif // endif |
---|
12566 | 18976 | if (!wl_cfg80211_netdev_notifier_registered) { |
---|
12567 | 18977 | wl_cfg80211_netdev_notifier_registered = TRUE; |
---|
12568 | 18978 | err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); |
---|
.. | .. |
---|
12572 | 18982 | goto cfg80211_attach_out; |
---|
12573 | 18983 | } |
---|
12574 | 18984 | } |
---|
12575 | | -#if defined(COEX_DHCP) |
---|
| 18985 | +#if defined(OEM_ANDROID) && defined(COEX_DHCP) |
---|
12576 | 18986 | cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev); |
---|
12577 | 18987 | if (!cfg->btcoex_info) |
---|
12578 | 18988 | 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 */ |
---|
12580 | 18993 | |
---|
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); |
---|
12589 | 18996 | if (err) |
---|
12590 | 18997 | 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 |
---|
12592 | 19017 | |
---|
12593 | 19018 | return err; |
---|
12594 | 19019 | |
---|
.. | .. |
---|
12598 | 19023 | return err; |
---|
12599 | 19024 | } |
---|
12600 | 19025 | |
---|
12601 | | -void wl_cfg80211_detach(void *para) |
---|
| 19026 | +void wl_cfg80211_detach(struct bcm_cfg80211 *cfg) |
---|
12602 | 19027 | { |
---|
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); |
---|
12604 | 19033 | |
---|
12605 | | - (void)para; |
---|
12606 | | - cfg = g_bcm_cfg; |
---|
| 19034 | +#ifdef ENABLE_HOGSQS |
---|
| 19035 | + cancel_delayed_work_sync(&cfg->hogsqs_eventwork); |
---|
| 19036 | +#endif // endif |
---|
12607 | 19037 | |
---|
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) |
---|
12613 | 19039 | wl_cfg80211_btcoex_deinit(); |
---|
12614 | 19040 | cfg->btcoex_info = NULL; |
---|
12615 | | -#endif |
---|
| 19041 | +#endif /* defined(OEM_ANDROID) && defined(COEX_DHCP) */ |
---|
12616 | 19042 | |
---|
12617 | 19043 | wl_setup_rfkill(cfg, FALSE); |
---|
12618 | 19044 | #ifdef DEBUGFS_CFG80211 |
---|
12619 | 19045 | wl_free_debugfs(cfg); |
---|
12620 | | -#endif |
---|
| 19046 | +#endif // endif |
---|
12621 | 19047 | if (cfg->p2p_supported) { |
---|
12622 | 19048 | if (timer_pending(&cfg->p2p->listen_timer)) |
---|
12623 | 19049 | del_timer_sync(&cfg->p2p->listen_timer); |
---|
12624 | 19050 | wl_cfgp2p_deinit_priv(cfg); |
---|
12625 | 19051 | } |
---|
| 19052 | + |
---|
| 19053 | +#ifdef WL_WPS_SYNC |
---|
| 19054 | + wl_deinit_wps_reauth_sm(cfg); |
---|
| 19055 | +#endif /* WL_WPS_SYNC */ |
---|
12626 | 19056 | |
---|
12627 | 19057 | if (timer_pending(&cfg->scan_timeout)) |
---|
12628 | 19058 | del_timer_sync(&cfg->scan_timeout); |
---|
.. | .. |
---|
12632 | 19062 | } |
---|
12633 | 19063 | #endif /* DHD_LOSSLESS_ROAMING */ |
---|
12634 | 19064 | |
---|
| 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 |
---|
12635 | 19073 | #if defined(WL_CFG80211_P2P_DEV_IF) |
---|
12636 | 19074 | if (cfg->p2p_wdev) |
---|
12637 | 19075 | wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); |
---|
12638 | 19076 | #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 */ |
---|
12643 | 19086 | 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); |
---|
12645 | 19089 | wl_deinit_priv(cfg); |
---|
12646 | | - g_bcm_cfg = NULL; |
---|
12647 | 19090 | wl_cfg80211_clear_parent_dev(); |
---|
12648 | 19091 | wl_free_wdev(cfg); |
---|
12649 | 19092 | /* PLEASE do NOT call any function after wl_free_wdev, the driver's private |
---|
12650 | 19093 | * structure "cfg", which is the private part of wiphy, has been freed in |
---|
12651 | 19094 | * wl_free_wdev !!!!!!!!!!! |
---|
12652 | 19095 | */ |
---|
| 19096 | + WL_DBG(("Exit\n")); |
---|
12653 | 19097 | } |
---|
12654 | 19098 | |
---|
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() |
---|
12656 | 19101 | { |
---|
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 | + } |
---|
12660 | 19111 | } |
---|
12661 | 19112 | } |
---|
12662 | 19113 | |
---|
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) |
---|
12664 | 19159 | { |
---|
12665 | 19160 | struct bcm_cfg80211 *cfg = NULL; |
---|
12666 | 19161 | struct wl_event_q *e; |
---|
12667 | | - tsk_ctl_t *tsk = (tsk_ctl_t *)data; |
---|
12668 | 19162 | struct wireless_dev *wdev = NULL; |
---|
12669 | 19163 | |
---|
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)); |
---|
12671 | 19173 | |
---|
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); |
---|
12673 | 19180 | |
---|
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 */ |
---|
12678 | 19251 | break; |
---|
12679 | 19252 | } |
---|
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; |
---|
12712 | 19255 | } |
---|
12713 | | - WL_ERR(("was terminated\n")); |
---|
12714 | | - complete_and_exit(&tsk->completed, 0); |
---|
12715 | | - return 0; |
---|
| 19256 | + return ret; |
---|
12716 | 19257 | } |
---|
12717 | 19258 | |
---|
12718 | 19259 | void |
---|
12719 | 19260 | wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) |
---|
12720 | 19261 | { |
---|
| 19262 | + s32 status = ntoh32(e->status); |
---|
12721 | 19263 | u32 event_type = ntoh32(e->event_type); |
---|
12722 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 19264 | + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); |
---|
12723 | 19265 | struct net_info *netinfo; |
---|
12724 | 19266 | |
---|
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))); |
---|
12731 | 19269 | if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) { |
---|
12732 | 19270 | WL_ERR(("Stale event ignored\n")); |
---|
12733 | 19271 | return; |
---|
12734 | 19272 | } |
---|
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 */ |
---|
12737 | 19288 | return; |
---|
12738 | 19289 | } |
---|
12739 | 19290 | |
---|
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); |
---|
12745 | 19292 | if (!netinfo) { |
---|
12746 | 19293 | /* Since the netinfo entry is not there, the netdev entry is not |
---|
12747 | 19294 | * created via cfg80211 interface. so the event is not of interest |
---|
12748 | 19295 | * to the cfg80211 layer. |
---|
12749 | 19296 | */ |
---|
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) { |
---|
12751 | 19303 | return; |
---|
12752 | 19304 | } |
---|
12753 | 19305 | |
---|
.. | .. |
---|
12758 | 19310 | WL_DBG((" PNOEVENT: PNO_NET_LOST\n")); |
---|
12759 | 19311 | } |
---|
12760 | 19312 | |
---|
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 | + } |
---|
12763 | 19328 | } |
---|
12764 | 19329 | |
---|
12765 | 19330 | static void wl_init_eq(struct bcm_cfg80211 *cfg) |
---|
.. | .. |
---|
12777 | 19342 | while (!list_empty_careful(&cfg->eq_list)) { |
---|
12778 | 19343 | BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list); |
---|
12779 | 19344 | list_del(&e->eq_list); |
---|
12780 | | - kfree(e); |
---|
| 19345 | + MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q)); |
---|
12781 | 19346 | } |
---|
12782 | 19347 | wl_unlock_eq(cfg, flags); |
---|
12783 | 19348 | } |
---|
.. | .. |
---|
12814 | 19379 | uint32 evtq_size; |
---|
12815 | 19380 | uint32 data_len; |
---|
12816 | 19381 | unsigned long flags; |
---|
12817 | | - gfp_t aflags; |
---|
12818 | 19382 | |
---|
12819 | 19383 | data_len = 0; |
---|
12820 | 19384 | if (data) |
---|
12821 | 19385 | 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); |
---|
12825 | 19388 | if (unlikely(!e)) { |
---|
12826 | 19389 | WL_ERR(("event alloc failed\n")); |
---|
12827 | 19390 | return -ENOMEM; |
---|
.. | .. |
---|
12830 | 19393 | memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); |
---|
12831 | 19394 | if (data) |
---|
12832 | 19395 | memcpy(e->edata, data, data_len); |
---|
| 19396 | + e->datalen = data_len; |
---|
12833 | 19397 | flags = wl_lock_eq(cfg); |
---|
12834 | 19398 | list_add_tail(&e->eq_list, &cfg->eq_list); |
---|
12835 | 19399 | wl_unlock_eq(cfg, flags); |
---|
.. | .. |
---|
12837 | 19401 | return err; |
---|
12838 | 19402 | } |
---|
12839 | 19403 | |
---|
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) |
---|
12841 | 19405 | { |
---|
12842 | | - kfree(e); |
---|
| 19406 | + MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q)); |
---|
12843 | 19407 | } |
---|
12844 | 19408 | |
---|
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) |
---|
12846 | 19410 | { |
---|
12847 | 19411 | s32 infra = 0; |
---|
12848 | 19412 | s32 err = 0; |
---|
12849 | | - s32 mode = 0; |
---|
| 19413 | + bool skip_infra = false; |
---|
| 19414 | + |
---|
12850 | 19415 | 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; |
---|
12880 | 19435 | } |
---|
12881 | 19436 | |
---|
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 | + } |
---|
12884 | 19445 | return 0; |
---|
12885 | 19446 | } |
---|
12886 | 19447 | |
---|
.. | .. |
---|
12932 | 19493 | |
---|
12933 | 19494 | /* Write updated Event mask */ |
---|
12934 | 19495 | ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf, |
---|
12935 | | - sizeof(iovbuf), NULL); |
---|
| 19496 | + sizeof(iovbuf), NULL); |
---|
12936 | 19497 | if (unlikely(ret)) { |
---|
12937 | 19498 | WL_ERR(("Set event_msgs error (%d)\n", ret)); |
---|
12938 | 19499 | } |
---|
.. | .. |
---|
12947 | 19508 | s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; |
---|
12948 | 19509 | s8 eventmask[WL_EVENTING_MASK_LEN]; |
---|
12949 | 19510 | s32 err = 0; |
---|
12950 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 19511 | + struct bcm_cfg80211 *cfg; |
---|
12951 | 19512 | |
---|
12952 | | - if (!ndev || !cfg) |
---|
| 19513 | + if (!ndev) |
---|
| 19514 | + return -ENODEV; |
---|
| 19515 | + |
---|
| 19516 | + cfg = wl_get_cfg(ndev); |
---|
| 19517 | + if (!cfg) |
---|
12953 | 19518 | return -ENODEV; |
---|
12954 | 19519 | |
---|
12955 | 19520 | mutex_lock(&cfg->event_sync); |
---|
.. | .. |
---|
12967 | 19532 | clrbit(eventmask, event); |
---|
12968 | 19533 | } |
---|
12969 | 19534 | err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, |
---|
12970 | | - sizeof(iovbuf), NULL); |
---|
| 19535 | + sizeof(iovbuf), NULL); |
---|
12971 | 19536 | if (unlikely(err)) { |
---|
12972 | 19537 | WL_ERR(("Set event_msgs error (%d)\n", err)); |
---|
12973 | 19538 | goto eventmsg_out; |
---|
.. | .. |
---|
12978 | 19543 | return err; |
---|
12979 | 19544 | } |
---|
12980 | 19545 | |
---|
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[]) |
---|
12982 | 19827 | { |
---|
12983 | 19828 | struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); |
---|
12984 | 19829 | struct ieee80211_channel *band_chan_arr = NULL; |
---|
12985 | 19830 | 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; |
---|
12987 | 19832 | u32 *n_cnt = NULL; |
---|
12988 | 19833 | chanspec_t c = 0; |
---|
12989 | 19834 | s32 err = BCME_OK; |
---|
.. | .. |
---|
12992 | 19837 | u8 *pbuf = NULL; |
---|
12993 | 19838 | bool dfs_radar_disabled = FALSE; |
---|
12994 | 19839 | |
---|
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); |
---|
12998 | 19842 | if (pbuf == NULL) { |
---|
12999 | 19843 | WL_ERR(("failed to allocate local buf\n")); |
---|
13000 | 19844 | return -ENOMEM; |
---|
.. | .. |
---|
13004 | 19848 | 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync); |
---|
13005 | 19849 | if (err != 0) { |
---|
13006 | 19850 | WL_ERR(("get chanspecs failed with %d\n", err)); |
---|
13007 | | - kfree(pbuf); |
---|
| 19851 | + MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN); |
---|
13008 | 19852 | return err; |
---|
13009 | 19853 | } |
---|
13010 | | -#undef LOCAL_BUF_LEN |
---|
13011 | 19854 | |
---|
13012 | 19855 | 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; |
---|
13014 | 19857 | for (i = 0; i < dtoh32(list->count); i++) { |
---|
13015 | 19858 | index = 0; |
---|
13016 | 19859 | update = false; |
---|
.. | .. |
---|
13029 | 19872 | array_size = ARRAYSIZE(__wl_2ghz_channels); |
---|
13030 | 19873 | n_cnt = &n_2g; |
---|
13031 | 19874 | 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; |
---|
13033 | 19876 | } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) { |
---|
13034 | 19877 | band_chan_arr = __wl_5ghz_a_channels; |
---|
13035 | 19878 | array_size = ARRAYSIZE(__wl_5ghz_a_channels); |
---|
13036 | 19879 | n_cnt = &n_5g; |
---|
13037 | 19880 | 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 */ |
---|
13039 | 19891 | } else { |
---|
13040 | | - WL_ERR(("Invalid channel Sepc. 0x%x.\n", c)); |
---|
| 19892 | + WL_ERR(("Invalid channel Spec. 0x%x.\n", c)); |
---|
13041 | 19893 | continue; |
---|
13042 | 19894 | } |
---|
13043 | 19895 | if (!ht40_allowed && CHSPEC_IS40(c)) |
---|
.. | .. |
---|
13053 | 19905 | else |
---|
13054 | 19906 | index = *n_cnt; |
---|
13055 | 19907 | 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) |
---|
13057 | 19909 | band_chan_arr[index].center_freq = |
---|
13058 | 19910 | ieee80211_channel_to_frequency(channel); |
---|
13059 | 19911 | #else |
---|
13060 | 19912 | band_chan_arr[index].center_freq = |
---|
13061 | 19913 | ieee80211_channel_to_frequency(channel, band); |
---|
13062 | | -#endif |
---|
| 19914 | +#endif // endif |
---|
13063 | 19915 | band_chan_arr[index].hw_value = channel; |
---|
13064 | 19916 | band_chan_arr[index].beacon_found = false; |
---|
13065 | 19917 | |
---|
.. | .. |
---|
13087 | 19939 | if (!dfs_radar_disabled) { |
---|
13088 | 19940 | if (band == IEEE80211_BAND_2GHZ) |
---|
13089 | 19941 | channel |= WL_CHANSPEC_BAND_2G; |
---|
13090 | | - else |
---|
| 19942 | + else if (band == IEEE80211_BAND_5GHZ) |
---|
13091 | 19943 | 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 | + |
---|
13092 | 19949 | channel |= WL_CHANSPEC_BW_20; |
---|
13093 | 19950 | channel = wl_chspec_host_to_driver(channel); |
---|
13094 | 19951 | err = wldev_iovar_getint(dev, "per_chan_info", &channel); |
---|
.. | .. |
---|
13101 | 19958 | #else |
---|
13102 | 19959 | band_chan_arr[index].flags |= |
---|
13103 | 19960 | IEEE80211_CHAN_RADAR; |
---|
13104 | | -#endif |
---|
| 19961 | +#endif // endif |
---|
13105 | 19962 | } |
---|
13106 | 19963 | |
---|
13107 | 19964 | if (channel & WL_CHAN_PASSIVE) |
---|
.. | .. |
---|
13111 | 19968 | #else |
---|
13112 | 19969 | band_chan_arr[index].flags |= |
---|
13113 | 19970 | IEEE80211_CHAN_NO_IR; |
---|
13114 | | -#endif |
---|
| 19971 | +#endif // endif |
---|
13115 | 19972 | } else if (err == BCME_UNSUPPORTED) { |
---|
13116 | 19973 | dfs_radar_disabled = TRUE; |
---|
13117 | 19974 | WL_ERR(("does not support per_chan_info\n")); |
---|
.. | .. |
---|
13125 | 19982 | } |
---|
13126 | 19983 | __wl_band_2ghz.n_channels = n_2g; |
---|
13127 | 19984 | __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 | + |
---|
13129 | 19991 | return err; |
---|
13130 | 19992 | } |
---|
13131 | 19993 | |
---|
13132 | | -s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) |
---|
| 19994 | +static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) |
---|
13133 | 19995 | { |
---|
13134 | 19996 | 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 |
---|
13136 | 20001 | u32 bandlist[3]; |
---|
| 20002 | +#endif /* WL_6E */ |
---|
13137 | 20003 | u32 nband = 0; |
---|
13138 | 20004 | u32 i = 0; |
---|
13139 | 20005 | s32 err = 0; |
---|
13140 | 20006 | s32 index = 0; |
---|
13141 | 20007 | s32 nmode = 0; |
---|
| 20008 | + u32 rxchain; |
---|
| 20009 | + u32 nchain; |
---|
13142 | 20010 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) |
---|
13143 | | - u32 j = 0; |
---|
13144 | 20011 | 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 */ |
---|
13155 | 20020 | 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 |
---|
13159 | 20021 | struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, }; |
---|
13160 | | -#endif |
---|
13161 | 20022 | |
---|
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)); |
---|
13172 | 20026 | if (unlikely(err)) { |
---|
13173 | 20027 | WL_ERR(("error read bandlist (%d)\n", err)); |
---|
13174 | | - goto end_bands; |
---|
| 20028 | + return err; |
---|
13175 | 20029 | } |
---|
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)); |
---|
13178 | 20032 | if (unlikely(err)) { |
---|
13179 | 20033 | WL_ERR(("error (%d)\n", err)); |
---|
13180 | | - goto end_bands; |
---|
| 20034 | + return err; |
---|
13181 | 20035 | } |
---|
13182 | 20036 | |
---|
13183 | 20037 | err = wldev_iovar_getint(dev, "nmode", &nmode); |
---|
.. | .. |
---|
13190 | 20044 | if (unlikely(err)) { |
---|
13191 | 20045 | WL_ERR(("error reading vhtmode (%d)\n", err)); |
---|
13192 | 20046 | } |
---|
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 |
---|
13231 | 20048 | |
---|
13232 | 20049 | /* For nmode and vhtmode check bw cap */ |
---|
13233 | 20050 | if (nmode || |
---|
13234 | 20051 | #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); |
---|
13242 | 20056 | } |
---|
| 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)); |
---|
13243 | 20067 | |
---|
13244 | 20068 | err = wl_construct_reginfo(cfg, bw_cap); |
---|
13245 | 20069 | if (err) { |
---|
13246 | 20070 | WL_ERR(("wl_construct_reginfo() fails err=%d\n", err)); |
---|
13247 | 20071 | if (err != BCME_UNSUPPORTED) |
---|
13248 | | - goto end_bands; |
---|
13249 | | - err = 0; |
---|
| 20072 | + return err; |
---|
13250 | 20073 | } |
---|
| 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 | + |
---|
13251 | 20083 | wiphy = bcmcfg_to_wiphy(cfg); |
---|
13252 | 20084 | nband = bandlist[0]; |
---|
13253 | 20085 | |
---|
13254 | 20086 | for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { |
---|
13255 | 20087 | index = -1; |
---|
13256 | 20088 | if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) { |
---|
13257 | | - bands[IEEE80211_BAND_5GHZ] = |
---|
13258 | | - &__wl_band_5ghz_a; |
---|
13259 | 20089 | 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; |
---|
13263 | 20091 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) |
---|
13264 | | - /* VHT capabilities. */ |
---|
13265 | 20092 | 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]); |
---|
13346 | 20094 | } |
---|
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 |
---|
13348 | 20104 | } |
---|
13349 | 20105 | else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { |
---|
13350 | | - bands[IEEE80211_BAND_2GHZ] = |
---|
13351 | | - &__wl_band_2ghz; |
---|
13352 | 20106 | 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 |
---|
13355 | 20116 | } |
---|
| 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 */ |
---|
13356 | 20131 | |
---|
13357 | 20132 | 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); |
---|
13365 | 20134 | } |
---|
13366 | | - |
---|
13367 | 20135 | } |
---|
13368 | 20136 | |
---|
13369 | 20137 | wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; |
---|
13370 | 20138 | 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 */ |
---|
13371 | 20142 | |
---|
13372 | 20143 | /* check if any bands populated otherwise makes 2Ghz as default */ |
---|
13373 | 20144 | if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL && |
---|
.. | .. |
---|
13378 | 20149 | |
---|
13379 | 20150 | if (notify) |
---|
13380 | 20151 | wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); |
---|
| 20152 | +#ifdef WL_SAE |
---|
| 20153 | + (void)wl_wiphy_update_sae(wiphy, dhd); |
---|
| 20154 | +#endif /* WL_SAE */ |
---|
13381 | 20155 | |
---|
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 | + |
---|
13385 | 20167 | return err; |
---|
13386 | 20168 | } |
---|
13387 | 20169 | |
---|
13388 | 20170 | static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) |
---|
13389 | 20171 | { |
---|
13390 | 20172 | 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; |
---|
13391 | 20177 | struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); |
---|
13392 | 20178 | 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]; |
---|
13393 | 20188 | |
---|
13394 | 20189 | WL_DBG(("In\n")); |
---|
| 20190 | + |
---|
| 20191 | + /* Reserve 0x8000 toggle bit for P2P GO/GC */ |
---|
| 20192 | + cfg->vif_macaddr_mask = 0x8000; |
---|
13395 | 20193 | |
---|
13396 | 20194 | err = dhd_config_dongle(cfg); |
---|
13397 | 20195 | if (unlikely(err)) |
---|
13398 | 20196 | return err; |
---|
13399 | 20197 | |
---|
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); |
---|
13401 | 20215 | if (unlikely(err && err != -EINPROGRESS)) { |
---|
13402 | | - WL_ERR(("wl_config_ifmode failed\n")); |
---|
| 20216 | + WL_ERR(("wl_config_infra failed\n")); |
---|
13403 | 20217 | if (err == -1) { |
---|
13404 | 20218 | WL_ERR(("return error %d\n", err)); |
---|
13405 | 20219 | return err; |
---|
13406 | 20220 | } |
---|
13407 | 20221 | } |
---|
13408 | | - err = wl_update_wiphybands(cfg, true); |
---|
| 20222 | + err = __wl_update_wiphybands(cfg, true); |
---|
13409 | 20223 | if (unlikely(err)) { |
---|
13410 | 20224 | WL_ERR(("wl_update_wiphybands failed\n")); |
---|
13411 | 20225 | if (err == -1) { |
---|
.. | .. |
---|
13413 | 20227 | return err; |
---|
13414 | 20228 | } |
---|
13415 | 20229 | } |
---|
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); |
---|
13421 | 20237 | } |
---|
13422 | | - wl_init_event_handler(cfg); |
---|
13423 | | - |
---|
13424 | 20238 | err = wl_init_scan(cfg); |
---|
13425 | 20239 | if (err) { |
---|
13426 | 20240 | WL_ERR(("wl_init_scan failed\n")); |
---|
13427 | 20241 | 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 | + } |
---|
13428 | 20263 | } |
---|
13429 | 20264 | #ifdef DHD_LOSSLESS_ROAMING |
---|
13430 | 20265 | if (timer_pending(&cfg->roam_timeout)) { |
---|
.. | .. |
---|
13432 | 20267 | } |
---|
13433 | 20268 | #endif /* DHD_LOSSLESS_ROAMING */ |
---|
13434 | 20269 | |
---|
| 20270 | +#ifdef DHD_MONITOR_INTERFACE |
---|
13435 | 20271 | 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 */ |
---|
13436 | 20325 | |
---|
13437 | 20326 | INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler); |
---|
13438 | 20327 | wl_set_drv_status(cfg, READY, ndev); |
---|
.. | .. |
---|
13442 | 20331 | static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) |
---|
13443 | 20332 | { |
---|
13444 | 20333 | s32 err = 0; |
---|
13445 | | - unsigned long flags; |
---|
13446 | 20334 | struct net_info *iter, *next; |
---|
13447 | 20335 | 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) |
---|
13449 | 20338 | 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 */ |
---|
13453 | 20340 | 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")); |
---|
13459 | 20342 | |
---|
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); |
---|
13463 | 20359 | |
---|
13464 | 20360 | if (cfg->p2p_supported) { |
---|
13465 | 20361 | wl_clr_p2p_status(cfg, GO_NEG_PHASE); |
---|
13466 | 20362 | #ifdef PROP_TXSTATUS_VSDB |
---|
13467 | | -#if defined(BCMSDIO) || defined(BCMDBUS) |
---|
| 20363 | +#if defined(BCMSDIO) |
---|
13468 | 20364 | if (wl_cfgp2p_vif_created(cfg)) { |
---|
13469 | 20365 | bool enabled = false; |
---|
13470 | 20366 | dhd_wlfc_get_enable(dhd, &enabled); |
---|
.. | .. |
---|
13474 | 20370 | cfg->wlfc_on = false; |
---|
13475 | 20371 | } |
---|
13476 | 20372 | } |
---|
13477 | | -#endif /* defined(BCMSDIO) || defined(BCMDBUS) */ |
---|
| 20373 | +#endif /* defined(BCMSDIO) */ |
---|
13478 | 20374 | #endif /* PROP_TXSTATUS_VSDB */ |
---|
13479 | 20375 | } |
---|
13480 | 20376 | |
---|
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); |
---|
13485 | 20403 | } |
---|
13486 | 20404 | |
---|
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(); |
---|
13502 | 20406 | for_each_ndev(cfg, iter, next) { |
---|
| 20407 | + GCC_DIAGNOSTIC_POP(); |
---|
13503 | 20408 | if (iter->ndev) /* p2p discovery iface is null */ |
---|
13504 | 20409 | wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev); |
---|
13505 | 20410 | } |
---|
13506 | | -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
13507 | | - 4 && __GNUC_MINOR__ >= 6)) |
---|
13508 | | -_Pragma("GCC diagnostic pop") |
---|
13509 | | -#endif |
---|
13510 | 20411 | |
---|
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(); |
---|
13527 | 20419 | for_each_ndev(cfg, iter, next) { |
---|
| 20420 | + GCC_DIAGNOSTIC_POP(); |
---|
13528 | 20421 | /* p2p discovery iface ndev ptr could be null */ |
---|
13529 | 20422 | if (iter->ndev == NULL) |
---|
13530 | 20423 | continue; |
---|
13531 | 20424 | #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 | + |
---|
13533 | 20437 | 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); |
---|
13534 | 20455 | } |
---|
13535 | 20456 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */ |
---|
13536 | 20457 | wl_clr_drv_status(cfg, READY, iter->ndev); |
---|
.. | .. |
---|
13541 | 20462 | wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev); |
---|
13542 | 20463 | wl_clr_drv_status(cfg, AP_CREATED, iter->ndev); |
---|
13543 | 20464 | 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); |
---|
13544 | 20467 | } |
---|
13545 | | -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
13546 | | - 4 && __GNUC_MINOR__ >= 6)) |
---|
13547 | | -_Pragma("GCC diagnostic pop") |
---|
13548 | | -#endif |
---|
13549 | 20468 | bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype = |
---|
13550 | 20469 | 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 */ |
---|
13552 | 20475 | if (p2p_net) |
---|
13553 | 20476 | dev_close(p2p_net); |
---|
13554 | | -#endif |
---|
| 20477 | +#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT)&& !PLATFORM_SLP */ |
---|
13555 | 20478 | |
---|
13556 | 20479 | /* 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 | + |
---|
13560 | 20486 | wl_flush_eq(cfg); |
---|
13561 | 20487 | wl_link_down(cfg); |
---|
13562 | 20488 | if (cfg->p2p_supported) { |
---|
.. | .. |
---|
13569 | 20495 | del_timer_sync(&cfg->scan_timeout); |
---|
13570 | 20496 | } |
---|
13571 | 20497 | |
---|
| 20498 | + wl_cfg80211_clear_mgmt_vndr_ies(cfg); |
---|
| 20499 | +#if defined(OEM_ANDROID) |
---|
13572 | 20500 | DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub)); |
---|
| 20501 | +#endif // endif |
---|
13573 | 20502 | |
---|
| 20503 | +#ifdef DHD_MONITOR_INTERFACE |
---|
13574 | 20504 | dhd_monitor_uninit(); |
---|
| 20505 | +#endif /* DHD_MONITOR_INTERFACE */ |
---|
| 20506 | + |
---|
13575 | 20507 | #ifdef WLAIBSS_MCHAN |
---|
13576 | 20508 | bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev); |
---|
13577 | 20509 | #endif /* WLAIBSS_MCHAN */ |
---|
13578 | 20510 | |
---|
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 | | - |
---|
13585 | 20511 | #ifdef WL11U |
---|
13586 | 20512 | /* Clear interworking element. */ |
---|
13587 | 20513 | if (cfg->wl11u) { |
---|
| 20514 | + wl_clear_iwdata(cfg); |
---|
13588 | 20515 | cfg->wl11u = FALSE; |
---|
13589 | | - cfg->iw_ie_len = 0; |
---|
13590 | | - memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN); |
---|
13591 | 20516 | } |
---|
13592 | 20517 | #endif /* WL11U */ |
---|
13593 | 20518 | |
---|
| 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; |
---|
13594 | 20526 | |
---|
13595 | 20527 | DNGL_FUNC(dhd_cfg80211_down, (cfg)); |
---|
13596 | 20528 | |
---|
.. | .. |
---|
13602 | 20534 | return err; |
---|
13603 | 20535 | } |
---|
13604 | 20536 | |
---|
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) |
---|
13606 | 20595 | { |
---|
13607 | 20596 | struct bcm_cfg80211 *cfg; |
---|
13608 | 20597 | s32 err = 0; |
---|
.. | .. |
---|
13614 | 20603 | s8 iovbuf[WLC_IOCTL_SMLEN]; |
---|
13615 | 20604 | #endif /* DISABLE_PM_BCNRX */ |
---|
13616 | 20605 | |
---|
13617 | | - (void)para; |
---|
13618 | 20606 | WL_DBG(("In\n")); |
---|
13619 | | - cfg = g_bcm_cfg; |
---|
| 20607 | + cfg = wl_get_cfg(net); |
---|
13620 | 20608 | |
---|
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)) { |
---|
13623 | 20611 | WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err)); |
---|
13624 | 20612 | return err; |
---|
13625 | 20613 | } |
---|
.. | .. |
---|
13641 | 20629 | return err; |
---|
13642 | 20630 | } |
---|
13643 | 20631 | } |
---|
| 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 */ |
---|
13644 | 20642 | err = __wl_cfg80211_up(cfg); |
---|
13645 | 20643 | if (unlikely(err)) |
---|
13646 | 20644 | WL_ERR(("__wl_cfg80211_up failed\n")); |
---|
13647 | 20645 | |
---|
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 */ |
---|
13649 | 20655 | |
---|
13650 | 20656 | /* IOVAR configurations with 'up' condition */ |
---|
13651 | 20657 | #ifdef DISABLE_PM_BCNRX |
---|
13652 | | - interr = wldev_iovar_setbuf(bcmcfg_to_prmry_ndev(cfg), "pm_bcnrx", |
---|
13653 | | - (char *)¶m, sizeof(param), iovbuf, sizeof(iovbuf), &cfg->ioctl_buf_sync); |
---|
| 20658 | + interr = wldev_iovar_setbuf(net, "pm_bcnrx", (char *)¶m, sizeof(param), iovbuf, |
---|
| 20659 | + sizeof(iovbuf), &cfg->ioctl_buf_sync); |
---|
13654 | 20660 | |
---|
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 | + } |
---|
13657 | 20664 | #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 */ |
---|
13658 | 20672 | |
---|
13659 | 20673 | mutex_unlock(&cfg->usr_sync); |
---|
13660 | 20674 | |
---|
13661 | 20675 | #ifdef WLAIBSS_MCHAN |
---|
13662 | 20676 | bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME); |
---|
13663 | 20677 | #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 | | - |
---|
13673 | 20678 | return err; |
---|
13674 | 20679 | } |
---|
13675 | 20680 | |
---|
13676 | 20681 | /* Private Event to Supplicant with indication that chip hangs */ |
---|
13677 | 20682 | int wl_cfg80211_hang(struct net_device *dev, u16 reason) |
---|
13678 | 20683 | { |
---|
13679 | | - struct bcm_cfg80211 *cfg; |
---|
| 20684 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
| 20685 | + dhd_pub_t *dhd; |
---|
13680 | 20686 | #if defined(SOFTAP_SEND_HANGEVT) |
---|
13681 | 20687 | /* specifc mac address used for hang event */ |
---|
13682 | 20688 | uint8 hang_mac[ETHER_ADDR_LEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11}; |
---|
13683 | | - dhd_pub_t *dhd; |
---|
13684 | 20689 | #endif /* SOFTAP_SEND_HANGEVT */ |
---|
13685 | | - if (!g_bcm_cfg) { |
---|
| 20690 | + if (!cfg) { |
---|
13686 | 20691 | return BCME_ERROR; |
---|
13687 | 20692 | } |
---|
13688 | 20693 | |
---|
13689 | | - cfg = g_bcm_cfg; |
---|
| 20694 | + RETURN_EIO_IF_NOT_UP(cfg); |
---|
13690 | 20695 | |
---|
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) |
---|
13694 | 20696 | 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 |
---|
13695 | 20718 | if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { |
---|
13696 | 20719 | cfg80211_del_sta(dev, hang_mac, GFP_ATOMIC); |
---|
13697 | 20720 | } else |
---|
13698 | 20721 | #endif /* SOFTAP_SEND_HANGEVT */ |
---|
13699 | 20722 | { |
---|
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 | + } |
---|
13701 | 20730 | } |
---|
13702 | 20731 | if (cfg != NULL) { |
---|
13703 | 20732 | wl_link_down(cfg); |
---|
.. | .. |
---|
13705 | 20734 | return 0; |
---|
13706 | 20735 | } |
---|
13707 | 20736 | |
---|
13708 | | -s32 wl_cfg80211_down(void *para) |
---|
| 20737 | +s32 wl_cfg80211_down(struct net_device *dev) |
---|
13709 | 20738 | { |
---|
13710 | | - struct bcm_cfg80211 *cfg; |
---|
13711 | | - s32 err = 0; |
---|
| 20739 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
| 20740 | + s32 err = BCME_ERROR; |
---|
13712 | 20741 | |
---|
13713 | | - (void)para; |
---|
13714 | 20742 | WL_DBG(("In\n")); |
---|
13715 | | - cfg = g_bcm_cfg; |
---|
13716 | 20743 | |
---|
13717 | 20744 | if (cfg) { |
---|
13718 | 20745 | mutex_lock(&cfg->usr_sync); |
---|
.. | .. |
---|
13723 | 20750 | return err; |
---|
13724 | 20751 | } |
---|
13725 | 20752 | |
---|
13726 | | -#if (defined(STBLINUX) && defined(WL_CFG80211)) |
---|
13727 | | -int wl_cfg80211_cleanup(void) |
---|
| 20753 | +void |
---|
| 20754 | +wl_cfg80211_sta_ifdown(struct net_device *dev) |
---|
13728 | 20755 | { |
---|
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); |
---|
13732 | 20757 | |
---|
13733 | | - if (!cfg) |
---|
13734 | | - return -EINVAL; |
---|
| 20758 | + WL_DBG(("In\n")); |
---|
13735 | 20759 | |
---|
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)) */ |
---|
13746 | 20769 | } |
---|
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; |
---|
13764 | 20770 | } |
---|
13765 | | -#endif /* STBLINUX && WL_CFG80211 */ |
---|
13766 | 20771 | |
---|
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) |
---|
13768 | 20773 | { |
---|
13769 | 20774 | unsigned long flags; |
---|
13770 | 20775 | void *rptr = NULL; |
---|
.. | .. |
---|
13772 | 20777 | |
---|
13773 | 20778 | if (!profile) |
---|
13774 | 20779 | return NULL; |
---|
13775 | | - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); |
---|
| 20780 | + WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags); |
---|
13776 | 20781 | switch (item) { |
---|
13777 | 20782 | case WL_PROF_SEC: |
---|
13778 | 20783 | rptr = &profile->sec; |
---|
.. | .. |
---|
13789 | 20794 | case WL_PROF_CHAN: |
---|
13790 | 20795 | rptr = &profile->channel; |
---|
13791 | 20796 | break; |
---|
| 20797 | + case WL_PROF_LATEST_BSSID: |
---|
| 20798 | + rptr = profile->latest_bssid; |
---|
| 20799 | + break; |
---|
13792 | 20800 | } |
---|
13793 | | - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); |
---|
| 20801 | + WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags); |
---|
13794 | 20802 | if (!rptr) |
---|
13795 | 20803 | WL_ERR(("invalid item (%d)\n", item)); |
---|
13796 | 20804 | return rptr; |
---|
.. | .. |
---|
13807 | 20815 | |
---|
13808 | 20816 | if (!profile) |
---|
13809 | 20817 | return WL_INVALID; |
---|
13810 | | - spin_lock_irqsave(&cfg->cfgdrv_lock, flags); |
---|
| 20818 | + WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags); |
---|
13811 | 20819 | switch (item) { |
---|
13812 | 20820 | case WL_PROF_SSID: |
---|
13813 | 20821 | ssid = (const wlc_ssid_t *) data; |
---|
13814 | | - memset(profile->ssid.SSID, 0, |
---|
| 20822 | + bzero(profile->ssid.SSID, |
---|
13815 | 20823 | 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); |
---|
13818 | 20826 | break; |
---|
13819 | 20827 | case WL_PROF_BSSID: |
---|
13820 | 20828 | if (data) |
---|
13821 | 20829 | memcpy(profile->bssid, data, ETHER_ADDR_LEN); |
---|
13822 | 20830 | else |
---|
13823 | | - memset(profile->bssid, 0, ETHER_ADDR_LEN); |
---|
| 20831 | + bzero(profile->bssid, ETHER_ADDR_LEN); |
---|
13824 | 20832 | break; |
---|
13825 | 20833 | case WL_PROF_SEC: |
---|
13826 | 20834 | memcpy(&profile->sec, data, sizeof(profile->sec)); |
---|
.. | .. |
---|
13837 | 20845 | case WL_PROF_CHAN: |
---|
13838 | 20846 | profile->channel = *(const u32*)data; |
---|
13839 | 20847 | 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; |
---|
13840 | 20857 | default: |
---|
13841 | 20858 | err = -EOPNOTSUPP; |
---|
13842 | 20859 | break; |
---|
13843 | 20860 | } |
---|
13844 | | - spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); |
---|
| 20861 | + WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags); |
---|
13845 | 20862 | |
---|
13846 | 20863 | if (err == -EOPNOTSUPP) |
---|
13847 | 20864 | WL_ERR(("unsupported item (%d)\n", item)); |
---|
.. | .. |
---|
13875 | 20892 | struct wl_ie *ie = wl_to_ie(cfg); |
---|
13876 | 20893 | |
---|
13877 | 20894 | ie->offset = 0; |
---|
| 20895 | + bzero(ie->buf, sizeof(ie->buf)); |
---|
13878 | 20896 | } |
---|
13879 | 20897 | |
---|
13880 | 20898 | static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v) |
---|
.. | .. |
---|
13894 | 20912 | return err; |
---|
13895 | 20913 | } |
---|
13896 | 20914 | |
---|
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) |
---|
13899 | 20917 | { |
---|
13900 | 20918 | 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; |
---|
13901 | 20921 | /* 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(); |
---|
13907 | 20924 | 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) { |
---|
13913 | 20935 | 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) { |
---|
13915 | 20946 | 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)); |
---|
13918 | 20949 | } |
---|
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, |
---|
13922 | 20959 | (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])); |
---|
13927 | 20967 | } |
---|
13928 | 20968 | return; |
---|
13929 | 20969 | } |
---|
13930 | 20970 | if (*(ssidie + 2) == '\0') |
---|
13931 | | - memcpy(ssidie + 2, bi->SSID, bi->SSID_len); |
---|
| 20971 | + memcpy(ssidie + 2, bi->SSID, ssid_len); |
---|
13932 | 20972 | return; |
---|
13933 | 20973 | } |
---|
13934 | 20974 | |
---|
.. | .. |
---|
13987 | 21027 | { |
---|
13988 | 21028 | unsigned long flags; |
---|
13989 | 21029 | |
---|
13990 | | - spin_lock_irqsave(&cfg->eq_lock, flags); |
---|
| 21030 | + WL_CFG_EQ_LOCK(&cfg->eq_lock, flags); |
---|
13991 | 21031 | return flags; |
---|
13992 | 21032 | } |
---|
13993 | 21033 | |
---|
13994 | 21034 | static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags) |
---|
13995 | 21035 | { |
---|
13996 | | - spin_unlock_irqrestore(&cfg->eq_lock, flags); |
---|
| 21036 | + WL_CFG_EQ_UNLOCK(&cfg->eq_lock, flags); |
---|
13997 | 21037 | } |
---|
13998 | 21038 | |
---|
13999 | 21039 | static void wl_init_eq_lock(struct bcm_cfg80211 *cfg) |
---|
.. | .. |
---|
14012 | 21052 | |
---|
14013 | 21053 | s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) |
---|
14014 | 21054 | { |
---|
14015 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 21055 | + struct bcm_cfg80211 *cfg = wl_get_cfg(net); |
---|
14016 | 21056 | struct ether_addr primary_mac; |
---|
14017 | 21057 | if (!cfg->p2p) |
---|
14018 | 21058 | return -1; |
---|
14019 | 21059 | if (!p2p_is_on(cfg)) { |
---|
14020 | 21060 | get_primary_mac(cfg, &primary_mac); |
---|
14021 | 21061 | wl_cfgp2p_generate_bss_mac(cfg, &primary_mac); |
---|
| 21062 | + memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN); |
---|
14022 | 21063 | } else { |
---|
14023 | 21064 | memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet, |
---|
14024 | 21065 | ETHER_ADDR_LEN); |
---|
.. | .. |
---|
14028 | 21069 | } |
---|
14029 | 21070 | s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) |
---|
14030 | 21071 | { |
---|
14031 | | - struct bcm_cfg80211 *cfg; |
---|
14032 | | - |
---|
14033 | | - cfg = g_bcm_cfg; |
---|
| 21072 | + struct bcm_cfg80211 *cfg = wl_get_cfg(net); |
---|
14034 | 21073 | |
---|
14035 | 21074 | return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len); |
---|
14036 | 21075 | } |
---|
14037 | 21076 | |
---|
14038 | 21077 | s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) |
---|
14039 | 21078 | { |
---|
14040 | | - struct bcm_cfg80211 *cfg; |
---|
14041 | | - cfg = g_bcm_cfg; |
---|
| 21079 | + struct bcm_cfg80211 *cfg = wl_get_cfg(net); |
---|
14042 | 21080 | |
---|
14043 | 21081 | return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len); |
---|
14044 | 21082 | } |
---|
14045 | 21083 | |
---|
14046 | 21084 | s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) |
---|
14047 | 21085 | { |
---|
14048 | | - struct bcm_cfg80211 *cfg; |
---|
14049 | | - cfg = g_bcm_cfg; |
---|
| 21086 | + struct bcm_cfg80211 *cfg = wl_get_cfg(net); |
---|
14050 | 21087 | |
---|
14051 | 21088 | return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len); |
---|
14052 | 21089 | } |
---|
14053 | 21090 | |
---|
14054 | 21091 | s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len) |
---|
14055 | 21092 | { |
---|
14056 | | - struct bcm_cfg80211 *cfg; |
---|
14057 | | - cfg = g_bcm_cfg; |
---|
| 21093 | + struct bcm_cfg80211 *cfg = wl_get_cfg(net); |
---|
14058 | 21094 | |
---|
14059 | 21095 | 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); |
---|
14060 | 21103 | } |
---|
14061 | 21104 | |
---|
14062 | 21105 | #ifdef P2PLISTEN_AP_SAMECHN |
---|
.. | .. |
---|
14068 | 21111 | /* disable PM for p2p responding on infra AP channel */ |
---|
14069 | 21112 | s32 pm = PM_OFF; |
---|
14070 | 21113 | |
---|
14071 | | - ret = wldev_ioctl(net, WLC_SET_PM, &pm, sizeof(pm), true); |
---|
| 21114 | + ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm)); |
---|
14072 | 21115 | } |
---|
14073 | 21116 | |
---|
14074 | 21117 | return ret; |
---|
.. | .. |
---|
14079 | 21122 | { |
---|
14080 | 21123 | int freq = 0; |
---|
14081 | 21124 | |
---|
14082 | | -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) |
---|
| 21125 | +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) |
---|
14083 | 21126 | freq = ieee80211_channel_to_frequency(channel); |
---|
14084 | 21127 | #else |
---|
14085 | 21128 | { |
---|
.. | .. |
---|
14090 | 21133 | band = IEEE80211_BAND_5GHZ; |
---|
14091 | 21134 | freq = ieee80211_channel_to_frequency(channel, band); |
---|
14092 | 21135 | } |
---|
14093 | | -#endif |
---|
| 21136 | +#endif // endif |
---|
14094 | 21137 | return freq; |
---|
14095 | 21138 | } |
---|
14096 | 21139 | |
---|
14097 | | - |
---|
14098 | 21140 | #ifdef WLTDLS |
---|
14099 | | -static s32 |
---|
| 21141 | +s32 |
---|
14100 | 21142 | wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, |
---|
14101 | 21143 | const wl_event_msg_t *e, void *data) { |
---|
14102 | 21144 | |
---|
.. | .. |
---|
14111 | 21153 | msg = " TDLS PEER DISCOVERD "; |
---|
14112 | 21154 | break; |
---|
14113 | 21155 | 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 */ |
---|
14117 | 21156 | if (cfg->tdls_mgmt_frame) { |
---|
14118 | 21157 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) |
---|
14119 | 21158 | 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); |
---|
14122 | 21160 | #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) |
---|
14123 | 21161 | 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); |
---|
14126 | 21164 | #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \ |
---|
14127 | | - defined(WL_COMPAT_WIRELESS) |
---|
| 21165 | + defined(WL_COMPAT_WIRELESS) |
---|
14128 | 21166 | 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); |
---|
14131 | 21169 | #else |
---|
14132 | 21170 | 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 */ |
---|
14136 | 21174 | } |
---|
14137 | 21175 | 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 */ |
---|
14138 | 21180 | break; |
---|
14139 | 21181 | 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 */ |
---|
14143 | 21182 | 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; |
---|
14146 | 21185 | cfg->tdls_mgmt_freq = 0; |
---|
14147 | 21186 | } |
---|
14148 | 21187 | 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 */ |
---|
14149 | 21192 | break; |
---|
14150 | 21193 | } |
---|
14151 | 21194 | 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)), |
---|
14153 | 21196 | (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary")); |
---|
14154 | 21197 | } |
---|
14155 | 21198 | return 0; |
---|
.. | .. |
---|
14157 | 21200 | } |
---|
14158 | 21201 | #endif /* WLTDLS */ |
---|
14159 | 21202 | |
---|
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) |
---|
14162 | 21204 | #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \ |
---|
14163 | 21205 | KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) |
---|
| 21206 | +static s32 |
---|
14164 | 21207 | 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) |
---|
14167 | 21210 | #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \ |
---|
14168 | 21211 | (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, |
---|
14170 | 21213 | 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) |
---|
14172 | 21215 | #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 |
---|
14173 | 21221 | 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 */ |
---|
14181 | 21225 | { |
---|
14182 | 21226 | s32 ret = 0; |
---|
14183 | | -#ifdef WLTDLS |
---|
| 21227 | +#if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS) |
---|
14184 | 21228 | struct bcm_cfg80211 *cfg; |
---|
14185 | 21229 | 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); |
---|
14188 | 21232 | |
---|
14189 | 21233 | #if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2) |
---|
14190 | 21234 | /* 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 | + */ |
---|
14193 | 21237 | BCM_REFERENCE(peer_capability); |
---|
14194 | 21238 | #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */ |
---|
14195 | 21239 | |
---|
14196 | 21240 | 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; |
---|
14224 | 21247 | |
---|
| 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 | + } |
---|
14225 | 21276 | 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); |
---|
14227 | 21278 | |
---|
14228 | 21279 | if (ret) { |
---|
14229 | 21280 | WL_ERR(("tdls_wfd_ie error %d\n", ret)); |
---|
14230 | 21281 | } |
---|
| 21282 | + |
---|
14231 | 21283 | out: |
---|
14232 | | -#endif /* WLTDLS */ |
---|
| 21284 | +#endif /* TDLS_MSG_ONLY_WFD && WLTDLS */ |
---|
14233 | 21285 | return ret; |
---|
14234 | 21286 | } |
---|
14235 | 21287 | |
---|
.. | .. |
---|
14241 | 21293 | static s32 |
---|
14242 | 21294 | wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
---|
14243 | 21295 | u8 *peer, enum nl80211_tdls_operation oper) |
---|
14244 | | -#endif |
---|
| 21296 | +#endif // endif |
---|
14245 | 21297 | { |
---|
14246 | 21298 | s32 ret = 0; |
---|
14247 | 21299 | #ifdef WLTDLS |
---|
14248 | | - struct bcm_cfg80211 *cfg; |
---|
| 21300 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
14249 | 21301 | tdls_iovar_t info; |
---|
14250 | 21302 | dhd_pub_t *dhdp; |
---|
14251 | 21303 | bool tdls_auto_mode = false; |
---|
14252 | | - cfg = g_bcm_cfg; |
---|
14253 | 21304 | dhdp = (dhd_pub_t *)(cfg->pub); |
---|
14254 | | - memset(&info, 0, sizeof(tdls_iovar_t)); |
---|
| 21305 | + bzero(&info, sizeof(tdls_iovar_t)); |
---|
14255 | 21306 | if (peer) { |
---|
14256 | 21307 | memcpy(&info.ea, peer, ETHER_ADDR_LEN); |
---|
14257 | 21308 | } else { |
---|
.. | .. |
---|
14264 | 21315 | */ |
---|
14265 | 21316 | if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) { |
---|
14266 | 21317 | 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")); |
---|
14268 | 21319 | } else { |
---|
14269 | 21320 | info.mode = TDLS_MANUAL_EP_DISCOVERY; |
---|
14270 | 21321 | } |
---|
.. | .. |
---|
14273 | 21324 | if (dhdp->tdls_mode == true) { |
---|
14274 | 21325 | info.mode = TDLS_MANUAL_EP_CREATE; |
---|
14275 | 21326 | 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); |
---|
14277 | 21329 | if (ret < 0) { |
---|
14278 | 21330 | return ret; |
---|
14279 | 21331 | } |
---|
.. | .. |
---|
14289 | 21341 | goto out; |
---|
14290 | 21342 | } |
---|
14291 | 21343 | /* 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); |
---|
14293 | 21345 | if (ret < 0) { |
---|
14294 | 21346 | return ret; |
---|
14295 | | - |
---|
14296 | 21347 | } |
---|
14297 | 21348 | if (info.mode) { |
---|
14298 | 21349 | ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info), |
---|
.. | .. |
---|
14302 | 21353 | } |
---|
14303 | 21354 | } |
---|
14304 | 21355 | out: |
---|
| 21356 | + if (ret) { |
---|
| 21357 | + wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL); |
---|
| 21358 | + return -ENOTSUPP; |
---|
| 21359 | + } |
---|
14305 | 21360 | #endif /* WLTDLS */ |
---|
14306 | 21361 | return ret; |
---|
14307 | 21362 | } |
---|
14308 | | -#endif |
---|
| 21363 | +#endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */ |
---|
14309 | 21364 | |
---|
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, |
---|
14311 | 21366 | enum wl_management_type type) |
---|
14312 | 21367 | { |
---|
14313 | 21368 | struct bcm_cfg80211 *cfg; |
---|
14314 | | - struct net_device *ndev = NULL; |
---|
14315 | | - struct ether_addr primary_mac; |
---|
14316 | 21369 | s32 ret = 0; |
---|
| 21370 | + struct ether_addr primary_mac; |
---|
14317 | 21371 | s32 bssidx = 0; |
---|
14318 | 21372 | s32 pktflag = 0; |
---|
14319 | | - cfg = g_bcm_cfg; |
---|
| 21373 | + cfg = wl_get_cfg(ndev); |
---|
14320 | 21374 | |
---|
14321 | | - if (wl_get_drv_status(cfg, AP_CREATING, net)) { |
---|
| 21375 | + if (wl_get_drv_status(cfg, AP_CREATING, ndev)) { |
---|
14322 | 21376 | /* Vendor IEs should be set to FW |
---|
14323 | 21377 | * after SoftAP interface is brought up |
---|
14324 | 21378 | */ |
---|
| 21379 | + WL_DBG(("Skipping set IE since AP is not up \n")); |
---|
14325 | 21380 | 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")); |
---|
14342 | 21391 | goto exit; |
---|
14343 | 21392 | } |
---|
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")); |
---|
14346 | 21406 | ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY); |
---|
14347 | 21407 | 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); |
---|
14352 | 21413 | } |
---|
| 21414 | + |
---|
14353 | 21415 | if (ndev != NULL) { |
---|
14354 | 21416 | switch (type) { |
---|
14355 | 21417 | case WL_BEACON: |
---|
.. | .. |
---|
14362 | 21424 | pktflag = VNDR_IE_ASSOCRSP_FLAG; |
---|
14363 | 21425 | break; |
---|
14364 | 21426 | } |
---|
14365 | | - if (pktflag) |
---|
| 21427 | + if (pktflag) { |
---|
14366 | 21428 | ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, |
---|
14367 | 21429 | ndev_to_cfgdev(ndev), bssidx, pktflag, buf, len); |
---|
| 21430 | + } |
---|
14368 | 21431 | } |
---|
14369 | 21432 | exit: |
---|
14370 | 21433 | return ret; |
---|
.. | .. |
---|
14376 | 21439 | { |
---|
14377 | 21440 | u32 val = 0; |
---|
14378 | 21441 | 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); |
---|
14392 | 21443 | /* Set interface up, explicitly. */ |
---|
14393 | 21444 | val = 1; |
---|
14394 | 21445 | |
---|
14395 | | - ret = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true); |
---|
| 21446 | + ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val)); |
---|
14396 | 21447 | if (ret < 0) { |
---|
14397 | 21448 | WL_ERR(("set interface up failed, error = %d\n", ret)); |
---|
14398 | 21449 | goto done; |
---|
.. | .. |
---|
14404 | 21455 | ret = BCME_OK; |
---|
14405 | 21456 | goto done; |
---|
14406 | 21457 | } |
---|
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); |
---|
14412 | 21460 | |
---|
14413 | 21461 | done: |
---|
14414 | 21462 | return ret; |
---|
14415 | 21463 | } |
---|
14416 | 21464 | |
---|
14417 | 21465 | static bool |
---|
14418 | | -wl_cfg80211_valid_channel_p2p(int channel) |
---|
| 21466 | +wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec) |
---|
14419 | 21467 | { |
---|
14420 | 21468 | bool valid = false; |
---|
| 21469 | + char chanbuf[CHANSPEC_STR_LEN]; |
---|
14421 | 21470 | |
---|
14422 | 21471 | /* channel 1 to 14 */ |
---|
14423 | | - if ((channel >= 1) && (channel <= 14)) { |
---|
| 21472 | + if ((chanspec >= 0x2b01) && (chanspec <= 0x2b0e)) { |
---|
14424 | 21473 | valid = true; |
---|
14425 | 21474 | } |
---|
| 21475 | +#ifdef IGUANA_LEGACY_CHIPS |
---|
14426 | 21476 | /* channel 36 to 48 */ |
---|
14427 | | - else if ((channel >= 36) && (channel <= 48)) { |
---|
| 21477 | + else if ((chanspec >= 0xd024) && (chanspec <= 0xd030)) { |
---|
14428 | 21478 | valid = true; |
---|
14429 | 21479 | } |
---|
14430 | 21480 | /* channel 149 to 161 */ |
---|
14431 | | - else if ((channel >= 149) && (channel <= 161)) { |
---|
| 21481 | + else if ((chanspec >= 0xd095) && (chanspec <= 0xd0a5)) { |
---|
14432 | 21482 | valid = true; |
---|
14433 | 21483 | } |
---|
| 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 */ |
---|
14434 | 21494 | else { |
---|
14435 | 21495 | 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))); |
---|
14437 | 21498 | } |
---|
14438 | 21499 | |
---|
14439 | 21500 | return valid; |
---|
.. | .. |
---|
14446 | 21507 | struct bcm_cfg80211 *cfg = NULL; |
---|
14447 | 21508 | chanspec_t chanspec = 0; |
---|
14448 | 21509 | |
---|
14449 | | - cfg = g_bcm_cfg; |
---|
| 21510 | + cfg = wl_get_cfg(ndev); |
---|
14450 | 21511 | |
---|
14451 | 21512 | /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */ |
---|
14452 | 21513 | chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 | |
---|
.. | .. |
---|
14469 | 21530 | s32 ret = BCME_ERROR; |
---|
14470 | 21531 | s32 i = 0; |
---|
14471 | 21532 | s32 j = 0; |
---|
14472 | | - struct bcm_cfg80211 *cfg = NULL; |
---|
| 21533 | + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); |
---|
14473 | 21534 | wl_uint32_list_t *list = NULL; |
---|
14474 | 21535 | chanspec_t chanspec = 0; |
---|
14475 | | - |
---|
14476 | | - cfg = g_bcm_cfg; |
---|
14477 | 21536 | |
---|
14478 | 21537 | /* Restrict channels to 5GHz, 20MHz BW, no SB. */ |
---|
14479 | 21538 | chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 | |
---|
.. | .. |
---|
14500 | 21559 | } |
---|
14501 | 21560 | |
---|
14502 | 21561 | if (CHANNEL_IS_RADAR(channel) || |
---|
14503 | | - !(wl_cfg80211_valid_channel_p2p(CHSPEC_CHANNEL(chanspec)))) { |
---|
| 21562 | + !(wl_cfg80211_valid_chanspec_p2p(chanspec))) { |
---|
14504 | 21563 | continue; |
---|
14505 | 21564 | } else { |
---|
14506 | 21565 | list->element[j] = list->element[i]; |
---|
.. | .. |
---|
14524 | 21583 | int retry = 0; |
---|
14525 | 21584 | |
---|
14526 | 21585 | /* 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); |
---|
14528 | 21587 | if (ret < 0) { |
---|
14529 | 21588 | WL_ERR(("can't start auto channel scan, error = %d\n", ret)); |
---|
14530 | 21589 | *channel = 0; |
---|
.. | .. |
---|
14536 | 21595 | |
---|
14537 | 21596 | while (retry--) { |
---|
14538 | 21597 | OSL_SLEEP(CHAN_SEL_IOCTL_DELAY); |
---|
14539 | | - |
---|
14540 | 21598 | 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)); |
---|
14543 | 21600 | if ((ret == 0) && (dtoh32(chosen) != 0)) { |
---|
14544 | 21601 | *channel = (u16)(chosen & 0x00FF); |
---|
14545 | | - WL_INFORM(("selected channel = %d\n", *channel)); |
---|
| 21602 | + WL_INFORM_MEM(("selected channel = %d\n", *channel)); |
---|
14546 | 21603 | break; |
---|
14547 | 21604 | } |
---|
14548 | | - WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n", |
---|
| 21605 | + WL_DBG(("attempt = %d, ret = %d, chosen = %d\n", |
---|
14549 | 21606 | (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen))); |
---|
14550 | 21607 | } |
---|
14551 | 21608 | |
---|
.. | .. |
---|
14562 | 21619 | static s32 |
---|
14563 | 21620 | wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev) |
---|
14564 | 21621 | { |
---|
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); |
---|
14569 | 21623 | /* Clear scan stop driver status. */ |
---|
14570 | 21624 | wl_clr_drv_status(cfg, SCANNING, ndev); |
---|
14571 | 21625 | |
---|
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; |
---|
14583 | 21627 | } |
---|
14584 | 21628 | |
---|
14585 | 21629 | s32 |
---|
.. | .. |
---|
14592 | 21636 | struct bcm_cfg80211 *cfg = NULL; |
---|
14593 | 21637 | struct net_device *ndev = NULL; |
---|
14594 | 21638 | |
---|
14595 | | - memset(cmd, 0, total_len); |
---|
| 21639 | + bzero(cmd, total_len); |
---|
| 21640 | + cfg = wl_get_cfg(dev); |
---|
14596 | 21641 | |
---|
14597 | | - buf = kzalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL); |
---|
| 21642 | + buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE); |
---|
14598 | 21643 | if (buf == NULL) { |
---|
14599 | 21644 | WL_ERR(("failed to allocate chanspec buffer\n")); |
---|
14600 | 21645 | return -ENOMEM; |
---|
.. | .. |
---|
14604 | 21649 | * Always use primary interface, irrespective of interface on which |
---|
14605 | 21650 | * command came. |
---|
14606 | 21651 | */ |
---|
14607 | | - cfg = g_bcm_cfg; |
---|
14608 | 21652 | ndev = bcmcfg_to_prmry_ndev(cfg); |
---|
14609 | 21653 | |
---|
14610 | 21654 | /* |
---|
.. | .. |
---|
14661 | 21705 | channel = 0; |
---|
14662 | 21706 | } |
---|
14663 | 21707 | |
---|
14664 | | - pos += snprintf(pos, total_len, "%04d ", channel); |
---|
| 21708 | + pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel); |
---|
14665 | 21709 | |
---|
14666 | 21710 | /* 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); |
---|
14668 | 21712 | |
---|
14669 | 21713 | done: |
---|
14670 | 21714 | if (NULL != buf) { |
---|
14671 | | - kfree(buf); |
---|
| 21715 | + MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE); |
---|
14672 | 21716 | } |
---|
14673 | 21717 | |
---|
14674 | 21718 | /* Restore FW and driver back to normal state. */ |
---|
.. | .. |
---|
14747 | 21791 | wl_debuglevel_write(struct file *file, const char __user *userbuf, |
---|
14748 | 21792 | size_t count, loff_t *ppos) |
---|
14749 | 21793 | { |
---|
14750 | | - char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL]; |
---|
| 21794 | + char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)], sublog[SUBLOGLEVELZ]; |
---|
14751 | 21795 | char *params, *token, *colon; |
---|
14752 | 21796 | 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); |
---|
14757 | 21798 | |
---|
| 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'; |
---|
14758 | 21806 | params = &tbuf[0]; |
---|
14759 | 21807 | colon = strchr(params, '\n'); |
---|
14760 | 21808 | if (colon != NULL) |
---|
14761 | 21809 | *colon = '\0'; |
---|
14762 | 21810 | while ((token = strsep(¶ms, " ")) != NULL) { |
---|
14763 | | - memset(sublog, 0, sizeof(sublog)); |
---|
| 21811 | + bzero(sublog, sizeof(sublog)); |
---|
14764 | 21812 | if (token == NULL || !*token) |
---|
14765 | 21813 | break; |
---|
14766 | 21814 | if (*token == '\0') |
---|
.. | .. |
---|
14769 | 21817 | if (colon != NULL) { |
---|
14770 | 21818 | *colon = ' '; |
---|
14771 | 21819 | } |
---|
14772 | | - tokens = sscanf(token, "%s %u", sublog, &log_on); |
---|
| 21820 | + tokens = sscanf(token, "%"S(SUBLOGLEVEL)"s %u", sublog, &log_on); |
---|
14773 | 21821 | if (colon != NULL) |
---|
14774 | 21822 | *colon = ':'; |
---|
14775 | 21823 | |
---|
.. | .. |
---|
14790 | 21838 | "SUBMODULE:LEVEL (%d tokens)\n", |
---|
14791 | 21839 | tbuf, token, tokens)); |
---|
14792 | 21840 | |
---|
14793 | | - |
---|
14794 | 21841 | } |
---|
14795 | 21842 | return count; |
---|
14796 | 21843 | } |
---|
.. | .. |
---|
14800 | 21847 | size_t count, loff_t *ppos) |
---|
14801 | 21848 | { |
---|
14802 | 21849 | char *param; |
---|
14803 | | - char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)]; |
---|
| 21850 | + char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)]; |
---|
14804 | 21851 | uint i; |
---|
14805 | | - memset(tbuf, 0, sizeof(tbuf)); |
---|
| 21852 | + bzero(tbuf, sizeof(tbuf)); |
---|
14806 | 21853 | param = &tbuf[0]; |
---|
14807 | 21854 | for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { |
---|
14808 | 21855 | param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ", |
---|
.. | .. |
---|
14857 | 21904 | } |
---|
14858 | 21905 | #endif /* DEBUGFS_CFG80211 */ |
---|
14859 | 21906 | |
---|
| 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 | + |
---|
14860 | 21917 | struct device *wl_cfg80211_get_parent_dev(void) |
---|
14861 | 21918 | { |
---|
14862 | 21919 | return cfg80211_parent_dev; |
---|
.. | .. |
---|
14874 | 21931 | |
---|
14875 | 21932 | void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac) |
---|
14876 | 21933 | { |
---|
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 | + } |
---|
14880 | 21943 | } |
---|
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) |
---|
14882 | 21945 | { |
---|
14883 | 21946 | 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)) |
---|
14888 | 21949 | { |
---|
14889 | 21950 | WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode)); |
---|
14890 | 21951 | return false; |
---|
.. | .. |
---|
14928 | 21989 | } |
---|
14929 | 21990 | #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */ |
---|
14930 | 21991 | |
---|
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) |
---|
14934 | 21995 | { |
---|
14935 | | - bcm_tlv_t *ie; |
---|
| 21996 | + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); |
---|
| 21997 | + int ret = 0; |
---|
| 21998 | + char ioctl_buf[50]; |
---|
14936 | 21999 | |
---|
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; |
---|
14939 | 22003 | } |
---|
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; |
---|
14941 | 22015 | } |
---|
| 22016 | +#endif /* WL_HOST_BAND_MGMT */ |
---|
14942 | 22017 | |
---|
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) |
---|
14947 | 22020 | { |
---|
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]; |
---|
14952 | 22024 | |
---|
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; |
---|
14963 | 22028 | } |
---|
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 | + } |
---|
14974 | 22050 | } |
---|
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 | + } |
---|
14980 | 22061 | } |
---|
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; |
---|
15024 | 22063 | } |
---|
15025 | | -#endif /* WL11U */ |
---|
15026 | 22064 | |
---|
15027 | 22065 | s32 |
---|
15028 | 22066 | wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int total_len) |
---|
15029 | 22067 | { |
---|
15030 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
15031 | | - char ioctl_buf[50]; |
---|
| 22068 | + char ioctl_buf[WLC_IOCTL_SMLEN]; |
---|
15032 | 22069 | int err = 0; |
---|
15033 | 22070 | uint32 val = 0; |
---|
15034 | 22071 | chanspec_t chanspec = 0; |
---|
15035 | 22072 | int abort; |
---|
15036 | 22073 | int bytes_written = 0; |
---|
15037 | | - wl_dfs_ap_move_status_t *status; |
---|
| 22074 | + struct wl_dfs_ap_move_status_v2 *status; |
---|
15038 | 22075 | char chanbuf[CHANSPEC_STR_LEN]; |
---|
15039 | 22076 | const char *dfs_state_str[DFS_SCAN_S_MAX] = { |
---|
15040 | 22077 | "Radar Free On Channel", |
---|
.. | .. |
---|
15044 | 22081 | "RSDB Mode switch in Progress For Scan" |
---|
15045 | 22082 | }; |
---|
15046 | 22083 | 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"); |
---|
15048 | 22085 | return bytes_written; |
---|
15049 | 22086 | } |
---|
15050 | 22087 | if (!*data) { |
---|
15051 | 22088 | 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))) { |
---|
15053 | 22090 | WL_ERR(("setting dfs_ap_move failed with err=%d \n", err)); |
---|
15054 | 22091 | return err; |
---|
15055 | 22092 | } |
---|
15056 | | - status = (wl_dfs_ap_move_status_t *)cfg->ioctl_buf; |
---|
| 22093 | + status = (struct wl_dfs_ap_move_status_v2 *)ioctl_buf; |
---|
15057 | 22094 | |
---|
15058 | 22095 | if (status->version != WL_DFS_AP_MOVE_VERSION) { |
---|
15059 | 22096 | err = BCME_UNSUPPORTED; |
---|
.. | .. |
---|
15068 | 22105 | bytes_written = snprintf(command, total_len, |
---|
15069 | 22106 | "AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec); |
---|
15070 | 22107 | } |
---|
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]); |
---|
15073 | 22111 | return bytes_written; |
---|
15074 | 22112 | } else { |
---|
15075 | 22113 | bytes_written = snprintf(command, total_len, "dfs AP move in IDLE state\n"); |
---|
15076 | 22114 | return bytes_written; |
---|
15077 | 22115 | } |
---|
15078 | | - |
---|
15079 | 22116 | } |
---|
15080 | 22117 | |
---|
15081 | 22118 | abort = bcm_atoi(data); |
---|
.. | .. |
---|
15104 | 22141 | return err; |
---|
15105 | 22142 | } |
---|
15106 | 22143 | |
---|
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) |
---|
15109 | 22145 | { |
---|
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; |
---|
15130 | 22149 | } else { |
---|
15131 | | - err = snprintf(command, total_len, "Missing band\n"); |
---|
15132 | | - goto exit; |
---|
| 22150 | + return false; |
---|
15133 | 22151 | } |
---|
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; |
---|
15220 | 22152 | } |
---|
15221 | 22153 | |
---|
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) |
---|
15224 | 22155 | { |
---|
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); |
---|
15548 | 22157 | |
---|
15549 | 22158 | return cfg->pub; |
---|
15550 | 22159 | } |
---|
15551 | 22160 | |
---|
15552 | | -bool wl_cfg80211_is_p2p_active(void) |
---|
| 22161 | +bool wl_cfg80211_is_p2p_active(struct net_device *dev) |
---|
15553 | 22162 | { |
---|
15554 | | - return (g_bcm_cfg && g_bcm_cfg->p2p); |
---|
| 22163 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
| 22164 | + return (cfg && cfg->p2p); |
---|
15555 | 22165 | } |
---|
15556 | 22166 | |
---|
15557 | | -bool wl_cfg80211_is_roam_offload(void) |
---|
| 22167 | +bool wl_cfg80211_is_roam_offload(struct net_device * dev) |
---|
15558 | 22168 | { |
---|
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); |
---|
15560 | 22171 | } |
---|
15561 | 22172 | |
---|
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) |
---|
15563 | 22175 | { |
---|
15564 | | - dhd_pub_t *dhd = NULL; |
---|
15565 | | - struct net_device *ndev = NULL; |
---|
15566 | 22176 | u8 *curbssid = NULL; |
---|
| 22177 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
15567 | 22178 | |
---|
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; |
---|
15572 | 22184 | } |
---|
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); |
---|
15579 | 22186 | |
---|
15580 | 22187 | if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) { |
---|
15581 | 22188 | return true; |
---|
.. | .. |
---|
15591 | 22198 | s32 pm = PM_FAST; |
---|
15592 | 22199 | BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work); |
---|
15593 | 22200 | 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; |
---|
15603 | 22210 | 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); |
---|
15620 | 22221 | } |
---|
15621 | 22222 | } |
---|
15622 | | -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
15623 | | - 4 && __GNUC_MINOR__ >= 6)) |
---|
15624 | | -_Pragma("GCC diagnostic pop") |
---|
15625 | | -#endif |
---|
15626 | 22223 | } |
---|
| 22224 | +#if defined(OEM_ANDROID) |
---|
| 22225 | + DHD_PM_WAKE_UNLOCK(cfg->pub); |
---|
| 22226 | +#endif /* BCMDONGLEHOST && OEM_ANDROID */ |
---|
15627 | 22227 | } |
---|
| 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 |
---|
15628 | 22241 | |
---|
15629 | 22242 | u8 |
---|
15630 | 22243 | wl_get_action_category(void *frame, u32 frame_len) |
---|
.. | .. |
---|
15636 | 22249 | if (frame_len < DOT11_ACTION_HDR_LEN) |
---|
15637 | 22250 | return DOT11_ACTION_CAT_ERR_MASK; |
---|
15638 | 22251 | category = ptr[DOT11_ACTION_CAT_OFF]; |
---|
15639 | | - WL_INFORM(("Action Category: %d\n", category)); |
---|
| 22252 | + WL_DBG(("Action Category: %d\n", category)); |
---|
15640 | 22253 | return category; |
---|
15641 | 22254 | } |
---|
15642 | 22255 | |
---|
.. | .. |
---|
15651 | 22264 | if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len)) |
---|
15652 | 22265 | return BCME_ERROR; |
---|
15653 | 22266 | *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)); |
---|
15655 | 22268 | return BCME_OK; |
---|
15656 | 22269 | } |
---|
15657 | 22270 | |
---|
15658 | 22271 | #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) |
---|
15661 | 22274 | { |
---|
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; |
---|
15663 | 22292 | } |
---|
15664 | 22293 | #endif /* WLFBT */ |
---|
15665 | 22294 | |
---|
.. | .. |
---|
15671 | 22300 | wl_event_msg_t e; |
---|
15672 | 22301 | |
---|
15673 | 22302 | bzero(&e, sizeof(e)); |
---|
15674 | | - e.event_type = cpu_to_be32(WLC_E_BSSID); |
---|
| 22303 | + e.event_type = cpu_to_be32(WLC_E_ROAM); |
---|
15675 | 22304 | memcpy(&e.addr, bssid, ETHER_ADDR_LEN); |
---|
15676 | 22305 | /* trigger the roam event handler */ |
---|
15677 | | - WL_INFORM(("Delayed roam to " MACDBG "\n", MAC2STRDBG((u8*)(bssid)))); |
---|
15678 | 22306 | err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL); |
---|
15679 | 22307 | |
---|
15680 | 22308 | return err; |
---|
15681 | 22309 | } |
---|
15682 | 22310 | |
---|
15683 | 22311 | static s32 |
---|
15684 | | -wl_cfg80211_parse_vndr_ies(u8 *parse, u32 len, |
---|
| 22312 | +wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len, |
---|
15685 | 22313 | struct parsed_vndr_ies *vndr_ies) |
---|
15686 | 22314 | { |
---|
15687 | 22315 | 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; |
---|
15690 | 22318 | struct parsed_vndr_ie_info *parsed_info; |
---|
15691 | 22319 | u32 count = 0; |
---|
15692 | | - s32 remained_len; |
---|
| 22320 | + u32 remained_len; |
---|
15693 | 22321 | |
---|
15694 | | - remained_len = (s32)len; |
---|
15695 | | - memset(vndr_ies, 0, sizeof(*vndr_ies)); |
---|
| 22322 | + remained_len = len; |
---|
| 22323 | + bzero(vndr_ies, sizeof(*vndr_ies)); |
---|
15696 | 22324 | |
---|
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; |
---|
15699 | 22327 | if (!bcm_valid_tlv(ie, remained_len)) |
---|
15700 | 22328 | ie = NULL; |
---|
15701 | 22329 | while (ie) { |
---|
15702 | 22330 | if (count >= MAX_VNDR_IE_NUMBER) |
---|
15703 | 22331 | 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 | + } |
---|
15718 | 22371 | } |
---|
15719 | 22372 | |
---|
15720 | 22373 | parsed_info = &vndr_ies->ie_info[count++]; |
---|
15721 | 22374 | |
---|
15722 | 22375 | /* save vndr ie information */ |
---|
15723 | | - parsed_info->ie_ptr = (char *)vndrie; |
---|
| 22376 | + parsed_info->ie_ptr = (const char *)vndrie; |
---|
15724 | 22377 | parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN); |
---|
15725 | 22378 | memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t)); |
---|
15726 | 22379 | 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 | + } |
---|
15731 | 22388 | } |
---|
15732 | 22389 | end: |
---|
15733 | 22390 | ie = bcm_next_tlv(ie, &remained_len); |
---|
.. | .. |
---|
15735 | 22392 | return err; |
---|
15736 | 22393 | } |
---|
15737 | 22394 | |
---|
| 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 | + |
---|
15738 | 22570 | 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) |
---|
15740 | 22572 | { |
---|
15741 | 22573 | s32 index; |
---|
| 22574 | + s32 ret; |
---|
15742 | 22575 | struct net_info *netinfo; |
---|
15743 | 22576 | s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, |
---|
15744 | 22577 | VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG}; |
---|
15745 | 22578 | |
---|
15746 | | - netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx); |
---|
| 22579 | + netinfo = wl_get_netinfo_by_wdev(cfg, wdev); |
---|
15747 | 22580 | if (!netinfo || !netinfo->wdev) { |
---|
15748 | 22581 | WL_ERR(("netinfo or netinfo->wdev is NULL\n")); |
---|
15749 | 22582 | return -1; |
---|
15750 | 22583 | } |
---|
15751 | 22584 | |
---|
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)); |
---|
15753 | 22586 | /* Clear the IEs set in the firmware so that host is in sync with firmware */ |
---|
15754 | 22587 | 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 | + } |
---|
15758 | 22593 | } |
---|
15759 | 22594 | |
---|
15760 | 22595 | return 0; |
---|
.. | .. |
---|
15766 | 22601 | struct net_info *iter, *next; |
---|
15767 | 22602 | |
---|
15768 | 22603 | 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(); |
---|
15774 | 22605 | 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); |
---|
15776 | 22608 | } |
---|
15777 | | -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
15778 | | - 4 && __GNUC_MINOR__ >= 6)) |
---|
15779 | | -_Pragma("GCC diagnostic pop") |
---|
15780 | | -#endif |
---|
15781 | 22609 | return 0; |
---|
15782 | 22610 | } |
---|
15783 | 22611 | |
---|
.. | .. |
---|
15803 | 22631 | s32 remained_buf_len; |
---|
15804 | 22632 | wl_bss_vndr_ies_t *ies = NULL; |
---|
15805 | 22633 | 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; |
---|
15809 | 22635 | |
---|
15810 | 22636 | ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); |
---|
| 22637 | + wdev = cfgdev_to_wdev(cfgdev); |
---|
15811 | 22638 | |
---|
15812 | 22639 | if (bssidx > WL_MAX_IFS) { |
---|
15813 | 22640 | WL_ERR(("bssidx > supported concurrent Ifaces \n")); |
---|
15814 | 22641 | return -EINVAL; |
---|
15815 | 22642 | } |
---|
15816 | 22643 | |
---|
15817 | | - netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx); |
---|
| 22644 | + netinfo = wl_get_netinfo_by_wdev(cfg, wdev); |
---|
15818 | 22645 | if (!netinfo) { |
---|
15819 | 22646 | WL_ERR(("net_info ptr is NULL \n")); |
---|
15820 | 22647 | return -EINVAL; |
---|
15821 | 22648 | } |
---|
15822 | 22649 | |
---|
15823 | 22650 | /* 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)); |
---|
15825 | 22652 | curr_ie_buf = g_mgmt_ie_buf; |
---|
15826 | 22653 | 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)); |
---|
15827 | 22657 | |
---|
15828 | 22658 | switch (pktflag) { |
---|
15829 | 22659 | case VNDR_IE_PRBRSP_FLAG : |
---|
.. | .. |
---|
15851 | 22681 | mgmt_ie_len = &ies->assoc_req_ie_len; |
---|
15852 | 22682 | mgmt_ie_buf_len = sizeof(ies->assoc_req_ie); |
---|
15853 | 22683 | 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; |
---|
15854 | 22689 | default: |
---|
15855 | 22690 | mgmt_ie_buf = NULL; |
---|
15856 | 22691 | mgmt_ie_len = NULL; |
---|
.. | .. |
---|
15865 | 22700 | /* parse and save new vndr_ie in curr_ie_buff before comparing it */ |
---|
15866 | 22701 | if (vndr_ie && vndr_ie_len && curr_ie_buf) { |
---|
15867 | 22702 | 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) { |
---|
15878 | 22706 | WL_ERR(("parse vndr ie failed \n")); |
---|
15879 | 22707 | goto exit; |
---|
15880 | 22708 | } |
---|
15881 | | -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ |
---|
15882 | | - 4 && __GNUC_MINOR__ >= 6)) |
---|
15883 | | -_Pragma("GCC diagnostic pop") |
---|
15884 | | -#endif |
---|
| 22709 | + |
---|
15885 | 22710 | for (i = 0; i < new_vndr_ies.count; i++) { |
---|
15886 | 22711 | struct parsed_vndr_ie_info *vndrie_info = |
---|
15887 | 22712 | &new_vndr_ies.ie_info[i]; |
---|
.. | .. |
---|
15902 | 22727 | if (mgmt_ie_buf != NULL) { |
---|
15903 | 22728 | if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && |
---|
15904 | 22729 | (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")); |
---|
15906 | 22731 | goto exit; |
---|
15907 | 22732 | } |
---|
15908 | 22733 | |
---|
.. | .. |
---|
15916 | 22741 | for (i = 0; i < old_vndr_ies.count; i++) { |
---|
15917 | 22742 | struct parsed_vndr_ie_info *vndrie_info = |
---|
15918 | 22743 | &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 */ |
---|
15919 | 22759 | |
---|
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 | + } |
---|
15924 | 22769 | |
---|
15925 | 22770 | del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, |
---|
15926 | 22771 | pktflag, vndrie_info->vndrie.oui, |
---|
.. | .. |
---|
15945 | 22790 | for (i = 0; i < new_vndr_ies.count; i++) { |
---|
15946 | 22791 | struct parsed_vndr_ie_info *vndrie_info = |
---|
15947 | 22792 | &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 | + } |
---|
15954 | 22818 | |
---|
15955 | 22819 | del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf, |
---|
15956 | 22820 | pktflag, vndrie_info->vndrie.oui, |
---|
.. | .. |
---|
16003 | 22867 | int macnum = 0; |
---|
16004 | 22868 | int macmode = MACLIST_MODE_DISABLED; |
---|
16005 | 22869 | struct maclist *list; |
---|
| 22870 | + struct bcm_cfg80211 *cfg = wl_get_cfg(cfgdev); |
---|
16006 | 22871 | |
---|
16007 | 22872 | /* get the MAC filter mode */ |
---|
16008 | 22873 | if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) { |
---|
.. | .. |
---|
16015 | 22880 | /* if acl == NULL, macmode is still disabled.. */ |
---|
16016 | 22881 | if (macmode == MACLIST_MODE_DISABLED) { |
---|
16017 | 22882 | 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)); |
---|
16019 | 22885 | |
---|
16020 | 22886 | return ret; |
---|
16021 | 22887 | } |
---|
16022 | 22888 | |
---|
16023 | 22889 | macnum = acl->n_acl_entries; |
---|
16024 | 22890 | 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)); |
---|
16027 | 22893 | return -1; |
---|
16028 | 22894 | } |
---|
16029 | 22895 | |
---|
16030 | 22896 | /* 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); |
---|
16033 | 22899 | 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")); |
---|
16035 | 22901 | return -1; |
---|
16036 | 22902 | } |
---|
16037 | 22903 | |
---|
.. | .. |
---|
16042 | 22908 | } |
---|
16043 | 22909 | /* set the list */ |
---|
16044 | 22910 | 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)); |
---|
16046 | 22912 | |
---|
16047 | | - kfree(list); |
---|
| 22913 | + MFREE(cfg->osh, list, sizeof(int) + |
---|
| 22914 | + sizeof(struct ether_addr) * macnum); |
---|
16048 | 22915 | |
---|
16049 | 22916 | return ret; |
---|
16050 | 22917 | } |
---|
.. | .. |
---|
16055 | 22922 | struct cfg80211_chan_def *chandef, |
---|
16056 | 22923 | #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ |
---|
16057 | 22924 | \ |
---|
16058 | | - \ |
---|
16059 | | - \ |
---|
16060 | 22925 | 0))) |
---|
16061 | 22926 | struct chan_info *chaninfo, |
---|
16062 | 22927 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */ |
---|
16063 | | -struct wiphy *wiphy) |
---|
16064 | | - |
---|
| 22928 | + struct wiphy *wiphy) |
---|
16065 | 22929 | { |
---|
16066 | 22930 | uint16 freq = 0; |
---|
16067 | 22931 | int chan_type = 0; |
---|
16068 | 22932 | int channel = 0; |
---|
| 22933 | + struct ieee80211_channel *chan; |
---|
16069 | 22934 | |
---|
16070 | 22935 | if (!chandef) { |
---|
16071 | 22936 | return -1; |
---|
.. | .. |
---|
16080 | 22945 | { |
---|
16081 | 22946 | if (CHSPEC_SB_UPPER(chanspec)) { |
---|
16082 | 22947 | channel += CH_10MHZ_APART; |
---|
| 22948 | + chan_type = NL80211_CHAN_HT40MINUS; |
---|
16083 | 22949 | } else { |
---|
16084 | 22950 | channel -= CH_10MHZ_APART; |
---|
| 22951 | + chan_type = NL80211_CHAN_HT40PLUS; |
---|
16085 | 22952 | } |
---|
16086 | 22953 | } |
---|
16087 | | - chan_type = NL80211_CHAN_HT40PLUS; |
---|
16088 | 22954 | break; |
---|
16089 | 22955 | |
---|
16090 | 22956 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) |
---|
.. | .. |
---|
16104 | 22970 | channel += (CH_10MHZ_APART + CH_20MHZ_APART); |
---|
16105 | 22971 | } |
---|
16106 | 22972 | |
---|
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) |
---|
16108 | 22974 | 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) |
---|
16110 | 22976 | chan_type = NL80211_CHAN_HT40PLUS; |
---|
16111 | 22977 | } |
---|
16112 | 22978 | break; |
---|
.. | .. |
---|
16122 | 22988 | else |
---|
16123 | 22989 | freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); |
---|
16124 | 22990 | |
---|
| 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 | + |
---|
16125 | 23002 | #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); |
---|
16127 | 23004 | #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ |
---|
16128 | | - \ |
---|
16129 | | - \ |
---|
16130 | 23005 | \ |
---|
16131 | 23006 | 0))) |
---|
16132 | 23007 | chaninfo->freq = freq; |
---|
.. | .. |
---|
16143 | 23018 | struct cfg80211_chan_def chandef; |
---|
16144 | 23019 | #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ |
---|
16145 | 23020 | \ |
---|
16146 | | - \ |
---|
16147 | | - \ |
---|
16148 | 23021 | 0))) |
---|
16149 | 23022 | struct chan_info chaninfo; |
---|
16150 | 23023 | #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 |
---|
16151 | 23027 | |
---|
16152 | 23028 | if (!wiphy) { |
---|
16153 | 23029 | WL_ERR(("wiphy is null\n")); |
---|
16154 | 23030 | return; |
---|
16155 | 23031 | } |
---|
| 23032 | +#if (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) |
---|
16156 | 23033 | /* Channel switch support is only for AP/GO/ADHOC/MESH */ |
---|
16157 | 23034 | if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION || |
---|
16158 | 23035 | dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) { |
---|
16159 | 23036 | WL_ERR(("No channel switch notify support for STA/GC\n")); |
---|
16160 | 23037 | return; |
---|
16161 | 23038 | } |
---|
| 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 |
---|
16162 | 23048 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) |
---|
16163 | 23049 | if (wl_chspec_chandef(chanspec, &chandef, wiphy)) { |
---|
16164 | 23050 | #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ |
---|
16165 | | - \ |
---|
16166 | | - \ |
---|
16167 | 23051 | \ |
---|
16168 | 23052 | 0))) |
---|
16169 | 23053 | if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) { |
---|
.. | .. |
---|
16177 | 23061 | cfg80211_ch_switch_notify(dev, &chandef); |
---|
16178 | 23062 | #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \ |
---|
16179 | 23063 | \ |
---|
16180 | | - \ |
---|
16181 | | - \ |
---|
16182 | 23064 | 0))) |
---|
16183 | 23065 | freq = chan_info.freq; |
---|
16184 | 23066 | cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type); |
---|
.. | .. |
---|
16189 | 23071 | } |
---|
16190 | 23072 | #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */ |
---|
16191 | 23073 | |
---|
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) |
---|
16195 | 23078 | { |
---|
16196 | | - int ret; |
---|
16197 | | - int cur_mode; |
---|
| 23079 | + u32 channel = LCHSPEC_CHANNEL(chanspec); |
---|
16198 | 23080 | |
---|
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. |
---|
16208 | 23087 | */ |
---|
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; |
---|
16290 | 23092 | } |
---|
16291 | 23093 | } |
---|
16292 | 23094 | |
---|
16293 | 23095 | 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) |
---|
16295 | 23098 | { |
---|
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; |
---|
16298 | 23101 | |
---|
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)); |
---|
16305 | 23105 | return -1; |
---|
16306 | 23106 | } |
---|
16307 | 23107 | |
---|
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; |
---|
16309 | 23125 | } |
---|
16310 | 23126 | |
---|
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)) |
---|
16385 | 23127 | static s32 |
---|
16386 | 23128 | wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, |
---|
16387 | 23129 | const wl_event_msg_t *e, void *data) |
---|
16388 | 23130 | { |
---|
16389 | 23131 | int error = 0; |
---|
16390 | | - int chsp = 0; |
---|
| 23132 | + u32 chanspec = 0; |
---|
16391 | 23133 | struct net_device *ndev = NULL; |
---|
16392 | | - struct wiphy *wiphy = NULL; |
---|
16393 | | - chanspec_t chanspec; |
---|
| 23134 | + struct ether_addr bssid; |
---|
16394 | 23135 | |
---|
16395 | 23136 | WL_DBG(("Enter\n")); |
---|
16396 | 23137 | if (unlikely(e->status)) { |
---|
.. | .. |
---|
16400 | 23141 | |
---|
16401 | 23142 | if (likely(cfgdev)) { |
---|
16402 | 23143 | 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); |
---|
16405 | 23155 | if (unlikely(error)) { |
---|
16406 | 23156 | WL_ERR(("Get chanspec error: %d \n", error)); |
---|
16407 | 23157 | return -1; |
---|
16408 | 23158 | } |
---|
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 | + |
---|
16414 | 23175 | } |
---|
16415 | 23176 | |
---|
16416 | 23177 | return 0; |
---|
16417 | 23178 | } |
---|
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 */ |
---|
16436 | 23179 | |
---|
16437 | 23180 | void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg) |
---|
16438 | 23181 | { |
---|
.. | .. |
---|
16455 | 23198 | } |
---|
16456 | 23199 | |
---|
16457 | 23200 | #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) |
---|
16459 | 23202 | { |
---|
16460 | | - struct bcm_cfg80211 *cfg = g_bcm_cfg; |
---|
| 23203 | + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); |
---|
16461 | 23204 | struct wireless_dev *wdev = NULL; |
---|
16462 | 23205 | |
---|
16463 | 23206 | WL_DBG(("Enter \n")); |
---|
.. | .. |
---|
16475 | 23218 | } |
---|
16476 | 23219 | #endif /* WL_CFG80211_P2P_DEV_IF */ |
---|
16477 | 23220 | |
---|
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 | | - |
---|
16519 | 23221 | #ifdef GTK_OFFLOAD_SUPPORT |
---|
16520 | 23222 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) |
---|
16521 | 23223 | static s32 |
---|
.. | .. |
---|
16531 | 23233 | WL_ERR(("data is NULL or wrong net device\n")); |
---|
16532 | 23234 | return -EINVAL; |
---|
16533 | 23235 | } |
---|
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); |
---|
16543 | 23240 | bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH); |
---|
16544 | 23241 | bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH); |
---|
16545 | 23242 | bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN); |
---|
.. | .. |
---|
16553 | 23250 | return err; |
---|
16554 | 23251 | } |
---|
16555 | 23252 | #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 = ¶ms->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) */ |
---|