bcmdhd: fix build error after source merge
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / drivers / net / wireless / bcmdhd4361 / wl_cfg80211.c
1 /*
2 * Linux cfg80211 driver
3 *
4 * Copyright (C) 1999-2019, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: wl_cfg80211.c 820080 2019-05-16 03:05:46Z $
28 */
29 /* */
30 #include <typedefs.h>
31 #include <linuxver.h>
32 #include <linux/kernel.h>
33
34 #include <wlc_types.h>
35 #include <bcmutils.h>
36 #include <bcmwifi_channels.h>
37 #include <bcmendian.h>
38 #include <ethernet.h>
39 #ifdef WL_WPS_SYNC
40 #include <eapol.h>
41 #endif /* WL_WPS_SYNC */
42 #include <802.11.h>
43 #ifdef FILS_SUPPORT
44 #include <fils.h>
45 #include <frag.h>
46 #endif // endif
47 #include <linux/if_arp.h>
48 #include <asm/uaccess.h>
49
50 #include <ethernet.h>
51 #include <linux/kernel.h>
52 #include <linux/kthread.h>
53 #include <linux/netdevice.h>
54 #include <linux/sched.h>
55 #include <linux/etherdevice.h>
56 #include <linux/wireless.h>
57 #include <linux/ieee80211.h>
58 #include <linux/wait.h>
59 #include <net/cfg80211.h>
60 #include <net/rtnetlink.h>
61
62 #include <wlioctl.h>
63 #include <wldev_common.h>
64 #include <wl_cfg80211.h>
65 #include <wl_cfgp2p.h>
66 #include <bcmdevs.h>
67 #include <wl_android.h>
68 #include <dngl_stats.h>
69 #include <dhd.h>
70 #include <dhd_linux.h>
71 #include <dhd_debug.h>
72 #include <dhdioctl.h>
73 #include <wlioctl.h>
74 #include <dhd_cfg80211.h>
75 #include <dhd_bus.h>
76 #ifdef PNO_SUPPORT
77 #include <dhd_pno.h>
78 #endif /* PNO_SUPPORT */
79 #include <wl_cfgvendor.h>
80
81 #ifdef WL_NAN
82 #include <wl_cfgnan.h>
83 #endif /* WL_NAN */
84
85 #ifdef PROP_TXSTATUS
86 #include <dhd_wlfc.h>
87 #endif // endif
88
89 #ifdef BCMPCIE
90 #include <dhd_flowring.h>
91 #endif // endif
92 #ifdef RTT_SUPPORT
93 #include <dhd_rtt.h>
94 #endif /* RTT_SUPPORT */
95
96 #ifdef BIGDATA_SOFTAP
97 #include <wl_bigdata.h>
98 #endif /* BIGDATA_SOFTAP */
99
100 #ifdef DHD_EVENT_LOG_FILTER
101 #include <dhd_event_log_filter.h>
102 #endif /* DHD_EVENT_LOG_FILTER */
103
104 #ifdef BCMWAPI_WPI
105 /* these items should evetually go into wireless.h of the linux system headfile dir */
106 #ifndef IW_ENCODE_ALG_SM4
107 #define IW_ENCODE_ALG_SM4 0x20
108 #endif // endif
109
110 #ifndef IW_AUTH_WAPI_ENABLED
111 #define IW_AUTH_WAPI_ENABLED 0x20
112 #endif // endif
113
114 #ifndef IW_AUTH_WAPI_VERSION_1
115 #define IW_AUTH_WAPI_VERSION_1 0x00000008
116 #endif // endif
117
118 #ifndef IW_AUTH_CIPHER_SMS4
119 #define IW_AUTH_CIPHER_SMS4 0x00000020
120 #endif // endif
121
122 #ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
123 #define IW_AUTH_KEY_MGMT_WAPI_PSK 4
124 #endif // endif
125
126 #ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
127 #define IW_AUTH_KEY_MGMT_WAPI_CERT 8
128 #endif // endif
129 #endif /* BCMWAPI_WPI */
130
131 #ifdef BCMWAPI_WPI
132 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
133 #else /* BCMWAPI_WPI */
134 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
135 #endif /* BCMWAPI_WPI */
136
137 static struct device *cfg80211_parent_dev = NULL;
138 static struct bcm_cfg80211 *g_bcmcfg = NULL;
139 u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_P2P_ACTION | WL_DBG_INFO;
140
141 #define MAX_VIF_OFFSET 15
142 #define MAX_WAIT_TIME 1500
143 #ifdef WLAIBSS_MCHAN
144 #define IBSS_IF_NAME "ibss%d"
145 #endif /* WLAIBSS_MCHAN */
146
147 #ifdef VSDB
148 /* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
149 #define DEFAULT_SLEEP_TIME_VSDB 120
150 #define OFF_CHAN_TIME_THRESHOLD_MS 200
151 #define AF_RETRY_DELAY_TIME 40
152
153 /* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
154 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
155 do { \
156 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
157 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
158 OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
159 } \
160 } while (0)
161 #else /* VSDB */
162 /* if not VSDB, do nothing */
163 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
164 #endif /* VSDB */
165
166 #define DNGL_FUNC(func, parameters) func parameters
167 #define COEX_DHCP
168
169 #define WLAN_EID_SSID 0
170 #define CH_MIN_5G_CHANNEL 34
171 #define CH_MIN_2G_CHANNEL 1
172 #define ACTIVE_SCAN 1
173 #define PASSIVE_SCAN 0
174 #ifdef WLAIBSS
175 enum abiss_event_type {
176 AIBSS_EVENT_TXFAIL
177 };
178 #endif // endif
179
180 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
181 4 && __GNUC_MINOR__ >= 6))
182 #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
183 _Pragma("GCC diagnostic push") \
184 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
185 (entry) = list_first_entry((ptr), type, member); \
186 _Pragma("GCC diagnostic pop") \
187
188 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
189 _Pragma("GCC diagnostic push") \
190 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
191 entry = container_of((ptr), type, member); \
192 _Pragma("GCC diagnostic pop") \
193
194 #else
195 #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
196 (entry) = list_first_entry((ptr), type, member); \
197
198 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
199 entry = container_of((ptr), type, member); \
200
201 #endif /* STRICT_GCC_WARNINGS */
202
203 #ifdef WL_RELMCAST
204 enum rmc_event_type {
205 RMC_EVENT_NONE,
206 RMC_EVENT_LEADER_CHECK_FAIL
207 };
208 #endif /* WL_RELMCAST */
209
210 #ifdef WL_LASTEVT
211 typedef struct wl_last_event {
212 uint32 current_time; /* current tyime */
213 uint32 timestamp; /* event timestamp */
214 wl_event_msg_t event; /* Encapsulated event */
215 } wl_last_event_t;
216 #endif /* WL_LASTEVT */
217
218 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
219 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
220 * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
221 * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
222 * All the chnages in world regulatory domain are to be done here.
223 *
224 * this definition reuires disabling missing-field-initializer warning
225 * as the ieee80211_regdomain definition differs in plain linux and in Android
226 */
227 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
228 4 && __GNUC_MINOR__ >= 6))
229 _Pragma("GCC diagnostic push")
230 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
231 #endif // endif
232 static const struct ieee80211_regdomain brcm_regdom = {
233 .n_reg_rules = 4,
234 .alpha2 = "99",
235 .reg_rules = {
236 /* IEEE 802.11b/g, channels 1..11 */
237 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
238 /* If any */
239 /* IEEE 802.11 channel 14 - Only JP enables
240 * this and for 802.11b only
241 */
242 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
243 /* IEEE 802.11a, channel 36..64 */
244 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
245 /* IEEE 802.11a, channel 100..165 */
246 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
247 };
248 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
249 4 && __GNUC_MINOR__ >= 6))
250 _Pragma("GCC diagnostic pop")
251 #endif // endif
252
253 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
254 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
255 static const struct ieee80211_iface_limit common_if_limits[] = {
256 {
257 /*
258 * Driver can support up to 2 AP's
259 */
260 .max = 2,
261 .types = BIT(NL80211_IFTYPE_AP),
262 },
263 {
264 /*
265 * During P2P-GO removal, P2P-GO is first changed to STA and later only
266 * removed. So setting maximum possible number of STA interfaces according
267 * to kernel version.
268 *
269 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
270 * linux-3.8 and above - max:4
271 * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
272 * for NAN defined, registering it as STA type)
273 */
274 #ifdef WL_ENABLE_P2P_IF
275 .max = 3,
276 #else
277 .max = 4,
278 #endif /* WL_ENABLE_P2P_IF */
279 .types = BIT(NL80211_IFTYPE_STATION),
280 },
281 {
282 .max = 2,
283 .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
284 },
285 #if defined(WL_CFG80211_P2P_DEV_IF)
286 {
287 .max = 1,
288 .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
289 },
290 #endif /* WL_CFG80211_P2P_DEV_IF */
291 {
292 .max = 1,
293 .types = BIT(NL80211_IFTYPE_ADHOC),
294 },
295 };
296
297 #define NUM_DIFF_CHANNELS 2
298
299 static const struct ieee80211_iface_combination
300 common_iface_combinations[] = {
301 {
302 .num_different_channels = NUM_DIFF_CHANNELS,
303 /*
304 * max_interfaces = 4
305 * The max no of interfaces will be used in dual p2p case.
306 * {STA, P2P Device, P2P Group 1, P2P Group 2}. Though we
307 * will not be using the STA functionality in this case, it
308 * will remain registered as it is the primary interface.
309 */
310 .max_interfaces = 4,
311 .limits = common_if_limits,
312 .n_limits = ARRAY_SIZE(common_if_limits),
313 },
314 };
315 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
316
317 static const char *wl_if_state_strs[WL_IF_STATE_MAX + 1] = {
318 "WL_IF_CREATE_REQ",
319 "WL_IF_CREATE_DONE",
320 "WL_IF_DELETE_REQ",
321 "WL_IF_DELETE_DONE",
322 "WL_IF_CHANGE_REQ",
323 "WL_IF_CHANGE_DONE",
324 "WL_IF_STATE_MAX"
325 };
326
327 #ifdef BCMWAPI_WPI
328 #if defined(ANDROID_PLATFORM_VERSION) && (ANDROID_PLATFORM_VERSION >= 8)
329 /* WAPI define in ieee80211.h is used */
330 #else
331 #undef WLAN_AKM_SUITE_WAPI_PSK
332 #define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04
333
334 #undef WLAN_AKM_SUITE_WAPI_CERT
335 #define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12
336
337 #undef NL80211_WAPI_VERSION_1
338 #define NL80211_WAPI_VERSION_1 1 << 2
339 #endif /* ANDROID_PLATFORM_VERSION && ANDROID_PLATFORM_VERSION >= 8 */
340 #endif /* BCMWAPI_WPI */
341
342 /* Data Element Definitions */
343 #define WPS_ID_CONFIG_METHODS 0x1008
344 #define WPS_ID_REQ_TYPE 0x103A
345 #define WPS_ID_DEVICE_NAME 0x1011
346 #define WPS_ID_VERSION 0x104A
347 #define WPS_ID_DEVICE_PWD_ID 0x1012
348 #define WPS_ID_REQ_DEV_TYPE 0x106A
349 #define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
350 #define WPS_ID_PRIM_DEV_TYPE 0x1054
351
352 /* Device Password ID */
353 #define DEV_PW_DEFAULT 0x0000
354 #define DEV_PW_USER_SPECIFIED 0x0001,
355 #define DEV_PW_MACHINE_SPECIFIED 0x0002
356 #define DEV_PW_REKEY 0x0003
357 #define DEV_PW_PUSHBUTTON 0x0004
358 #define DEV_PW_REGISTRAR_SPECIFIED 0x0005
359
360 /* Config Methods */
361 #define WPS_CONFIG_USBA 0x0001
362 #define WPS_CONFIG_ETHERNET 0x0002
363 #define WPS_CONFIG_LABEL 0x0004
364 #define WPS_CONFIG_DISPLAY 0x0008
365 #define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
366 #define WPS_CONFIG_INT_NFC_TOKEN 0x0020
367 #define WPS_CONFIG_NFC_INTERFACE 0x0040
368 #define WPS_CONFIG_PUSHBUTTON 0x0080
369 #define WPS_CONFIG_KEYPAD 0x0100
370 #define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
371 #define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
372 #define WPS_CONFIG_VIRT_DISPLAY 0x2008
373 #define WPS_CONFIG_PHY_DISPLAY 0x4008
374
375 #define PM_BLOCK 1
376 #define PM_ENABLE 0
377
378 #ifdef BCMCCX
379 #ifndef WLAN_AKM_SUITE_CCKM
380 #define WLAN_AKM_SUITE_CCKM 0x00409600
381 #endif // endif
382 #define DOT11_LEAP_AUTH 0x80 /* LEAP auth frame paylod constants */
383 #endif /* BCMCCX */
384
385 #define WL_AKM_SUITE_SHA256_1X 0x000FAC05
386 #define WL_AKM_SUITE_SHA256_PSK 0x000FAC06
387
388 #ifndef IBSS_COALESCE_ALLOWED
389 #define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT
390 #endif // endif
391
392 #ifndef IBSS_INITIAL_SCAN_ALLOWED
393 #define IBSS_INITIAL_SCAN_ALLOWED IBSS_INITIAL_SCAN_ALLOWED_DEFAULT
394 #endif // endif
395
396 #define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
397 #define LONG_LISTEN_TIME 2000
398
399 #ifdef WBTEXT
400 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
401 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
402 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
403 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
404 #define DEFAULT_WBTEXT_PROFILE_A "a -70 -75 70 10 -75 -128 0 10"
405 #define DEFAULT_WBTEXT_PROFILE_B "b -60 -75 70 10 -75 -128 0 10"
406 #define DEFAULT_WBTEXT_WEIGHT_RSSI_A "RSSI a 65"
407 #define DEFAULT_WBTEXT_WEIGHT_RSSI_B "RSSI b 65"
408 #define DEFAULT_WBTEXT_WEIGHT_CU_A "CU a 35"
409 #define DEFAULT_WBTEXT_WEIGHT_CU_B "CU b 35"
410 #define DEFAULT_WBTEXT_TABLE_RSSI_A "RSSI a 0 55 100 55 60 90 \
411 60 65 70 65 70 50 70 128 20"
412 #define DEFAULT_WBTEXT_TABLE_RSSI_B "RSSI b 0 55 100 55 60 90 \
413 60 65 70 65 70 50 70 128 20"
414 #define DEFAULT_WBTEXT_TABLE_CU_A "CU a 0 30 100 30 50 90 \
415 50 60 70 60 80 50 80 100 20"
416 #define DEFAULT_WBTEXT_TABLE_CU_B "CU b 0 10 100 10 25 90 \
417 25 40 70 40 70 50 70 100 20"
418
419 typedef struct wl_wbtext_bssid {
420 struct ether_addr ea;
421 struct list_head list;
422 } wl_wbtext_bssid_t;
423
424 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev);
425 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
426 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
427 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg);
428 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
429 struct wl_profile *profile);
430 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
431 struct wl_profile *profile);
432 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev);
433 static int wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len);
434 #endif /* WBTEXT */
435
436 #ifdef SUPPORT_AP_RADIO_PWRSAVE
437 #define RADIO_PWRSAVE_PPS 10
438 #define RADIO_PWRSAVE_QUIET_TIME 10
439 #define RADIO_PWRSAVE_LEVEL 3
440 #define RADIO_PWRSAVE_STAS_ASSOC_CHECK 0
441
442 #define RADIO_PWRSAVE_LEVEL_MIN 1
443 #define RADIO_PWRSAVE_LEVEL_MAX 5
444 #define RADIO_PWRSAVE_PPS_MIN 1
445 #define RADIO_PWRSAVE_QUIETTIME_MIN 1
446 #define RADIO_PWRSAVE_ASSOCCHECK_MIN 0
447 #define RADIO_PWRSAVE_ASSOCCHECK_MAX 1
448
449 #define RADIO_PWRSAVE_MAJOR_VER 1
450 #define RADIO_PWRSAVE_MINOR_VER 1
451 #define RADIO_PWRSAVE_MAJOR_VER_SHIFT 8
452 #define RADIO_PWRSAVE_VERSION \
453 ((RADIO_PWRSAVE_MAJOR_VER << RADIO_PWRSAVE_MAJOR_VER_SHIFT)| RADIO_PWRSAVE_MINOR_VER)
454 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
455
456 #define MIN_P2P_IE_LEN 8 /* p2p_ie->OUI(3) + p2p_ie->oui_type(1) +
457 * Attribute ID(1) + Length(2) + 1(Mininum length:1)
458 */
459 #define MAX_P2P_IE_LEN 251 /* Up To 251 */
460
461 #define MAX_VNDR_OUI_STR_LEN 256
462 #define VNDR_OUI_STR_LEN 10
463 static const uchar *exclude_vndr_oui_list[] = {
464 "\x00\x50\xf2", /* Microsoft */
465 "\x00\x00\xf0", /* Samsung Elec */
466 WFA_OUI, /* WFA */
467 NULL
468 };
469
470 typedef struct wl_vndr_oui_entry {
471 uchar oui[DOT11_OUI_LEN];
472 struct list_head list;
473 } wl_vndr_oui_entry_t;
474
475 static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
476 struct net_device *ndev, char *vndr_oui, u32 vndr_oui_len);
477 static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg);
478
479 /*
480 * cfg80211_ops api/callback list
481 */
482 static s32 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
483 const struct ether_addr *da, const struct ether_addr *sa,
484 const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody);
485 static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
486 struct cfg80211_scan_request *request,
487 struct cfg80211_ssid *this_ssid);
488 #if defined(WL_CFG80211_P2P_DEV_IF)
489 static s32
490 wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request);
491 #else
492 static s32
493 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
494 struct cfg80211_scan_request *request);
495 #endif /* WL_CFG80211_P2P_DEV_IF */
496 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
497 static void wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev);
498 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
499 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
500 #ifdef WLAIBSS_MCHAN
501 static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name);
502 static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
503 #endif /* WLAIBSS_MCHAN */
504 static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
505 struct cfg80211_ibss_params *params);
506 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
507 struct net_device *dev);
508 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
509 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
510 struct net_device *dev, const u8 *mac,
511 struct station_info *sinfo);
512 #else
513 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
514 struct net_device *dev, u8 *mac,
515 struct station_info *sinfo);
516 #endif // endif
517 static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
518 struct net_device *dev, bool enabled,
519 s32 timeout);
520 static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
521 struct cfg80211_connect_params *sme);
522 static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
523 u16 reason_code);
524 #if defined(WL_CFG80211_P2P_DEV_IF)
525 static s32
526 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
527 enum nl80211_tx_power_setting type, s32 mbm);
528 #else
529 static s32
530 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
531 enum nl80211_tx_power_setting type, s32 dbm);
532 #endif /* WL_CFG80211_P2P_DEV_IF */
533 #if defined(WL_CFG80211_P2P_DEV_IF)
534 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
535 struct wireless_dev *wdev, s32 *dbm);
536 #else
537 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
538 #endif /* WL_CFG80211_P2P_DEV_IF */
539 static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
540 struct net_device *dev,
541 u8 key_idx, bool unicast, bool multicast);
542 static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
543 u8 key_idx, bool pairwise, const u8 *mac_addr,
544 struct key_params *params);
545 static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
546 u8 key_idx, bool pairwise, const u8 *mac_addr);
547 static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
548 u8 key_idx, bool pairwise, const u8 *mac_addr,
549 void *cookie, void (*callback) (void *cookie,
550 struct key_params *params));
551 static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
552 struct net_device *dev, u8 key_idx);
553 static s32 wl_cfg80211_resume(struct wiphy *wiphy);
554 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
555 2, 0))
556 static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
557 bcm_struct_cfgdev *cfgdev, u64 cookie);
558 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
559 static s32 wl_cfg80211_del_station(
560 struct wiphy *wiphy, struct net_device *ndev,
561 struct station_del_parameters *params);
562 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
563 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
564 struct net_device *ndev, const u8* mac_addr);
565 #else
566 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
567 struct net_device *ndev, u8* mac_addr);
568 #endif // endif
569 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
570 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
571 struct net_device *dev, const u8 *mac, struct station_parameters *params);
572 #else
573 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
574 struct net_device *dev, u8 *mac, struct station_parameters *params);
575 #endif // endif
576 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
577 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
578 static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
579 #else
580 static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
581 #endif // endif
582 static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
583 struct cfg80211_pmksa *pmksa);
584 static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
585 struct cfg80211_pmksa *pmksa);
586 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
587 struct net_device *dev);
588 void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
589 static void wl_cfg80211_cancel_scan(struct bcm_cfg80211 *cfg);
590 static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
591 struct net_device *ndev, bool aborted, bool fw_abort);
592 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
593 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
594 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
595 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
596 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
597 u32 peer_capability, const u8 *buf, size_t len);
598 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
599 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
600 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
601 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
602 u32 peer_capability, const u8 *buf, size_t len);
603 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
604 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
605 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
606 u32 peer_capability, bool initiator, const u8 *buf, size_t len);
607 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
608 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
609 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
610 const u8 *buf, size_t len);
611 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
612 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
613 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
614 const u8 *peer, enum nl80211_tdls_operation oper);
615 #else
616 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
617 u8 *peer, enum nl80211_tdls_operation oper);
618 #endif // endif
619 #endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
620 #ifdef WL_SCHED_SCAN
621 static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev);
622 #endif /* WL_SCHED_SCAN */
623 static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg, struct net_device *dev);
624
625 struct wireless_dev *
626 wl_cfg80211_create_iface(struct wiphy *wiphy, wl_iftype_t
627 iface_type, u8 *mac_addr, const char *name);
628 s32
629 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
630
631 s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
632 struct net_device *ndev, s32 bsscfg_idx,
633 wl_iftype_t iftype, s32 del, u8 *addr);
634 s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
635 struct net_device *ndev, s32 bsscfg_idx,
636 wl_iftype_t brcm_iftype, s32 del, u8 *addr);
637 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
638 static s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev);
639 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */
640 #ifdef GTK_OFFLOAD_SUPPORT
641 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
642 static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
643 struct cfg80211_gtk_rekey_data *data);
644 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
645 #endif /* GTK_OFFLOAD_SUPPORT */
646 chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
647 chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
648 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev);
649
650 /*
651 * event & event Q handlers for cfg80211 interfaces
652 */
653 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
654 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
655 static void wl_event_handler(struct work_struct *work_data);
656 static void wl_init_eq(struct bcm_cfg80211 *cfg);
657 static void wl_flush_eq(struct bcm_cfg80211 *cfg);
658 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
659 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
660 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
661 static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
662 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
663 static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
664 const wl_event_msg_t *msg, void *data);
665 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e);
666 static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
667 const wl_event_msg_t *e, void *data);
668 static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
669 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
670 static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
671 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
672 static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
673 const wl_event_msg_t *e, void *data);
674 static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
675 const wl_event_msg_t *e, void *data, bool completed);
676 static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
677 const wl_event_msg_t *e, void *data);
678 static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
679 const wl_event_msg_t *e, void *data);
680 #ifdef BT_WIFI_HANDOVER
681 static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
682 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
683 #endif /* BT_WIFI_HANDOVER */
684 #ifdef WL_SCHED_SCAN
685 static s32
686 wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
687 const wl_event_msg_t *e, void *data);
688 #endif /* WL_SCHED_SCAN */
689 #ifdef PNO_SUPPORT
690 static s32 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
691 const wl_event_msg_t *e, void *data);
692 #endif /* PNO_SUPPORT */
693 #ifdef GSCAN_SUPPORT
694 static s32 wl_notify_gscan_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
695 const wl_event_msg_t *e, void *data);
696 static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
697 const wl_event_msg_t *e, void *data);
698 #endif /* GSCAN_SUPPORT */
699 #ifdef RSSI_MONITOR_SUPPORT
700 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
701 const wl_event_msg_t *e, void *data);
702 #endif /* RSSI_MONITOR_SUPPORT */
703 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
704 enum wl_status state, bool set);
705 #ifdef CUSTOM_EVENT_PM_WAKE
706 static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
707 const wl_event_msg_t *e, void *data);
708 #endif /* CUSTOM_EVENT_PM_WAKE */
709 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
710 static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
711 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
712 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
713 #ifdef DHD_LOSSLESS_ROAMING
714 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
715 #endif /* DHD_LOSSLESS_ROAMING */
716
717 #ifdef WLTDLS
718 static s32 wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg,
719 enum wl_tdls_config state, bool tdls_mode);
720 static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
721 const wl_event_msg_t *e, void *data);
722 #endif /* WLTDLS */
723 /*
724 * register/deregister parent device
725 */
726 static void wl_cfg80211_clear_parent_dev(void);
727 /*
728 * ioctl utilites
729 */
730
731 /*
732 * cfg80211 set_wiphy_params utilities
733 */
734 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
735 static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
736 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
737
738 /*
739 * cfg profile utilities
740 */
741 static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
742 const wl_event_msg_t *e, const void *data, s32 item);
743 static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item);
744 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
745
746 /*
747 * cfg80211 connect utilites
748 */
749 static s32 wl_set_wpa_version(struct net_device *dev,
750 struct cfg80211_connect_params *sme);
751 static s32 wl_set_auth_type(struct net_device *dev,
752 struct cfg80211_connect_params *sme);
753 static s32 wl_set_set_cipher(struct net_device *dev,
754 struct cfg80211_connect_params *sme);
755 static s32 wl_set_key_mgmt(struct net_device *dev,
756 struct cfg80211_connect_params *sme);
757 static s32 wl_set_set_sharedkey(struct net_device *dev,
758 struct cfg80211_connect_params *sme);
759 #ifdef BCMWAPI_WPI
760 static s32 wl_set_set_wapi_ie(struct net_device *dev,
761 struct cfg80211_connect_params *sme);
762 #endif // endif
763 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
764 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch,
765 struct wl_join_params *join_params, size_t *join_params_size);
766 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
767
768 /*
769 * information element utilities
770 */
771 static void wl_rst_ie(struct bcm_cfg80211 *cfg);
772 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
773 static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 *ie_size,
774 bool roam);
775 static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size);
776 static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size);
777 static u32 wl_get_ielen(struct bcm_cfg80211 *cfg);
778 #ifdef MFP
779 static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie, const u8** rsn_cap);
780 #endif // endif
781
782 #ifdef WL11U
783 static bcm_tlv_t *
784 wl_cfg80211_find_interworking_ie(const u8 *parse, u32 len);
785 static s32
786 wl_cfg80211_clear_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx);
787 static s32
788 wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
789 uint8 ie_id, uint8 *data, uint8 data_len);
790 #endif /* WL11U */
791
792 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data);
793 static void wl_free_wdev(struct bcm_cfg80211 *cfg);
794
795 static s32 wl_inform_bss(struct bcm_cfg80211 *cfg);
796 static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool roam);
797 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam);
798 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
799 s32 wl_cfg80211_channel_to_freq(u32 channel);
800
801 static void wl_cfg80211_work_handler(struct work_struct *work);
802 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
803 u8 key_idx, const u8 *mac_addr,
804 struct key_params *params);
805 /*
806 * key indianess swap utilities
807 */
808 static void swap_key_from_BE(struct wl_wsec_key *key);
809 static void swap_key_to_BE(struct wl_wsec_key *key);
810
811 /*
812 * bcm_cfg80211 memory init/deinit utilities
813 */
814 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
815 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
816
817 static void wl_delay(u32 ms);
818
819 /*
820 * ibss mode utilities
821 */
822 static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev);
823 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
824
825 /*
826 * link up/down , default configuration utilities
827 */
828 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
829 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
830
831 #ifdef WL_LASTEVT
832 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, void *data);
833 #define WL_IS_LINKDOWN(cfg, e, data) wl_is_linkdown(cfg, e, data)
834 #else
835 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
836 #define WL_IS_LINKDOWN(cfg, e, data) wl_is_linkdown(cfg, e)
837 #endif /* WL_LASTEVT */
838
839 static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
840 struct net_device *ndev);
841 static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
842 static void wl_link_up(struct bcm_cfg80211 *cfg);
843 static void wl_link_down(struct bcm_cfg80211 *cfg);
844 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype);
845 static void wl_init_conf(struct wl_conf *conf);
846 int wl_cfg80211_get_ioctl_version(void);
847
848 /*
849 * find most significant bit set
850 */
851 static __used u32 wl_find_msb(u16 bit16);
852
853 /*
854 * rfkill support
855 */
856 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
857 static int wl_rfkill_set(void *data, bool blocked);
858 #ifdef DEBUGFS_CFG80211
859 static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg);
860 static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg);
861 #endif // endif
862 static wl_scan_params_t *wl_cfg80211_scan_alloc_params(struct bcm_cfg80211 *cfg,
863 int channel, int nprobes, int *out_params_size);
864 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
865
866 #ifdef WL_CFG80211_ACL
867 /* ACL */
868 static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
869 const struct cfg80211_acl_data *acl);
870 #endif /* WL_CFG80211_ACL */
871
872 /*
873 * Some external functions, TODO: move them to dhd_linux.h
874 */
875 int dhd_add_monitor(const char *name, struct net_device **new_ndev);
876 int dhd_del_monitor(struct net_device *ndev);
877 int dhd_monitor_init(void *dhd_pub);
878 int dhd_monitor_uninit(void);
879 int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
880
881 #ifdef ESCAN_CHANNEL_CACHE
882 void reset_roam_cache(struct bcm_cfg80211 *cfg);
883 void add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi);
884 int get_roam_channel_list(int target_chan, chanspec_t *channels,
885 int n_channels, const wlc_ssid_t *ssid, int ioctl_ver);
886 void set_roam_band(int band);
887 #endif /* ESCAN_CHANNEL_CACHE */
888
889 #ifdef ROAM_CHANNEL_CACHE
890 int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
891 void print_roam_cache(struct bcm_cfg80211 *cfg);
892 void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
893 #endif /* ROAM_CHANNEL_CACHE */
894
895 #ifdef P2P_LISTEN_OFFLOADING
896 s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
897 #endif /* P2P_LISTEN_OFFLOADING */
898
899 #ifdef PKT_FILTER_SUPPORT
900 extern uint dhd_pkt_filter_enable;
901 extern uint dhd_master_mode;
902 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
903 #endif /* PKT_FILTER_SUPPORT */
904
905 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
906 const struct ether_addr *bssid);
907 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
908
909 static s32 wl_check_vif_support(struct bcm_cfg80211 *cfg, wl_iftype_t wl_iftype);
910 bool wl_is_wps_enrollee_active(struct net_device *ndev, const u8 *ie_ptr, u16 len);
911
912 #ifdef WL_WPS_SYNC
913 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg);
914 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg);
915 static void wl_wps_reauth_timeout(unsigned long data);
916 static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg);
917 static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev);
918 static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *peer_mac);
919 static void wl_wps_session_del(struct net_device *ndev);
920 static s32 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac);
921 static void wl_wps_handle_ifdel(struct net_device *ndev);
922 #endif /* WL_WPS_SYNC */
923 const u8 *wl_find_attribute(const u8 *buf, u16 len, u16 element_id);
924
925 #ifdef WL_BCNRECV
926 static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
927 const wl_event_msg_t *e, void *data);
928 #endif /* WL_BCNRECV */
929
930 static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ,
931 WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ };
932
933 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || (defined(CONFIG_ARCH_MSM) && \
934 defined(CFG80211_DISCONNECTED_V2))
935 #define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
936 cfg80211_disconnected(dev, reason, ie, len, loc_gen, gfp);
937 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0))
938 #define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
939 BCM_REFERENCE(loc_gen); \
940 cfg80211_disconnected(dev, reason, ie, len, gfp);
941 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) */
942
943 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || (defined(CONFIG_ARCH_MSM) && \
944 defined(CFG80211_DISCONNECTED_V2))
945 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
946 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
947 IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
948 #else
949 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
950 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
951 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
952 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
953
954 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
955 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
956 defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
957 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
958 resp_ie_len, status, gfp) \
959 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
960 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
961 #else
962 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
963 resp_ie_len, status, gfp) \
964 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
965 resp_ie_len, status, gfp);
966 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
967 (CFG80211_CONNECT_TIMEOUT_REASON_CODE)
968 */
969 #elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
970 /* There are customer kernels with backported changes for
971 * connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
972 * is available for kernels < 4.7 in such cases.
973 */
974 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
975 resp_ie_len, status, gfp) \
976 cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie, \
977 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
978 #else
979 /* Kernels < 4.7 doesn't support cfg80211_connect_bss */
980 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
981 resp_ie_len, status, gfp) \
982 cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
983 resp_ie_len, status, gfp);
984 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
985
986 #ifdef RSSI_OFFSET
987 static s32 wl_rssi_offset(s32 rssi)
988 {
989 rssi += RSSI_OFFSET;
990 if (rssi > 0)
991 rssi = 0;
992 return rssi;
993 }
994 #else
995 #define wl_rssi_offset(x) x
996 #endif // endif
997
998 #define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
999 (akm) == RSN_AKM_UNSPECIFIED || \
1000 (akm) == RSN_AKM_PSK)
1001
1002 extern int dhd_wait_pend8021x(struct net_device *dev);
1003 #ifdef PROP_TXSTATUS_VSDB
1004 extern int disable_proptx;
1005 #endif /* PROP_TXSTATUS_VSDB */
1006
1007 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
1008 extern void dhd_force_disable_singlcore_scan(dhd_pub_t *dhd);
1009 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
1010
1011 extern int passive_channel_skip;
1012
1013 static s32
1014 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1015 const wl_event_msg_t *e, void *data);
1016 static s32
1017 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1018 const wl_event_msg_t *e, void *data);
1019 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \
1020 0)))
1021 struct chan_info {
1022 int freq;
1023 int chan_type;
1024 };
1025 #endif // endif
1026
1027 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
1028 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(wiphy, bss);
1029 #else
1030 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(bss);
1031 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
1032
1033 #define CHAN2G(_channel, _freq, _flags) { \
1034 .band = NL80211_BAND_2GHZ, \
1035 .center_freq = (_freq), \
1036 .hw_value = (_channel), \
1037 .flags = (_flags), \
1038 .max_antenna_gain = 0, \
1039 .max_power = 30, \
1040 }
1041
1042 #define CHAN5G(_channel, _flags) { \
1043 .band = NL80211_BAND_5GHZ, \
1044 .center_freq = 5000 + (5 * (_channel)), \
1045 .hw_value = (_channel), \
1046 .flags = (_flags), \
1047 .max_antenna_gain = 0, \
1048 .max_power = 30, \
1049 }
1050
1051 #define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
1052 #define RATETAB_ENT(_rateid, _flags) \
1053 { \
1054 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
1055 .hw_value = (_rateid), \
1056 .flags = (_flags), \
1057 }
1058
1059 static struct ieee80211_rate __wl_rates[] = {
1060 RATETAB_ENT(DOT11_RATE_1M, 0),
1061 RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
1062 RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
1063 RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
1064 RATETAB_ENT(DOT11_RATE_6M, 0),
1065 RATETAB_ENT(DOT11_RATE_9M, 0),
1066 RATETAB_ENT(DOT11_RATE_12M, 0),
1067 RATETAB_ENT(DOT11_RATE_18M, 0),
1068 RATETAB_ENT(DOT11_RATE_24M, 0),
1069 RATETAB_ENT(DOT11_RATE_36M, 0),
1070 RATETAB_ENT(DOT11_RATE_48M, 0),
1071 RATETAB_ENT(DOT11_RATE_54M, 0)
1072 };
1073
1074 #define wl_a_rates (__wl_rates + 4)
1075 #define wl_a_rates_size 8
1076 #define wl_g_rates (__wl_rates + 0)
1077 #define wl_g_rates_size 12
1078
1079 static struct ieee80211_channel __wl_2ghz_channels[] = {
1080 CHAN2G(1, 2412, 0),
1081 CHAN2G(2, 2417, 0),
1082 CHAN2G(3, 2422, 0),
1083 CHAN2G(4, 2427, 0),
1084 CHAN2G(5, 2432, 0),
1085 CHAN2G(6, 2437, 0),
1086 CHAN2G(7, 2442, 0),
1087 CHAN2G(8, 2447, 0),
1088 CHAN2G(9, 2452, 0),
1089 CHAN2G(10, 2457, 0),
1090 CHAN2G(11, 2462, 0),
1091 CHAN2G(12, 2467, 0),
1092 CHAN2G(13, 2472, 0),
1093 CHAN2G(14, 2484, 0)
1094 };
1095
1096 static struct ieee80211_channel __wl_5ghz_a_channels[] = {
1097 CHAN5G(34, 0), CHAN5G(36, 0),
1098 CHAN5G(38, 0), CHAN5G(40, 0),
1099 CHAN5G(42, 0), CHAN5G(44, 0),
1100 CHAN5G(46, 0), CHAN5G(48, 0),
1101 CHAN5G(52, 0), CHAN5G(56, 0),
1102 CHAN5G(60, 0), CHAN5G(64, 0),
1103 CHAN5G(100, 0), CHAN5G(104, 0),
1104 CHAN5G(108, 0), CHAN5G(112, 0),
1105 CHAN5G(116, 0), CHAN5G(120, 0),
1106 CHAN5G(124, 0), CHAN5G(128, 0),
1107 CHAN5G(132, 0), CHAN5G(136, 0),
1108 CHAN5G(140, 0), CHAN5G(144, 0),
1109 CHAN5G(149, 0), CHAN5G(153, 0),
1110 CHAN5G(157, 0), CHAN5G(161, 0),
1111 CHAN5G(165, 0)
1112 };
1113
1114 static struct ieee80211_supported_band __wl_band_2ghz = {
1115 .band = NL80211_BAND_2GHZ,
1116 .channels = __wl_2ghz_channels,
1117 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
1118 .bitrates = wl_g_rates,
1119 .n_bitrates = wl_g_rates_size
1120 };
1121
1122 static struct ieee80211_supported_band __wl_band_5ghz_a = {
1123 .band = NL80211_BAND_5GHZ,
1124 .channels = __wl_5ghz_a_channels,
1125 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
1126 .bitrates = wl_a_rates,
1127 .n_bitrates = wl_a_rates_size
1128 };
1129
1130 static const u32 __wl_cipher_suites[] = {
1131 WLAN_CIPHER_SUITE_WEP40,
1132 WLAN_CIPHER_SUITE_WEP104,
1133 WLAN_CIPHER_SUITE_TKIP,
1134 WLAN_CIPHER_SUITE_CCMP,
1135 #ifdef MFP
1136 /*
1137 * Advertising AES_CMAC cipher suite to userspace would imply that we
1138 * are supporting MFP. So advertise only when MFP support is enabled.
1139 */
1140 WLAN_CIPHER_SUITE_AES_CMAC,
1141 #endif /* MFP */
1142 #ifdef BCMWAPI_WPI
1143 WLAN_CIPHER_SUITE_SMS4,
1144 #endif // endif
1145 #if defined(WLAN_CIPHER_SUITE_PMK)
1146 WLAN_CIPHER_SUITE_PMK,
1147 #endif /* WLAN_CIPHER_SUITE_PMK */
1148 };
1149
1150 #ifdef WL_SUPPORT_ACS
1151 /*
1152 * The firmware code required for this feature to work is currently under
1153 * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1154 * required firmware code out of the BCMINTERNAL flag.
1155 */
1156 struct wl_dump_survey {
1157 u32 obss;
1158 u32 ibss;
1159 u32 no_ctg;
1160 u32 no_pckt;
1161 u32 tx;
1162 u32 idle;
1163 };
1164 #endif /* WL_SUPPORT_ACS */
1165
1166 #ifdef WL_CFG80211_GON_COLLISION
1167 #define BLOCK_GON_REQ_MAX_NUM 5
1168 #endif /* WL_CFG80211_GON_COLLISION */
1169
1170 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1171 static int maxrxpktglom = 0;
1172 #endif // endif
1173
1174 /* IOCtl version read from targeted driver */
1175 int ioctl_version;
1176 #ifdef DEBUGFS_CFG80211
1177 #define SUBLOGLEVEL 20
1178 #define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1))
1179 static const struct {
1180 u32 log_level;
1181 char *sublogname;
1182 } sublogname_map[] = {
1183 {WL_DBG_ERR, "ERR"},
1184 {WL_DBG_INFO, "INFO"},
1185 {WL_DBG_DBG, "DBG"},
1186 {WL_DBG_SCAN, "SCAN"},
1187 {WL_DBG_TRACE, "TRACE"},
1188 {WL_DBG_P2P_ACTION, "P2PACTION"}
1189 };
1190 #endif // endif
1191
1192 #define BUFSZ 5
1193 #define BUFSZN BUFSZ + 1
1194
1195 #define _S(x) #x
1196 #define S(x) _S(x)
1197
1198 #define SOFT_AP_IF_NAME "swlan0"
1199
1200 #ifdef P2P_LISTEN_OFFLOADING
1201 void wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg);
1202 #endif /* P2P_LISTEN_OFFLOADING */
1203
1204 #ifdef CUSTOMER_HW4_DEBUG
1205 uint prev_dhd_console_ms = 0;
1206 u32 prev_wl_dbg_level = 0;
1207 bool wl_scan_timeout_dbg_enabled = 0;
1208 static void wl_scan_timeout_dbg_set(void);
1209 static void wl_scan_timeout_dbg_clear(void);
1210
1211 static void wl_scan_timeout_dbg_set(void)
1212 {
1213 WL_ERR(("Enter \n"));
1214 prev_dhd_console_ms = dhd_console_ms;
1215 prev_wl_dbg_level = wl_dbg_level;
1216
1217 dhd_console_ms = 1;
1218 wl_dbg_level |= (WL_DBG_ERR | WL_DBG_P2P_ACTION | WL_DBG_SCAN);
1219
1220 wl_scan_timeout_dbg_enabled = 1;
1221 }
1222 static void wl_scan_timeout_dbg_clear(void)
1223 {
1224 WL_ERR(("Enter \n"));
1225 dhd_console_ms = prev_dhd_console_ms;
1226 wl_dbg_level = prev_wl_dbg_level;
1227
1228 wl_scan_timeout_dbg_enabled = 0;
1229 }
1230 #endif /* CUSTOMER_HW4_DEBUG */
1231
1232 /* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1233 uint32 fw_assoc_watchdog_ms = 0;
1234 bool fw_assoc_watchdog_started = 0;
1235 #define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1236
1237 static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg,
1238 enum wl_pm_workq_act_type type)
1239 {
1240 u16 wq_duration = 0;
1241 dhd_pub_t *dhd = NULL;
1242
1243 if (cfg == NULL)
1244 return;
1245
1246 dhd = (dhd_pub_t *)(cfg->pub);
1247
1248 mutex_lock(&cfg->pm_sync);
1249 /*
1250 * Make cancel and schedule work part mutually exclusive
1251 * so that while cancelling, we are sure that there is no
1252 * work getting scheduled.
1253 */
1254 if (delayed_work_pending(&cfg->pm_enable_work)) {
1255 cancel_delayed_work(&cfg->pm_enable_work);
1256 DHD_PM_WAKE_UNLOCK(cfg->pub);
1257 }
1258
1259 if (type == WL_PM_WORKQ_SHORT) {
1260 wq_duration = WL_PM_ENABLE_TIMEOUT;
1261 } else if (type == WL_PM_WORKQ_LONG) {
1262 wq_duration = (WL_PM_ENABLE_TIMEOUT*2);
1263 }
1264
1265 /* It should schedule work item only if driver is up */
1266 if (wq_duration && dhd->up) {
1267 if (schedule_delayed_work(&cfg->pm_enable_work,
1268 msecs_to_jiffies((const unsigned int)wq_duration))) {
1269 DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub, wq_duration);
1270 } else {
1271 WL_ERR(("Can't schedule pm work handler\n"));
1272 }
1273 }
1274 mutex_unlock(&cfg->pm_sync);
1275 }
1276
1277 /* Return a new chanspec given a legacy chanspec
1278 * Returns INVCHANSPEC on error
1279 */
1280 chanspec_t
1281 wl_chspec_from_legacy(chanspec_t legacy_chspec)
1282 {
1283 chanspec_t chspec;
1284
1285 /* get the channel number */
1286 chspec = LCHSPEC_CHANNEL(legacy_chspec);
1287
1288 /* convert the band */
1289 if (LCHSPEC_IS2G(legacy_chspec)) {
1290 chspec |= WL_CHANSPEC_BAND_2G;
1291 } else {
1292 chspec |= WL_CHANSPEC_BAND_5G;
1293 }
1294
1295 /* convert the bw and sideband */
1296 if (LCHSPEC_IS20(legacy_chspec)) {
1297 chspec |= WL_CHANSPEC_BW_20;
1298 } else {
1299 chspec |= WL_CHANSPEC_BW_40;
1300 if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
1301 chspec |= WL_CHANSPEC_CTL_SB_L;
1302 } else {
1303 chspec |= WL_CHANSPEC_CTL_SB_U;
1304 }
1305 }
1306
1307 if (wf_chspec_malformed(chspec)) {
1308 WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1309 chspec));
1310 return INVCHANSPEC;
1311 }
1312
1313 return chspec;
1314 }
1315
1316 /* Return a legacy chanspec given a new chanspec
1317 * Returns INVCHANSPEC on error
1318 */
1319 static chanspec_t
1320 wl_chspec_to_legacy(chanspec_t chspec)
1321 {
1322 chanspec_t lchspec;
1323
1324 if (wf_chspec_malformed(chspec)) {
1325 WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1326 chspec));
1327 return INVCHANSPEC;
1328 }
1329
1330 /* get the channel number */
1331 lchspec = CHSPEC_CHANNEL(chspec);
1332
1333 /* convert the band */
1334 if (CHSPEC_IS2G(chspec)) {
1335 lchspec |= WL_LCHANSPEC_BAND_2G;
1336 } else {
1337 lchspec |= WL_LCHANSPEC_BAND_5G;
1338 }
1339
1340 /* convert the bw and sideband */
1341 if (CHSPEC_IS20(chspec)) {
1342 lchspec |= WL_LCHANSPEC_BW_20;
1343 lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
1344 } else if (CHSPEC_IS40(chspec)) {
1345 lchspec |= WL_LCHANSPEC_BW_40;
1346 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
1347 lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
1348 } else {
1349 lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
1350 }
1351 } else {
1352 /* cannot express the bandwidth */
1353 char chanbuf[CHANSPEC_STR_LEN];
1354 WL_ERR((
1355 "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1356 "to pre-11ac format\n",
1357 wf_chspec_ntoa(chspec, chanbuf), chspec));
1358 return INVCHANSPEC;
1359 }
1360
1361 return lchspec;
1362 }
1363
1364 /* given a chanspec value, do the endian and chanspec version conversion to
1365 * a chanspec_t value
1366 * Returns INVCHANSPEC on error
1367 */
1368 chanspec_t
1369 wl_chspec_host_to_driver(chanspec_t chanspec)
1370 {
1371 if (ioctl_version == 1) {
1372 chanspec = wl_chspec_to_legacy(chanspec);
1373 if (chanspec == INVCHANSPEC) {
1374 return chanspec;
1375 }
1376 }
1377 chanspec = htodchanspec(chanspec);
1378
1379 return chanspec;
1380 }
1381
1382 /* given a channel value, do the endian and chanspec version conversion to
1383 * a chanspec_t value
1384 * Returns INVCHANSPEC on error
1385 */
1386 chanspec_t
1387 wl_ch_host_to_driver(u16 channel)
1388 {
1389 chanspec_t chanspec;
1390
1391 chanspec = channel & WL_CHANSPEC_CHAN_MASK;
1392
1393 if (channel <= CH_MAX_2G_CHANNEL)
1394 chanspec |= WL_CHANSPEC_BAND_2G;
1395 else
1396 chanspec |= WL_CHANSPEC_BAND_5G;
1397
1398 chanspec |= WL_CHANSPEC_BW_20;
1399
1400 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
1401
1402 return wl_chspec_host_to_driver(chanspec);
1403 }
1404
1405 /* given a chanspec value from the driver, do the endian and chanspec version conversion to
1406 * a chanspec_t value
1407 * Returns INVCHANSPEC on error
1408 */
1409 chanspec_t
1410 wl_chspec_driver_to_host(chanspec_t chanspec)
1411 {
1412 chanspec = dtohchanspec(chanspec);
1413 if (ioctl_version == 1) {
1414 chanspec = wl_chspec_from_legacy(chanspec);
1415 }
1416
1417 return chanspec;
1418 }
1419
1420 /*
1421 * convert ASCII string to MAC address (colon-delimited format)
1422 * eg: 00:11:22:33:44:55
1423 */
1424 int
1425 wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
1426 {
1427 char *c = NULL;
1428 int count = 0;
1429
1430 memset(n, 0, ETHER_ADDR_LEN);
1431 for (;;) {
1432 n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
1433 if (!*c++ || count == ETHER_ADDR_LEN)
1434 break;
1435 a = c;
1436 }
1437 return (count == ETHER_ADDR_LEN);
1438 }
1439
1440 /* There isn't a lot of sense in it, but you can transmit anything you like */
1441 static const struct ieee80211_txrx_stypes
1442 wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1443 [NL80211_IFTYPE_ADHOC] = {
1444 .tx = 0xffff,
1445 .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
1446 },
1447 [NL80211_IFTYPE_STATION] = {
1448 .tx = 0xffff,
1449 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1450 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1451 },
1452 [NL80211_IFTYPE_AP] = {
1453 .tx = 0xffff,
1454 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1455 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1456 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1457 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1458 BIT(IEEE80211_STYPE_AUTH >> 4) |
1459 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1460 BIT(IEEE80211_STYPE_ACTION >> 4)
1461 },
1462 [NL80211_IFTYPE_AP_VLAN] = {
1463 /* copy AP */
1464 .tx = 0xffff,
1465 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1466 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1467 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1468 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1469 BIT(IEEE80211_STYPE_AUTH >> 4) |
1470 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1471 BIT(IEEE80211_STYPE_ACTION >> 4)
1472 },
1473 [NL80211_IFTYPE_P2P_CLIENT] = {
1474 .tx = 0xffff,
1475 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1476 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1477 },
1478 [NL80211_IFTYPE_P2P_GO] = {
1479 .tx = 0xffff,
1480 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1481 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1482 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1483 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1484 BIT(IEEE80211_STYPE_AUTH >> 4) |
1485 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1486 BIT(IEEE80211_STYPE_ACTION >> 4)
1487 },
1488 #if defined(WL_CFG80211_P2P_DEV_IF)
1489 [NL80211_IFTYPE_P2P_DEVICE] = {
1490 .tx = 0xffff,
1491 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1492 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1493 },
1494 #endif /* WL_CFG80211_P2P_DEV_IF */
1495 };
1496
1497 static void swap_key_from_BE(struct wl_wsec_key *key)
1498 {
1499 key->index = htod32(key->index);
1500 key->len = htod32(key->len);
1501 key->algo = htod32(key->algo);
1502 key->flags = htod32(key->flags);
1503 key->rxiv.hi = htod32(key->rxiv.hi);
1504 key->rxiv.lo = htod16(key->rxiv.lo);
1505 key->iv_initialized = htod32(key->iv_initialized);
1506 }
1507
1508 static void swap_key_to_BE(struct wl_wsec_key *key)
1509 {
1510 key->index = dtoh32(key->index);
1511 key->len = dtoh32(key->len);
1512 key->algo = dtoh32(key->algo);
1513 key->flags = dtoh32(key->flags);
1514 key->rxiv.hi = dtoh32(key->rxiv.hi);
1515 key->rxiv.lo = dtoh16(key->rxiv.lo);
1516 key->iv_initialized = dtoh32(key->iv_initialized);
1517 }
1518
1519 /* Dump the contents of the encoded wps ie buffer and get pbc value */
1520 static void
1521 wl_validate_wps_ie(const char *wps_ie, s32 wps_ie_len, bool *pbc)
1522 {
1523 #define WPS_IE_FIXED_LEN 6
1524 s16 len;
1525 const u8 *subel = NULL;
1526 u16 subelt_id;
1527 u16 subelt_len;
1528 u16 val;
1529 u8 *valptr = (uint8*) &val;
1530 if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
1531 WL_ERR(("invalid argument : NULL\n"));
1532 return;
1533 }
1534 len = (s16)wps_ie[TLV_LEN_OFF];
1535
1536 if (len > wps_ie_len) {
1537 WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
1538 return;
1539 }
1540 WL_DBG(("wps_ie len=%d\n", len));
1541 len -= 4; /* for the WPS IE's OUI, oui_type fields */
1542 subel = wps_ie + WPS_IE_FIXED_LEN;
1543 while (len >= 4) { /* must have attr id, attr len fields */
1544 valptr[0] = *subel++;
1545 valptr[1] = *subel++;
1546 subelt_id = HTON16(val);
1547
1548 valptr[0] = *subel++;
1549 valptr[1] = *subel++;
1550 subelt_len = HTON16(val);
1551
1552 len -= 4; /* for the attr id, attr len fields */
1553 len -= (s16)subelt_len; /* for the remaining fields in this attribute */
1554 if (len < 0) {
1555 break;
1556 }
1557 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
1558 subel, subelt_id, subelt_len));
1559
1560 if (subelt_id == WPS_ID_VERSION) {
1561 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
1562 } else if (subelt_id == WPS_ID_REQ_TYPE) {
1563 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
1564 } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
1565 valptr[0] = *subel;
1566 valptr[1] = *(subel + 1);
1567 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
1568 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
1569 char devname[33];
1570 int namelen = MIN(subelt_len, (sizeof(devname) - 1));
1571
1572 if (namelen) {
1573 memcpy(devname, subel, namelen);
1574 devname[namelen] = '\0';
1575 /* Printing len as rx'ed in the IE */
1576 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1577 devname, subelt_len));
1578 }
1579 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
1580 valptr[0] = *subel;
1581 valptr[1] = *(subel + 1);
1582 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
1583 *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
1584 } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
1585 valptr[0] = *subel;
1586 valptr[1] = *(subel + 1);
1587 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
1588 valptr[0] = *(subel + 6);
1589 valptr[1] = *(subel + 7);
1590 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
1591 } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
1592 valptr[0] = *subel;
1593 valptr[1] = *(subel + 1);
1594 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
1595 valptr[0] = *(subel + 6);
1596 valptr[1] = *(subel + 7);
1597 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
1598 } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
1599 valptr[0] = *subel;
1600 valptr[1] = *(subel + 1);
1601 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1602 ": cat=%u\n", HTON16(val)));
1603 } else {
1604 WL_DBG((" unknown attr 0x%x\n", subelt_id));
1605 }
1606
1607 subel += subelt_len;
1608 }
1609 }
1610
1611 s32 wl_set_tx_power(struct net_device *dev,
1612 enum nl80211_tx_power_setting type, s32 dbm)
1613 {
1614 s32 err = 0;
1615 s32 disable = 0;
1616 s32 txpwrqdbm;
1617 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1618
1619 /* Make sure radio is off or on as far as software is concerned */
1620 disable = WL_RADIO_SW_DISABLE << 16;
1621 disable = htod32(disable);
1622 err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable));
1623 if (unlikely(err)) {
1624 WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
1625 return err;
1626 }
1627
1628 if (dbm > 0xffff)
1629 dbm = 0xffff;
1630 txpwrqdbm = dbm * 4;
1631 #ifdef SUPPORT_WL_TXPOWER
1632 if (type == NL80211_TX_POWER_AUTOMATIC)
1633 txpwrqdbm = 127;
1634 else
1635 txpwrqdbm |= WL_TXPWR_OVERRIDE;
1636 #endif /* SUPPORT_WL_TXPOWER */
1637 err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
1638 sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
1639 &cfg->ioctl_buf_sync);
1640 if (unlikely(err))
1641 WL_ERR(("qtxpower error (%d)\n", err));
1642 else
1643 WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
1644
1645 return err;
1646 }
1647
1648 s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
1649 {
1650 s32 err = 0;
1651 s32 txpwrdbm;
1652 char ioctl_buf[WLC_IOCTL_SMLEN];
1653
1654 err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
1655 NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
1656 if (unlikely(err)) {
1657 WL_ERR(("error (%d)\n", err));
1658 return err;
1659 }
1660
1661 memcpy(&txpwrdbm, ioctl_buf, sizeof(txpwrdbm));
1662 txpwrdbm = dtoh32(txpwrdbm);
1663 *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
1664
1665 WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
1666
1667 return err;
1668 }
1669
1670 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
1671 {
1672 chanspec_t chspec;
1673 int cur_band, err = 0;
1674 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1675 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
1676 struct ether_addr bssid;
1677 wl_bss_info_t *bss = NULL;
1678 u16 channel = WL_P2P_TEMP_CHAN;
1679 char *buf;
1680
1681 memset(&bssid, 0, sizeof(bssid));
1682 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) {
1683 /* STA interface is not associated. So start the new interface on a temp
1684 * channel . Later proper channel will be applied by the above framework
1685 * via set_channel (cfg80211 API).
1686 */
1687 WL_DBG(("Not associated. Return a temp channel. \n"));
1688 cur_band = 0;
1689 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(int));
1690 if (unlikely(err)) {
1691 WL_ERR(("Get band failed\n"));
1692 } else if (cur_band == WLC_BAND_5G) {
1693 channel = WL_P2P_TEMP_CHAN_5G;
1694 }
1695 return wl_ch_host_to_driver(channel);
1696 }
1697
1698 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
1699 if (!buf) {
1700 WL_ERR(("buf alloc failed. use temp channel\n"));
1701 return wl_ch_host_to_driver(channel);
1702 }
1703
1704 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1705 if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf,
1706 WL_EXTRA_BUF_MAX))) {
1707 WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1708 chspec = wl_ch_host_to_driver(channel);
1709 }
1710 else {
1711 bss = (wl_bss_info_t *) (buf + 4);
1712 chspec = bss->chanspec;
1713
1714 WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
1715 }
1716
1717 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
1718 return chspec;
1719 }
1720
1721 static void
1722 wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable)
1723 {
1724 #ifdef PROP_TXSTATUS_VSDB
1725 #if defined(BCMSDIO)
1726 bool wlfc_enabled = FALSE;
1727 s32 err;
1728 dhd_pub_t *dhd;
1729 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1730
1731 dhd = (dhd_pub_t *)(cfg->pub);
1732 if (!dhd) {
1733 return;
1734 }
1735
1736 if (enable) {
1737 if (!cfg->wlfc_on && !disable_proptx) {
1738 dhd_wlfc_get_enable(dhd, &wlfc_enabled);
1739 if (!wlfc_enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1740 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1741 dhd_wlfc_init(dhd);
1742 err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32));
1743 if (err < 0)
1744 WL_ERR(("WLC_UP return err:%d\n", err));
1745 }
1746 cfg->wlfc_on = true;
1747 WL_DBG(("wlfc_on:%d \n", cfg->wlfc_on));
1748 }
1749 } else {
1750 dhd_wlfc_deinit(dhd);
1751 cfg->wlfc_on = false;
1752 }
1753 #endif /* defined(BCMSDIO) */
1754 #endif /* PROP_TXSTATUS_VSDB */
1755 }
1756
1757 struct wireless_dev *
1758 wl_cfg80211_p2p_if_add(struct bcm_cfg80211 *cfg,
1759 wl_iftype_t wl_iftype,
1760 char const *name, u8 *mac_addr, s32 *ret_err)
1761 {
1762 u16 chspec;
1763 s16 cfg_type;
1764 long timeout;
1765 s32 err;
1766 u16 p2p_iftype;
1767 int dhd_mode;
1768 struct net_device *new_ndev = NULL;
1769 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
1770 struct ether_addr *p2p_addr;
1771
1772 *ret_err = BCME_OK;
1773 if (!cfg->p2p) {
1774 WL_ERR(("p2p not initialized\n"));
1775 return NULL;
1776 }
1777 #if defined(WL_CFG80211_P2P_DEV_IF)
1778 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
1779 /* Handle Dedicated P2P discovery Interface */
1780 return wl_cfgp2p_add_p2p_disc_if(cfg);
1781 }
1782 #endif /* WL_CFG80211_P2P_DEV_IF */
1783
1784 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1785 p2p_iftype = WL_P2P_IF_GO;
1786 } else {
1787 p2p_iftype = WL_P2P_IF_CLIENT;
1788 }
1789
1790 /* Dual p2p doesn't support multiple P2PGO interfaces,
1791 * p2p_go_count is the counter for GO creation
1792 * requests.
1793 */
1794 if ((cfg->p2p->p2p_go_count > 0) && (wl_iftype == WL_IF_TYPE_P2P_GO)) {
1795 WL_ERR(("FW does not support multiple GO\n"));
1796 *ret_err = -ENOTSUPP;
1797 return NULL;
1798 }
1799 if (!cfg->p2p->on) {
1800 p2p_on(cfg) = true;
1801 wl_cfgp2p_set_firm_p2p(cfg);
1802 wl_cfgp2p_init_discovery(cfg);
1803 }
1804
1805 strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1);
1806 cfg->p2p->vir_ifname[IFNAMSIZ - 1] = '\0';
1807 /* In concurrency case, STA may be already associated in a particular channel.
1808 * so retrieve the current channel of primary interface and then start the virtual
1809 * interface on that.
1810 */
1811 chspec = wl_cfg80211_get_shared_freq(wiphy);
1812
1813 /* For P2P mode, use P2P-specific driver features to create the
1814 * bss: "cfg p2p_ifadd"
1815 */
1816 if (wl_check_dongle_idle(wiphy) != TRUE) {
1817 WL_ERR(("FW is busy to add interface"));
1818 return ERR_PTR(-ENOMEM);
1819 }
1820 wl_set_p2p_status(cfg, IF_ADDING);
1821 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
1822 cfg_type = wl_cfgp2p_get_conn_idx(cfg);
1823 if (cfg_type == BCME_ERROR) {
1824 wl_clr_p2p_status(cfg, IF_ADDING);
1825 WL_ERR(("Failed to get connection idx for p2p interface"));
1826 return NULL;
1827 }
1828
1829 p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
1830 memcpy(p2p_addr->octet, mac_addr, ETH_ALEN);
1831
1832 err = wl_cfgp2p_ifadd(cfg, p2p_addr,
1833 htod32(p2p_iftype), chspec);
1834 if (unlikely(err)) {
1835 wl_clr_p2p_status(cfg, IF_ADDING);
1836 WL_ERR((" virtual iface add failed (%d) \n", err));
1837 return NULL;
1838 }
1839
1840 /* Wait for WLC_E_IF event with IF_ADD opcode */
1841 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1842 ((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
1843 (cfg->if_event_info.valid)),
1844 msecs_to_jiffies(MAX_WAIT_TIME));
1845 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
1846 wl_if_event_info *event = &cfg->if_event_info;
1847 new_ndev = wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg), event,
1848 event->mac, cfg->p2p->vir_ifname, false);
1849 if (unlikely(!new_ndev)) {
1850 goto fail;
1851 }
1852
1853 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1854 cfg->p2p->p2p_go_count++;
1855 }
1856 /* Fill p2p specific data */
1857 wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
1858 wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
1859
1860 WL_ERR((" virtual interface(%s) is "
1861 "created net attach done\n", cfg->p2p->vir_ifname));
1862 dhd_mode = (wl_iftype == WL_IF_TYPE_P2P_GC) ?
1863 DHD_FLAG_P2P_GC_MODE : DHD_FLAG_P2P_GO_MODE;
1864 DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
1865 /* reinitialize completion to clear previous count */
1866 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1867 INIT_COMPLETION(cfg->iface_disable);
1868 #else
1869 init_completion(&cfg->iface_disable);
1870 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
1871
1872 return new_ndev->ieee80211_ptr;
1873 }
1874
1875 fail:
1876 return NULL;
1877 }
1878
1879 static s32
1880 wl_check_vif_support(struct bcm_cfg80211 *cfg, wl_iftype_t wl_iftype)
1881 {
1882 s32 ret = BCME_OK;
1883 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
1884
1885 #ifdef WL_NAN
1886 if ((cfg->nan_enable) && (wl_iftype != WL_IF_TYPE_NAN)) {
1887 ret = wl_cfgnan_disable(cfg, NAN_CONCURRENCY_CONFLICT);
1888 if (ret != BCME_OK) {
1889 WL_ERR(("failed to disable nan, error[%d]\n", ret));
1890 goto exit;
1891 }
1892 }
1893 #endif /* WL_NAN */
1894 /* If P2PGroup/Softap is enabled, another VIF
1895 * iface create request can't be supported
1896 */
1897 if ((wl_cfgp2p_vif_created(cfg)) ||
1898 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
1899 WL_ERR(("Additional vif can't be supported [%d]\n",
1900 dhd->op_mode));
1901 ret = -ENOTSUPP;
1902 goto exit;
1903 }
1904 exit:
1905 return ret;
1906 }
1907
1908 void
1909 wl_cfg80211_iface_state_ops(struct wireless_dev *wdev,
1910 wl_interface_state_t state,
1911 wl_iftype_t wl_iftype, u16 wl_mode)
1912 {
1913 struct net_device *ndev;
1914 struct bcm_cfg80211 *cfg;
1915 #if defined(CUSTOM_SET_CPUCORE)
1916 dhd_pub_t *dhd;
1917 #endif // endif
1918 s32 bssidx;
1919
1920 WL_DBG(("state:%s wl_iftype:%d mode:%d\n",
1921 wl_if_state_strs[state], wl_iftype, wl_mode));
1922 if (!wdev) {
1923 WL_ERR(("wdev null\n"));
1924 return;
1925 }
1926
1927 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_NAN_NMI)) {
1928 /* P2P discovery is a netless device and uses a
1929 * hidden bsscfg interface in fw. Don't apply the
1930 * iface ops state changes for p2p discovery I/F.
1931 * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
1932 * Don't apply iface ops state changes for NMI I/F.
1933 */
1934 return;
1935 }
1936
1937 cfg = wiphy_priv(wdev->wiphy);
1938 ndev = wdev->netdev;
1939 #ifdef CUSTOM_SET_CPUCORE
1940 dhd = (dhd_pub_t *)(cfg->pub);
1941 #endif /* CUSTOM_SET_CPUCORE */
1942
1943 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
1944 if (!ndev || (bssidx < 0)) {
1945 WL_ERR(("ndev null. skip iface state ops\n"));
1946 return;
1947 }
1948
1949 switch (state) {
1950 case WL_IF_CREATE_REQ:
1951 #ifdef WL_BCNRECV
1952 /* check fakeapscan in progress then abort */
1953 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
1954 #endif /* WL_BCNRECV */
1955 wl_cfg80211_scan_abort(cfg);
1956 wl_wlfc_enable(cfg, true);
1957
1958 #ifdef WLTDLS
1959 if (wl_iftype == WL_IF_TYPE_NAN) {
1960 /* disable TDLS on NAN IF create */
1961 wl_cfg80211_tdls_config(cfg, TDLS_STATE_NDI_CREATE, false);
1962 }
1963 else {
1964 /* disable TDLS if number of connected interfaces is >= 1 */
1965 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_CREATE, false);
1966 }
1967 #endif /* WLTDLS */
1968 break;
1969 case WL_IF_DELETE_REQ:
1970 #ifdef WL_WPS_SYNC
1971 wl_wps_handle_ifdel(ndev);
1972 #endif /* WPS_SYNC */
1973 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
1974 /* Send completion for any pending scans */
1975 wl_cfg80211_cancel_scan(cfg);
1976 }
1977
1978 #ifdef CUSTOM_SET_CPUCORE
1979 dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
1980 if (!(dhd->chan_isvht80)) {
1981 dhd_set_cpucore(dhd, FALSE);
1982 }
1983 #endif /* CUSTOM_SET_CPUCORE */
1984 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
1985 break;
1986 case WL_IF_CREATE_DONE:
1987 if (wl_mode == WL_MODE_BSS) {
1988 /* Common code for sta type interfaces - STA, GC */
1989 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
1990 }
1991 if (wl_iftype == WL_IF_TYPE_P2P_GC) {
1992 /* Disable firmware roaming for P2P interface */
1993 wldev_iovar_setint(ndev, "roam_off", 1);
1994 }
1995 if (wl_mode == WL_MODE_AP) {
1996 /* Common code for AP/GO */
1997 }
1998 break;
1999 case WL_IF_DELETE_DONE:
2000 #ifdef WLTDLS
2001 /* Enable back TDLS if connected interface is <= 1 */
2002 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2003 #endif /* WLTDLS */
2004 wl_wlfc_enable(cfg, false);
2005 break;
2006 case WL_IF_CHANGE_REQ:
2007 /* Flush existing IEs from firmware on role change */
2008 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
2009 break;
2010 case WL_IF_CHANGE_DONE:
2011 if (wl_mode == WL_MODE_BSS) {
2012 /* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2013 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2014 }
2015 break;
2016
2017 default:
2018 WL_ERR(("Unsupported state: %d\n", state));
2019 return;
2020 }
2021 }
2022
2023 static s32
2024 wl_cfg80211_p2p_if_del(struct wiphy *wiphy, struct wireless_dev *wdev)
2025 {
2026 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2027 s16 bssidx;
2028 s16 err;
2029 s32 cfg_type;
2030 struct net_device *ndev;
2031 long timeout;
2032
2033 if (unlikely(!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
2034 WL_INFORM_MEM(("device is not ready\n"));
2035 return BCME_NOTFOUND;
2036 }
2037
2038 #ifdef WL_CFG80211_P2P_DEV_IF
2039 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2040 /* Handle dedicated P2P discovery interface. */
2041 return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
2042 }
2043 #endif /* WL_CFG80211_P2P_DEV_IF */
2044
2045 /* Handle P2P Group Interface */
2046 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2047 if (bssidx <= 0) {
2048 WL_ERR(("bssidx not found\n"));
2049 return BCME_NOTFOUND;
2050 }
2051 if (wl_cfgp2p_find_type(cfg, bssidx, &cfg_type) != BCME_OK) {
2052 /* Couldn't find matching iftype */
2053 WL_MEM(("non P2P interface\n"));
2054 return BCME_NOTFOUND;
2055 }
2056
2057 if (wl_check_dongle_idle(wiphy) != TRUE) {
2058 WL_ERR(("FW is busy to add interface"));
2059 return BCME_ERROR;
2060 }
2061
2062 ndev = wdev->netdev;
2063 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2064 wl_clr_p2p_status(cfg, IF_ADDING);
2065
2066 /* for GO */
2067 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
2068 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
2069 cfg->p2p->p2p_go_count--;
2070 /* disable interface before bsscfg free */
2071 err = wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2072 /* if fw doesn't support "ifdis",
2073 do not wait for link down of ap mode
2074 */
2075 if (err == 0) {
2076 WL_ERR(("Wait for Link Down event for GO !!!\n"));
2077 wait_for_completion_timeout(&cfg->iface_disable,
2078 msecs_to_jiffies(500));
2079 } else if (err != BCME_UNSUPPORTED) {
2080 msleep(300);
2081 }
2082 } else {
2083 /* GC case */
2084 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
2085 WL_ERR(("Wait for Link Down event for GC !\n"));
2086 wait_for_completion_timeout
2087 (&cfg->iface_disable, msecs_to_jiffies(500));
2088 }
2089 }
2090
2091 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
2092 wl_set_p2p_status(cfg, IF_DELETING);
2093 DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
2094
2095 err = wl_cfgp2p_ifdel(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2096 if (unlikely(err)) {
2097 WL_ERR(("IFDEL operation failed, error code = %d\n", err));
2098 goto fail;
2099 } else {
2100 /* Wait for WLC_E_IF event */
2101 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2102 ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
2103 (cfg->if_event_info.valid)),
2104 msecs_to_jiffies(MAX_WAIT_TIME));
2105 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
2106 cfg->if_event_info.valid) {
2107 WL_ERR(("P2P IFDEL operation done\n"));
2108 err = BCME_OK;
2109 } else {
2110 WL_ERR(("IFDEL didn't complete properly\n"));
2111 err = -EINVAL;
2112 }
2113 }
2114
2115 fail:
2116 /* Even in failure case, attempt to remove the host data structure.
2117 * Firmware would be cleaned up via WiFi reset done by the
2118 * user space from hang event context (for android only).
2119 */
2120 memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
2121 wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
2122 wl_to_p2p_bss_ndev(cfg, cfg_type) = NULL;
2123 wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, cfg_type));
2124 dhd_net_if_lock(ndev);
2125 if (cfg->if_event_info.ifidx) {
2126 /* Remove interface except for primary ifidx */
2127 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
2128 }
2129 dhd_net_if_unlock(ndev);
2130 return err;
2131 }
2132
2133 static struct wireless_dev *
2134 wl_cfg80211_add_monitor_if(struct wiphy *wiphy, const char *name)
2135 {
2136 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
2137 WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2138 return ERR_PTR(-EOPNOTSUPP);
2139 #else
2140 struct wireless *wdev;
2141 struct net_device* ndev = NULL;
2142
2143 dhd_add_monitor(name, &ndev);
2144
2145 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2146 if (!wdev) {
2147 WL_ERR(("wireless_dev alloc failed! \n"));
2148 goto fail;
2149 }
2150
2151 wdev->wiphy = wiphy;
2152 wdev->iftype = iface_type;
2153 ndev->ieee80211_ptr = wdev;
2154 SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
2155
2156 WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
2157 return ndev->ieee80211_ptr;
2158 #endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */
2159 }
2160
2161 static struct wireless_dev *
2162 wl_cfg80211_add_ibss(struct wiphy *wiphy, u16 wl_iftype, char const *name)
2163 {
2164 #ifdef WLAIBSS_MCHAN
2165 /* AIBSS */
2166 return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
2167 #else
2168 /* Normal IBSS */
2169 WL_ERR(("IBSS not supported on Virtual iface\n"));
2170 return NULL;
2171 #endif // endif
2172 }
2173
2174 s32
2175 wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype)
2176 {
2177 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2178 u16 org_toggle_bytes;
2179 u16 cur_toggle_bytes;
2180 u16 toggled_bit;
2181
2182 if (!ndev || !mac_addr) {
2183 return -EINVAL;
2184 }
2185
2186 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_AP) ||
2187 (wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2188 /* Avoid invoking release mac addr code for interfaces using
2189 * fixed mac addr.
2190 */
2191 return BCME_OK;
2192 }
2193
2194 /* Fetch last two bytes of mac address */
2195 org_toggle_bytes = ntoh16(*((u16 *)&ndev->dev_addr[4]));
2196 cur_toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
2197
2198 toggled_bit = (org_toggle_bytes ^ cur_toggle_bytes);
2199 WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n",
2200 org_toggle_bytes, cur_toggle_bytes));
2201 if (toggled_bit & cfg->vif_macaddr_mask) {
2202 /* This toggled_bit is marked in the used mac addr
2203 * mask. Clear it.
2204 */
2205 cfg->vif_macaddr_mask &= ~toggled_bit;
2206 WL_INFORM(("MAC address - " MACDBG " released. toggled_bit:%04X vif_mask:%04X\n",
2207 MAC2STRDBG(mac_addr), toggled_bit, cfg->vif_macaddr_mask));
2208 } else {
2209 WL_ERR(("MAC address - " MACDBG " not found in the used list."
2210 " toggled_bit:%04x vif_mask:%04x\n", MAC2STRDBG(mac_addr),
2211 toggled_bit, cfg->vif_macaddr_mask));
2212 return -EINVAL;
2213 }
2214
2215 return BCME_OK;
2216 }
2217
2218 s32
2219 wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr)
2220 {
2221 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2222 u16 toggle_mask;
2223 u16 toggle_bit;
2224 u16 toggle_bytes;
2225 u16 used;
2226 u32 offset = 0;
2227 /* Toggle mask starts from MSB of second last byte */
2228 u16 mask = 0x8000;
2229
2230 if (!mac_addr) {
2231 return -EINVAL;
2232 }
2233
2234 memcpy(mac_addr, ndev->dev_addr, ETH_ALEN);
2235 /*
2236 * VIF MAC address managment
2237 * P2P Device addres: Primary MAC with locally admin. bit set
2238 * P2P Group address/NAN NMI/Softap/NAN DPI: Primary MAC addr
2239 * with local admin bit set and one additional bit toggled.
2240 * cfg->vif_macaddr_mask will hold the info regarding the mac address
2241 * released. Ensure to call wl_release_vif_macaddress to free up
2242 * the mac address.
2243 */
2244 if (wl_iftype == WL_IF_TYPE_P2P_DISC || wl_iftype == WL_IF_TYPE_AP) {
2245 mac_addr[0] |= 0x02;
2246 } else if ((wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2247 mac_addr[0] |= 0x02;
2248 mac_addr[4] ^= 0x80;
2249 } else {
2250 /* For locally administered mac addresses, we keep the
2251 * OUI part constant and just work on the last two bytes.
2252 */
2253 mac_addr[0] |= 0x02;
2254 toggle_mask = cfg->vif_macaddr_mask;
2255 toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
2256 do {
2257 used = toggle_mask & mask;
2258 if (!used) {
2259 /* Use this bit position */
2260 toggle_bit = mask >> offset;
2261 toggle_bytes ^= toggle_bit;
2262 cfg->vif_macaddr_mask |= toggle_bit;
2263 WL_DBG(("toggle_bit:%04X toggle_bytes:%04X toggle_mask:%04X\n",
2264 toggle_bit, toggle_bytes, cfg->vif_macaddr_mask));
2265 /* Macaddress are stored in network order */
2266 mac_addr[5] = *((u8 *)&toggle_bytes);
2267 mac_addr[4] = *(((u8 *)&toggle_bytes + 1));
2268 break;
2269 }
2270
2271 /* Shift by one */
2272 toggle_mask = toggle_mask << 0x1;
2273 offset++;
2274 if (offset > MAX_VIF_OFFSET) {
2275 /* We have used up all macaddresses. Something wrong! */
2276 WL_ERR(("Entire range of macaddress used up.\n"));
2277 ASSERT(0);
2278 break;
2279 }
2280 } while (true);
2281 }
2282 WL_INFORM_MEM(("Get virtual I/F mac addr: "MACDBG"\n", MAC2STRDBG(mac_addr)));
2283 return 0;
2284 }
2285
2286 /* All Android/Linux private/Vendor Interface calls should make
2287 * use of below API for interface creation.
2288 */
2289 struct wireless_dev *
2290 wl_cfg80211_add_if(struct bcm_cfg80211 *cfg,
2291 struct net_device *primary_ndev,
2292 wl_iftype_t wl_iftype, const char *name, u8 *mac)
2293 {
2294 u8 mac_addr[ETH_ALEN];
2295 s32 err = -ENODEV;
2296 struct wireless_dev *wdev = NULL;
2297 struct wiphy *wiphy;
2298 s32 wl_mode;
2299 dhd_pub_t *dhd;
2300 wl_iftype_t macaddr_iftype = wl_iftype;
2301
2302 WL_INFORM_MEM(("if name: %s, wl_iftype:%d \n",
2303 name ? name : "NULL", wl_iftype));
2304 if (!cfg || !primary_ndev || !name) {
2305 WL_ERR(("cfg/ndev/name ptr null\n"));
2306 return NULL;
2307 }
2308 if (wl_cfg80211_get_wdev_from_ifname(cfg, name)) {
2309 WL_ERR(("Interface name %s exists!\n", name));
2310 return NULL;
2311 }
2312 wiphy = bcmcfg_to_wiphy(cfg);
2313 dhd = (dhd_pub_t *)(cfg->pub);
2314 if (!dhd) {
2315 return NULL;
2316 }
2317
2318 if ((wl_mode = wl_iftype_to_mode(wl_iftype)) < 0) {
2319 return NULL;
2320 }
2321
2322 if ((err = wl_check_vif_support(cfg, wl_iftype)) < 0) {
2323 return NULL;
2324 }
2325
2326 /* Protect the interace op context */
2327 mutex_lock(&cfg->if_sync);
2328 /* Do pre-create ops */
2329 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CREATE_REQ,
2330 wl_iftype, wl_mode);
2331
2332 if (strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)) == 0) {
2333 macaddr_iftype = WL_IF_TYPE_AP;
2334 }
2335
2336 if (mac) {
2337 /* If mac address is provided, use that */
2338 memcpy(mac_addr, mac, ETH_ALEN);
2339 } else if ((wl_get_vif_macaddr(cfg, macaddr_iftype, mac_addr) != BCME_OK)) {
2340 /* Fetch the mac address to be used for virtual interface */
2341 err = -EINVAL;
2342 goto fail;
2343 }
2344
2345 switch (wl_iftype) {
2346 case WL_IF_TYPE_IBSS:
2347 wdev = wl_cfg80211_add_ibss(wiphy, wl_iftype, name);
2348 break;
2349 case WL_IF_TYPE_MONITOR:
2350 wdev = wl_cfg80211_add_monitor_if(wiphy, name);
2351 break;
2352 case WL_IF_TYPE_STA:
2353 case WL_IF_TYPE_AP:
2354 case WL_IF_TYPE_NAN:
2355 if (cfg->iface_cnt >= (IFACE_MAX_CNT - 1)) {
2356 WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
2357 cfg->iface_cnt));
2358 err = -ENOTSUPP;
2359 goto fail;
2360 }
2361 wdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
2362 wl_iftype, mac_addr, name);
2363 break;
2364 case WL_IF_TYPE_P2P_DISC:
2365 case WL_IF_TYPE_P2P_GO:
2366 /* Intentional fall through */
2367 case WL_IF_TYPE_P2P_GC:
2368 if (cfg->p2p_supported) {
2369 wdev = wl_cfg80211_p2p_if_add(cfg, wl_iftype,
2370 name, mac_addr, &err);
2371 break;
2372 }
2373 /* Intentionally fall through for unsupported interface
2374 * handling when firmware doesn't support p2p
2375 */
2376 default:
2377 WL_ERR(("Unsupported interface type\n"));
2378 err = -ENOTSUPP;
2379 goto fail;
2380 }
2381
2382 if (!wdev) {
2383 if (err != -ENOTSUPP) {
2384 err = -ENODEV;
2385 }
2386 WL_ERR(("vif create failed. err:%d\n", err));
2387 goto fail;
2388 }
2389
2390 /* Ensure decrementing in case of failure */
2391 cfg->vif_count++;
2392
2393 wl_cfg80211_iface_state_ops(wdev,
2394 WL_IF_CREATE_DONE, wl_iftype, wl_mode);
2395
2396 WL_INFORM_MEM(("Vif created."
2397 " dev->ifindex:%d cfg_iftype:%d, vif_count:%d\n",
2398 (wdev->netdev ? wdev->netdev->ifindex : 0xff),
2399 wdev->iftype, cfg->vif_count));
2400 mutex_unlock(&cfg->if_sync);
2401 return wdev;
2402
2403 fail:
2404 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
2405 WL_IF_DELETE_REQ, wl_iftype, wl_mode);
2406
2407 if (err != -ENOTSUPP) {
2408 /* For non-supported interfaces, just return error and
2409 * skip below recovery steps.
2410 */
2411 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2412 wl_copy_hang_info_if_falure(primary_ndev, HANG_REASON_IFACE_DEL_FAILURE, err);
2413 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2414 SUPP_LOG(("IF_ADD fail. err:%d\n", err));
2415 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
2416 #if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
2417 if (dhd->memdump_enabled) {
2418 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
2419 dhd_bus_mem_dump(dhd);
2420 }
2421 #endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
2422 dhd->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
2423 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2424 }
2425 mutex_unlock(&cfg->if_sync);
2426 return NULL;
2427 }
2428
2429 static bcm_struct_cfgdev *
2430 wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
2431 #if defined(WL_CFG80211_P2P_DEV_IF)
2432 const char *name,
2433 #else
2434 char *name,
2435 #endif /* WL_CFG80211_P2P_DEV_IF */
2436 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
2437 unsigned char name_assign_type,
2438 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
2439 enum nl80211_iftype type, u32 *flags,
2440 struct vif_params *params)
2441 {
2442 u16 wl_iftype;
2443 u16 wl_mode;
2444 struct net_device *primary_ndev;
2445 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2446 struct wireless_dev *wdev;
2447
2448 WL_DBG(("Enter iftype: %d\n", type));
2449 if (!cfg) {
2450 return ERR_PTR(-EINVAL);
2451 }
2452
2453 /* Use primary I/F for sending cmds down to firmware */
2454 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
2455 if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
2456 WL_ERR(("device is not ready\n"));
2457 return ERR_PTR(-ENODEV);
2458 }
2459 #if defined(SUPPORT_RANDOM_MAC_SCAN) && defined(DHD_RANDOM_MAC_SCAN)
2460 wl_cfg80211_random_mac_disable(primary_ndev);
2461 #endif /* SUPPORT_RANDOM_MAC_SCAN && DHD_RANDOM_MAC_SCAN */
2462 if (!name) {
2463 WL_ERR(("Interface name not provided \n"));
2464 return ERR_PTR(-EINVAL);
2465 }
2466
2467 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
2468 return ERR_PTR(-EINVAL);
2469 }
2470
2471 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, name, NULL);
2472 if (unlikely(!wdev)) {
2473 return ERR_PTR(-ENODEV);
2474 }
2475
2476 return wdev_to_cfgdev(wdev);
2477 }
2478
2479 static s32
2480 wl_cfg80211_del_ibss(struct wiphy *wiphy, struct wireless_dev *wdev)
2481 {
2482 WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev));
2483 #ifdef WLAIBSS_MCHAN
2484 /* AIBSS */
2485 return bcm_cfg80211_del_ibss_if(wiphy, wdev);
2486 #else
2487 /* Normal IBSS */
2488 return wl_cfg80211_del_iface(wiphy, wdev);
2489 #endif // endif
2490 }
2491
2492 s32
2493 wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
2494 struct wireless_dev *wdev, char *ifname)
2495 {
2496 int ret = BCME_OK;
2497 s32 bssidx;
2498 struct wiphy *wiphy;
2499 u16 wl_mode;
2500 u16 wl_iftype;
2501 struct net_info *netinfo;
2502 dhd_pub_t *dhd;
2503 BCM_REFERENCE(dhd);
2504
2505 if (!cfg) {
2506 return -EINVAL;
2507 }
2508
2509 mutex_lock(&cfg->if_sync);
2510 dhd = (dhd_pub_t *)(cfg->pub);
2511
2512 if (!wdev && ifname) {
2513 /* If only ifname is provided, fetch corresponding wdev ptr from our
2514 * internal data structure
2515 */
2516 wdev = wl_cfg80211_get_wdev_from_ifname(cfg, ifname);
2517 }
2518
2519 /* Check whether we have a valid wdev ptr */
2520 if (unlikely(!wdev)) {
2521 WL_ERR(("wdev not found. '%s' does not exists\n", ifname));
2522 mutex_unlock(&cfg->if_sync);
2523 return -ENODEV;
2524 }
2525
2526 WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev->iftype));
2527
2528 wiphy = wdev->wiphy;
2529 #ifdef WL_CFG80211_P2P_DEV_IF
2530 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2531 /* p2p discovery would be de-initialized in stop p2p
2532 * device context/from other virtual i/f creation context
2533 * so netinfo list may not have any node corresponding to
2534 * discovery I/F. Handle it before bssidx check.
2535 */
2536 ret = wl_cfg80211_p2p_if_del(wiphy, wdev);
2537 if (unlikely(ret)) {
2538 goto exit;
2539 } else {
2540 /* success case. return from here */
2541 if (cfg->vif_count) {
2542 cfg->vif_count--;
2543 }
2544 mutex_unlock(&cfg->if_sync);
2545 return BCME_OK;
2546 }
2547 }
2548 #endif /* WL_CFG80211_P2P_DEV_IF */
2549
2550 if ((netinfo = wl_get_netinfo_by_wdev(cfg, wdev)) == NULL) {
2551 WL_ERR(("Find netinfo from wdev %p failed\n", wdev));
2552 ret = -ENODEV;
2553 goto exit;
2554 }
2555
2556 if (!wdev->netdev) {
2557 WL_ERR(("ndev null! \n"));
2558 } else {
2559 /* Disable tx before del */
2560 netif_tx_disable(wdev->netdev);
2561 }
2562
2563 wl_iftype = netinfo->iftype;
2564 wl_mode = wl_iftype_to_mode(wl_iftype);
2565 bssidx = netinfo->bssidx;
2566 WL_INFORM_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
2567 wdev->iftype, wl_iftype, wl_mode, bssidx));
2568
2569 /* Do pre-interface del ops */
2570 wl_cfg80211_iface_state_ops(wdev, WL_IF_DELETE_REQ, wl_iftype, wl_mode);
2571
2572 switch (wl_iftype) {
2573 case WL_IF_TYPE_P2P_GO:
2574 case WL_IF_TYPE_P2P_GC:
2575 case WL_IF_TYPE_AP:
2576 case WL_IF_TYPE_STA:
2577 case WL_IF_TYPE_NAN:
2578 ret = wl_cfg80211_del_iface(wiphy, wdev);
2579 break;
2580 case WL_IF_TYPE_IBSS:
2581 ret = wl_cfg80211_del_ibss(wiphy, wdev);
2582 break;
2583
2584 default:
2585 WL_ERR(("Unsupported interface type\n"));
2586 ret = BCME_ERROR;
2587 }
2588
2589 exit:
2590 if (ret == BCME_OK) {
2591 /* Successful case */
2592 if (cfg->vif_count) {
2593 cfg->vif_count--;
2594 }
2595 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
2596 WL_IF_DELETE_DONE, wl_iftype, wl_mode);
2597 #ifdef WL_NAN
2598 if (!((cfg->nancfg.mac_rand) && (wl_iftype == WL_IF_TYPE_NAN)))
2599 #endif /* WL_NAN */
2600 {
2601 wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype);
2602 }
2603 WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg->vif_count));
2604 } else {
2605 if (!wdev->netdev) {
2606 WL_ERR(("ndev null! \n"));
2607 } else {
2608 /* IF del failed. revert back tx queue status */
2609 netif_tx_start_all_queues(wdev->netdev);
2610 }
2611
2612 /* Skip generating log files and sending HANG event
2613 * if driver state is not READY
2614 */
2615 if (wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg))) {
2616 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2617 wl_copy_hang_info_if_falure(primary_ndev,
2618 HANG_REASON_IFACE_DEL_FAILURE, ret);
2619 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2620 SUPP_LOG(("IF_DEL fail. err:%d\n", ret));
2621 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
2622 #if defined(DHD_FW_COREDUMP)
2623 if (dhd->memdump_enabled && (ret != -EBADTYPE)) {
2624 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
2625 dhd_bus_mem_dump(dhd);
2626 }
2627 #endif /* BCMDONGLEHOST && DHD_FW_COREDUMP */
2628 WL_ERR(("Notify hang event to upper layer \n"));
2629 dhd->hang_reason = HANG_REASON_IFACE_DEL_FAILURE;
2630 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2631 }
2632 }
2633
2634 mutex_unlock(&cfg->if_sync);
2635 return ret;
2636 }
2637
2638 static s32
2639 wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
2640 {
2641 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2642 struct wireless_dev *wdev = cfgdev_to_wdev(cfgdev);
2643 int ret = BCME_OK;
2644 u16 wl_iftype;
2645 u16 wl_mode;
2646 struct net_device *primary_ndev;
2647
2648 if (!cfg) {
2649 return -EINVAL;
2650 }
2651
2652 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
2653 wdev = cfgdev_to_wdev(cfgdev);
2654 if (!wdev) {
2655 WL_ERR(("wdev null"));
2656 return -ENODEV;
2657 }
2658
2659 WL_DBG(("Enter wdev:%p iftype: %d\n", wdev, wdev->iftype));
2660 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
2661 WL_ERR(("Wrong iftype: %d\n", wdev->iftype));
2662 return -ENODEV;
2663 }
2664
2665 if ((ret = wl_cfg80211_del_if(cfg, primary_ndev,
2666 wdev, NULL)) < 0) {
2667 WL_ERR(("IF del failed\n"));
2668 }
2669
2670 return ret;
2671 }
2672
2673 static s32
2674 wl_cfg80211_change_p2prole(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type)
2675 {
2676 s32 wlif_type;
2677 s32 mode = 0;
2678 s32 index;
2679 s32 err;
2680 s32 conn_idx = -1;
2681 chanspec_t chspec;
2682 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2683 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2684
2685 WL_INFORM_MEM(("Enter. current_role:%d new_role:%d \n", ndev->ieee80211_ptr->iftype, type));
2686
2687 if (!cfg->p2p || !wl_cfgp2p_vif_created(cfg)) {
2688 WL_ERR(("P2P not initialized \n"));
2689 return -EINVAL;
2690 }
2691
2692 if (!is_p2p_group_iface(ndev->ieee80211_ptr)) {
2693 WL_ERR(("Wrong if type \n"));
2694 return -EINVAL;
2695 }
2696
2697 if (wl_check_dongle_idle(wiphy) != TRUE) {
2698 WL_ERR(("FW is busy to add interface"));
2699 return -EINVAL;
2700 }
2701
2702 /* Abort any on-going scans to avoid race condition issues */
2703 wl_cfg80211_cancel_scan(cfg);
2704
2705 index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
2706 if (index < 0) {
2707 WL_ERR(("Find bsscfg index from ndev(%p) failed\n", ndev));
2708 return BCME_ERROR;
2709 }
2710 if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK) {
2711 return BCME_ERROR;
2712 }
2713
2714 /* In concurrency case, STA may be already associated in a particular
2715 * channel. so retrieve the current channel of primary interface and
2716 * then start the virtual interface on that.
2717 */
2718 chspec = wl_cfg80211_get_shared_freq(wiphy);
2719 if (type == NL80211_IFTYPE_P2P_GO) {
2720 /* Dual p2p doesn't support multiple P2PGO interfaces,
2721 * p2p_go_count is the counter for GO creation
2722 * requests.
2723 */
2724 if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
2725 WL_ERR(("FW does not support multiple GO\n"));
2726 return BCME_ERROR;
2727 }
2728 mode = WL_MODE_AP;
2729 wlif_type = WL_P2P_IF_GO;
2730 dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
2731 dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
2732 } else {
2733 wlif_type = WL_P2P_IF_CLIENT;
2734 /* for GO */
2735 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
2736 WL_INFORM_MEM(("Downgrading P2P GO to cfg_iftype:%d \n", type));
2737 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
2738 cfg->p2p->p2p_go_count--;
2739 /* disable interface before bsscfg free */
2740 err = wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx));
2741 /* if fw doesn't support "ifdis",
2742 * do not wait for link down of ap mode
2743 */
2744 if (err == 0) {
2745 WL_DBG(("Wait for Link Down event for GO !!!\n"));
2746 wait_for_completion_timeout(&cfg->iface_disable,
2747 msecs_to_jiffies(500));
2748 } else if (err != BCME_UNSUPPORTED) {
2749 msleep(300);
2750 }
2751 }
2752 }
2753
2754 wl_set_p2p_status(cfg, IF_CHANGING);
2755 wl_clr_p2p_status(cfg, IF_CHANGED);
2756 wl_cfgp2p_ifchange(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx),
2757 htod32(wlif_type), chspec, conn_idx);
2758 wait_event_interruptible_timeout(cfg->netif_change_event,
2759 (wl_get_p2p_status(cfg, IF_CHANGED) == true),
2760 msecs_to_jiffies(MAX_WAIT_TIME));
2761
2762 wl_clr_p2p_status(cfg, IF_CHANGING);
2763 wl_clr_p2p_status(cfg, IF_CHANGED);
2764
2765 if (mode == WL_MODE_AP) {
2766 wl_set_drv_status(cfg, CONNECTED, ndev);
2767 }
2768
2769 return BCME_OK;
2770 }
2771
2772 static s32
2773 wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
2774 enum nl80211_iftype type, u32 *flags,
2775 struct vif_params *params)
2776 {
2777 s32 infra = 1;
2778 s32 err = BCME_OK;
2779 u16 wl_iftype;
2780 u16 wl_mode;
2781 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2782 struct net_info *netinfo = NULL;
2783 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2784 struct net_device *primary_ndev;
2785
2786 if (!dhd)
2787 return -EINVAL;
2788
2789 WL_INFORM_MEM(("[%s] Enter. current cfg_iftype:%d new cfg_iftype:%d \n",
2790 ndev->name, ndev->ieee80211_ptr->iftype, type));
2791 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
2792
2793 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
2794 WL_ERR(("Unknown role \n"));
2795 return -EINVAL;
2796 }
2797
2798 /* If any scan is going on, abort it */
2799 if (wl_abort_scan_and_check(cfg) != TRUE) {
2800 wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
2801 }
2802
2803 mutex_lock(&cfg->if_sync);
2804 netinfo = wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
2805 if (unlikely(!netinfo)) {
2806 #ifdef WL_STATIC_IF
2807 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
2808 /* Incase of static interfaces, the netinfo will be
2809 * allocated only when FW interface is initialized. So
2810 * store the value and use it during initialization.
2811 */
2812 WL_INFORM_MEM(("skip change vif for static if\n"));
2813 ndev->ieee80211_ptr->iftype = type;
2814 err = BCME_OK;
2815 } else
2816 #endif /* WL_STATIC_IF */
2817 {
2818 WL_ERR(("netinfo not found \n"));
2819 err = -ENODEV;
2820 }
2821 goto fail;
2822 }
2823
2824 /* perform pre-if-change tasks */
2825 wl_cfg80211_iface_state_ops(ndev->ieee80211_ptr,
2826 WL_IF_CHANGE_REQ, wl_iftype, wl_mode);
2827
2828 switch (type) {
2829 case NL80211_IFTYPE_ADHOC:
2830 infra = 0;
2831 break;
2832 case NL80211_IFTYPE_STATION:
2833 /* Supplicant sets iftype to STATION while removing p2p GO */
2834 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
2835 /* Downgrading P2P GO */
2836 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
2837 if (unlikely(err)) {
2838 WL_ERR(("P2P downgrade failed \n"));
2839 }
2840 } else if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
2841 /* Downgrade role from AP to STA */
2842 if ((err = wl_cfg80211_add_del_bss(cfg, ndev,
2843 netinfo->bssidx, wl_iftype, 0, NULL)) < 0) {
2844 WL_ERR(("AP-STA Downgrade failed \n"));
2845 goto fail;
2846 }
2847 }
2848 break;
2849 case NL80211_IFTYPE_AP:
2850 /* intentional fall through */
2851 case NL80211_IFTYPE_AP_VLAN:
2852 {
2853 if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
2854 err = wl_cfg80211_set_ap_role(cfg, ndev);
2855 if (unlikely(err)) {
2856 WL_ERR(("set ap role failed!\n"));
2857 goto fail;
2858 }
2859 } else {
2860 WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
2861 }
2862 break;
2863 }
2864 case NL80211_IFTYPE_P2P_GO:
2865 /* Intentional fall through */
2866 case NL80211_IFTYPE_P2P_CLIENT:
2867 infra = 1;
2868 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
2869 break;
2870 case NL80211_IFTYPE_MONITOR:
2871 case NL80211_IFTYPE_WDS:
2872 case NL80211_IFTYPE_MESH_POINT:
2873 /* Intentional fall through */
2874 default:
2875 WL_ERR(("Unsupported type:%d \n", type));
2876 err = -EINVAL;
2877 goto fail;
2878 }
2879
2880 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(s32));
2881 if (err < 0) {
2882 WL_ERR(("SET INFRA/IBSS error %d\n", err));
2883 goto fail;
2884 }
2885
2886 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
2887 WL_IF_CHANGE_DONE, wl_iftype, wl_mode);
2888
2889 /* Update new iftype in relevant structures */
2890 ndev->ieee80211_ptr->iftype = type;
2891 netinfo->iftype = wl_iftype;
2892 WL_INFORM_MEM(("[%s] cfg_iftype changed to %d\n", ndev->name, type));
2893
2894 fail:
2895 if (err) {
2896 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
2897 }
2898 mutex_unlock(&cfg->if_sync);
2899 return err;
2900 }
2901
2902 s32
2903 wl_cfg80211_notify_ifadd(struct net_device *dev,
2904 int ifidx, char *name, uint8 *mac, uint8 bssidx, uint8 role)
2905 {
2906 bool ifadd_expected = FALSE;
2907 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2908 bool bss_pending_op = TRUE;
2909
2910 /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
2911 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
2912 */
2913 if (wl_get_p2p_status(cfg, IF_CHANGING))
2914 return wl_cfg80211_notify_ifchange(dev, ifidx, name, mac, bssidx);
2915
2916 /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
2917 if (wl_get_p2p_status(cfg, IF_ADDING)) {
2918 ifadd_expected = TRUE;
2919 wl_clr_p2p_status(cfg, IF_ADDING);
2920 } else if (cfg->bss_pending_op) {
2921 ifadd_expected = TRUE;
2922 bss_pending_op = FALSE;
2923 }
2924
2925 if (ifadd_expected) {
2926 wl_if_event_info *if_event_info = &cfg->if_event_info;
2927
2928 if_event_info->valid = TRUE;
2929 if_event_info->ifidx = ifidx;
2930 if_event_info->bssidx = bssidx;
2931 if_event_info->role = role;
2932 strncpy(if_event_info->name, name, IFNAMSIZ);
2933 if_event_info->name[IFNAMSIZ] = '\0';
2934 if (mac)
2935 memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
2936
2937 /* Update bss pendig operation status */
2938 if (!bss_pending_op) {
2939 cfg->bss_pending_op = FALSE;
2940 }
2941 WL_INFORM_MEM(("IF_ADD ifidx:%d bssidx:%d role:%d\n",
2942 ifidx, bssidx, role));
2943 wake_up_interruptible(&cfg->netif_change_event);
2944 return BCME_OK;
2945 }
2946
2947 return BCME_ERROR;
2948 }
2949
2950 s32
2951 wl_cfg80211_notify_ifdel(struct net_device *dev, int ifidx, char *name, uint8 *mac, uint8 bssidx)
2952 {
2953 bool ifdel_expected = FALSE;
2954 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2955 wl_if_event_info *if_event_info = &cfg->if_event_info;
2956 bool bss_pending_op = TRUE;
2957
2958 if (wl_get_p2p_status(cfg, IF_DELETING)) {
2959 ifdel_expected = TRUE;
2960 wl_clr_p2p_status(cfg, IF_DELETING);
2961 } else if (cfg->bss_pending_op) {
2962 ifdel_expected = TRUE;
2963 bss_pending_op = FALSE;
2964 }
2965
2966 if (ifdel_expected) {
2967 if_event_info->valid = TRUE;
2968 if_event_info->ifidx = ifidx;
2969 if_event_info->bssidx = bssidx;
2970 /* Update bss pendig operation status */
2971 if (!bss_pending_op) {
2972 cfg->bss_pending_op = FALSE;
2973 }
2974 WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx, bssidx));
2975 wake_up_interruptible(&cfg->netif_change_event);
2976 return BCME_OK;
2977 }
2978
2979 return BCME_ERROR;
2980 }
2981
2982 s32
2983 wl_cfg80211_notify_ifchange(struct net_device * dev, int ifidx, char *name, uint8 *mac,
2984 uint8 bssidx)
2985 {
2986 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2987
2988 if (wl_get_p2p_status(cfg, IF_CHANGING)) {
2989 wl_set_p2p_status(cfg, IF_CHANGED);
2990 wake_up_interruptible(&cfg->netif_change_event);
2991 return BCME_OK;
2992 }
2993
2994 return BCME_ERROR;
2995 }
2996
2997 /* Find listen channel */
2998 static s32 wl_find_listen_channel(struct bcm_cfg80211 *cfg,
2999 const u8 *ie, u32 ie_len)
3000 {
3001 const wifi_p2p_ie_t *p2p_ie;
3002 const u8 *end, *pos;
3003 s32 listen_channel;
3004
3005 pos = (const u8 *)ie;
3006
3007 p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len);
3008
3009 if (p2p_ie == NULL) {
3010 return 0;
3011 }
3012
3013 if (p2p_ie->len < MIN_P2P_IE_LEN || p2p_ie->len > MAX_P2P_IE_LEN) {
3014 CFGP2P_ERR(("p2p_ie->len out of range - %d\n", p2p_ie->len));
3015 return 0;
3016 }
3017
3018 pos = p2p_ie->subelts;
3019 end = p2p_ie->subelts + (p2p_ie->len - 4);
3020
3021 CFGP2P_DBG((" found p2p ie ! lenth %d \n",
3022 p2p_ie->len));
3023
3024 while (pos < end) {
3025 uint16 attr_len;
3026 if (pos + 2 >= end) {
3027 CFGP2P_DBG((" -- Invalid P2P attribute"));
3028 return 0;
3029 }
3030 attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0]));
3031
3032 if (pos + 3 + attr_len > end) {
3033 CFGP2P_DBG(("P2P: Attribute underflow "
3034 "(len=%u left=%d)",
3035 attr_len, (int) (end - pos - 3)));
3036 return 0;
3037 }
3038
3039 /* if Listen Channel att id is 6 and the vailue is valid,
3040 * return the listen channel
3041 */
3042 if (pos[0] == 6) {
3043 /* listen channel subel length format
3044 * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num)
3045 */
3046 listen_channel = pos[1 + 2 + 3 + 1];
3047
3048 if (listen_channel == SOCIAL_CHAN_1 ||
3049 listen_channel == SOCIAL_CHAN_2 ||
3050 listen_channel == SOCIAL_CHAN_3) {
3051 CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel));
3052 return listen_channel;
3053 }
3054 }
3055 pos += 3 + attr_len;
3056 }
3057 return 0;
3058 }
3059
3060 static void wl_scan_prep(struct bcm_cfg80211 *cfg, struct wl_scan_params *params,
3061 struct cfg80211_scan_request *request)
3062 {
3063 u32 n_ssids;
3064 u32 n_channels;
3065 u16 channel;
3066 chanspec_t chanspec;
3067 s32 i = 0, j = 0, offset;
3068 char *ptr;
3069 wlc_ssid_t ssid;
3070
3071 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
3072 params->bss_type = DOT11_BSSTYPE_ANY;
3073 params->scan_type = 0;
3074 params->nprobes = -1;
3075 params->active_time = -1;
3076 params->passive_time = -1;
3077 params->home_time = -1;
3078 params->channel_num = 0;
3079 memset(&params->ssid, 0, sizeof(wlc_ssid_t));
3080
3081 WL_SCAN(("Preparing Scan request\n"));
3082 WL_SCAN(("nprobes=%d\n", params->nprobes));
3083 WL_SCAN(("active_time=%d\n", params->active_time));
3084 WL_SCAN(("passive_time=%d\n", params->passive_time));
3085 WL_SCAN(("home_time=%d\n", params->home_time));
3086 WL_SCAN(("scan_type=%d\n", params->scan_type));
3087
3088 params->nprobes = htod32(params->nprobes);
3089 params->active_time = htod32(params->active_time);
3090 params->passive_time = htod32(params->passive_time);
3091 params->home_time = htod32(params->home_time);
3092
3093 /* if request is null just exit so it will be all channel broadcast scan */
3094 if (!request)
3095 return;
3096
3097 n_ssids = request->n_ssids;
3098 n_channels = request->n_channels;
3099
3100 /* Copy channel array if applicable */
3101 WL_SCAN(("### List of channelspecs to scan ###\n"));
3102 if (n_channels > 0) {
3103 for (i = 0; i < n_channels; i++) {
3104 channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq);
3105 /* SKIP DFS channels for Secondary interface */
3106 if ((cfg->escan_info.ndev != bcmcfg_to_prmry_ndev(cfg)) &&
3107 (request->channels[i]->flags &
3108 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
3109 (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN)))
3110 #else
3111 (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)))
3112 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */
3113 continue;
3114
3115 chanspec = WL_CHANSPEC_BW_20;
3116 if (chanspec == INVCHANSPEC) {
3117 WL_ERR(("Invalid chanspec! Skipping channel\n"));
3118 continue;
3119 }
3120
3121 if (request->channels[i]->band == NL80211_BAND_2GHZ) {
3122 #ifdef WL_HOST_BAND_MGMT
3123 if (cfg->curr_band == WLC_BAND_5G) {
3124 WL_DBG(("In 5G only mode, omit 2G channel:%d\n", channel));
3125 continue;
3126 }
3127 #endif /* WL_HOST_BAND_MGMT */
3128 chanspec |= WL_CHANSPEC_BAND_2G;
3129 } else {
3130 #ifdef WL_HOST_BAND_MGMT
3131 if (cfg->curr_band == WLC_BAND_2G) {
3132 WL_DBG(("In 2G only mode, omit 5G channel:%d\n", channel));
3133 continue;
3134 }
3135 #endif /* WL_HOST_BAND_MGMT */
3136 chanspec |= WL_CHANSPEC_BAND_5G;
3137 }
3138 params->channel_list[j] = channel;
3139 params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK;
3140 params->channel_list[j] |= chanspec;
3141 WL_SCAN(("Chan : %d, Channel spec: %x \n",
3142 channel, params->channel_list[j]));
3143 params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]);
3144 j++;
3145 }
3146 } else {
3147 WL_SCAN(("Scanning all channels\n"));
3148 }
3149 n_channels = j;
3150 /* Copy ssid array if applicable */
3151 WL_SCAN(("### List of SSIDs to scan ###\n"));
3152 if (n_ssids > 0) {
3153 offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16);
3154 offset = roundup(offset, sizeof(u32));
3155 ptr = (char*)params + offset;
3156 for (i = 0; i < n_ssids; i++) {
3157 memset(&ssid, 0, sizeof(wlc_ssid_t));
3158 ssid.SSID_len = MIN(request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN);
3159 memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
3160 if (!ssid.SSID_len)
3161 WL_SCAN(("%d: Broadcast scan\n", i));
3162 else
3163 WL_SCAN(("%d: scan for %s size =%d\n", i,
3164 ssid.SSID, ssid.SSID_len));
3165 memcpy(ptr, &ssid, sizeof(wlc_ssid_t));
3166 ptr += sizeof(wlc_ssid_t);
3167 }
3168 } else {
3169 WL_SCAN(("Broadcast scan\n"));
3170 }
3171 /* Adding mask to channel numbers */
3172 params->channel_num =
3173 htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
3174 (n_channels & WL_SCAN_PARAMS_COUNT_MASK));
3175
3176 if (n_channels == 1) {
3177 params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS);
3178 params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS);
3179 }
3180 }
3181
3182 static s32
3183 wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size)
3184 {
3185 wl_uint32_list_t *list;
3186 s32 err = BCME_OK;
3187 if (valid_chan_list == NULL || size <= 0)
3188 return -ENOMEM;
3189
3190 memset(valid_chan_list, 0, size);
3191 list = (wl_uint32_list_t *)(void *) valid_chan_list;
3192 list->count = htod32(WL_NUMCHANNELS);
3193 err = wldev_ioctl_get(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size);
3194 if (err != 0) {
3195 WL_ERR(("get channels failed with %d\n", err));
3196 }
3197
3198 return err;
3199 }
3200
3201 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
3202 #define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40
3203 bool g_first_broadcast_scan = TRUE;
3204 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
3205
3206 static s32
3207 wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev,
3208 struct cfg80211_scan_request *request, uint16 action)
3209 {
3210 s32 err = BCME_OK;
3211 u32 n_channels;
3212 u32 n_ssids;
3213 s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
3214 wl_escan_params_t *params = NULL;
3215 u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
3216 u32 num_chans = 0;
3217 s32 channel;
3218 u32 n_valid_chan;
3219 s32 search_state = WL_P2P_DISC_ST_SCAN;
3220 u32 i, j, n_nodfs = 0;
3221 u16 *default_chan_list = NULL;
3222 wl_uint32_list_t *list;
3223 s32 bssidx = -1;
3224 struct net_device *dev = NULL;
3225 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
3226 bool is_first_init_2g_scan = false;
3227 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
3228 p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN;
3229 u32 chan_mem = 0;
3230 #if defined(SUPPORT_RANDOM_MAC_SCAN)
3231 u8 mac_addr[ETHER_ADDR_LEN] = {0, };
3232 u8 mac_addr_mask[ETHER_ADDR_LEN] = {0, };
3233 #endif /* SUPPORT_RANDOM_MAC_SCAN */
3234
3235 WL_DBG(("Enter \n"));
3236
3237 /* scan request can come with empty request : perform all default scan */
3238 if (!cfg) {
3239 err = -EINVAL;
3240 goto exit;
3241 }
3242
3243 if (!cfg->p2p_supported || !p2p_scan(cfg)) {
3244 #if defined(SUPPORT_RANDOM_MAC_SCAN)
3245 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
3246 bcopy(request->mac_addr, mac_addr, ETHER_ADDR_LEN);
3247 bcopy(request->mac_addr_mask, mac_addr_mask, ETHER_ADDR_LEN);
3248 #else /* Kernel version is less than 3.19.0 */
3249 /* NL80211 default random mac addr and mask value */
3250 mac_addr[0] = 0x2;
3251 mac_addr_mask[0] = 0x3;
3252 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
3253 if ((request != NULL) && !ETHER_ISNULLADDR(mac_addr) &&
3254 !ETHER_ISNULLADDR(mac_addr_mask) &&
3255 !wl_is_wps_enrollee_active(ndev, request->ie, request->ie_len)) {
3256 wl_cfg80211_random_mac_enable(ndev, mac_addr, mac_addr_mask);
3257 if (err < 0) {
3258 if (err == BCME_UNSUPPORTED) {
3259 /* Ignore if chip doesnt support the feature */
3260 err = BCME_OK;
3261 } else {
3262 /* For errors other than unsupported fail the scan */
3263 WL_ERR(("%s : failed to set random mac for host scan, %d\n",
3264 __FUNCTION__, err));
3265 err = -EAGAIN;
3266 goto exit;
3267 }
3268 }
3269 } else {
3270 /* No randmac config provided. Ensure scanmac is disabled */
3271 wl_cfg80211_random_mac_disable(ndev);
3272 }
3273 #endif /* SUPPORT_RANDOM_MAC_SCAN */
3274
3275 /* LEGACY SCAN TRIGGER */
3276 WL_SCAN((" LEGACY E-SCAN START\n"));
3277
3278 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
3279 if (!request) {
3280 err = -EINVAL;
3281 goto exit;
3282 }
3283 if (ndev == bcmcfg_to_prmry_ndev(cfg) && g_first_broadcast_scan == true) {
3284 #ifdef USE_INITIAL_2G_SCAN
3285 struct ieee80211_channel tmp_channel_list[CH_MAX_2G_CHANNEL];
3286 /* allow one 5G channel to add previous connected channel in 5G */
3287 bool allow_one_5g_channel = TRUE;
3288 j = 0;
3289 for (i = 0; i < request->n_channels; i++) {
3290 int tmp_chan = ieee80211_frequency_to_channel
3291 (request->channels[i]->center_freq);
3292 if (tmp_chan > CH_MAX_2G_CHANNEL) {
3293 if (allow_one_5g_channel)
3294 allow_one_5g_channel = FALSE;
3295 else
3296 continue;
3297 }
3298 if (j > CH_MAX_2G_CHANNEL) {
3299 WL_ERR(("Index %d exceeds max 2.4GHz channels %d"
3300 " and previous 5G connected channel\n",
3301 j, CH_MAX_2G_CHANNEL));
3302 break;
3303 }
3304 bcopy(request->channels[i], &tmp_channel_list[j],
3305 sizeof(struct ieee80211_channel));
3306 WL_SCAN(("channel of request->channels[%d]=%d\n", i, tmp_chan));
3307 j++;
3308 }
3309 if ((j > 0) && (j <= CH_MAX_2G_CHANNEL)) {
3310 for (i = 0; i < j; i++)
3311 bcopy(&tmp_channel_list[i], request->channels[i],
3312 sizeof(struct ieee80211_channel));
3313
3314 request->n_channels = j;
3315 is_first_init_2g_scan = true;
3316 }
3317 else
3318 WL_ERR(("Invalid number of 2.4GHz channels %d\n", j));
3319
3320 WL_SCAN(("request->n_channels=%d\n", request->n_channels));
3321 #else /* USE_INITIAL_SHORT_DWELL_TIME */
3322 is_first_init_2g_scan = true;
3323 #endif /* USE_INITIAL_2G_SCAN */
3324 g_first_broadcast_scan = false;
3325 }
3326 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
3327
3328 /* if scan request is not empty parse scan request paramters */
3329 if (request != NULL) {
3330 n_channels = request->n_channels;
3331 n_ssids = request->n_ssids;
3332 if (n_channels % 2)
3333 /* If n_channels is odd, add a padd of u16 */
3334 params_size += sizeof(u16) * (n_channels + 1);
3335 else
3336 params_size += sizeof(u16) * n_channels;
3337
3338 /* Allocate space for populating ssids in wl_escan_params_t struct */
3339 params_size += sizeof(struct wlc_ssid) * n_ssids;
3340 }
3341 params = (wl_escan_params_t *)MALLOCZ(cfg->osh, params_size);
3342 if (params == NULL) {
3343 err = -ENOMEM;
3344 goto exit;
3345 }
3346 wl_scan_prep(cfg, &params->params, request);
3347
3348 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
3349 /* Override active_time to reduce scan time if it's first bradcast scan. */
3350 if (is_first_init_2g_scan)
3351 params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS;
3352 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
3353
3354 params->version = htod32(ESCAN_REQ_VERSION);
3355 params->action = htod16(action);
3356 wl_escan_set_sync_id(params->sync_id, cfg);
3357 wl_escan_set_type(cfg, WL_SCANTYPE_LEGACY);
3358 if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
3359 WL_ERR(("ioctl buffer length not sufficient\n"));
3360 MFREE(cfg->osh, params, params_size);
3361 err = -ENOMEM;
3362 goto exit;
3363 }
3364 if (cfg->active_scan == PASSIVE_SCAN) {
3365 params->params.scan_type = DOT11_SCANTYPE_PASSIVE;
3366 WL_DBG(("Passive scan_type %d \n", params->params.scan_type));
3367 }
3368
3369 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
3370
3371 err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
3372 cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3373 WL_INFORM_MEM(("LEGACY_SCAN sync ID: %d, bssidx: %d\n", params->sync_id, bssidx));
3374 if (unlikely(err)) {
3375 if (err == BCME_EPERM)
3376 /* Scan Not permitted at this point of time */
3377 WL_DBG((" Escan not permitted at this time (%d)\n", err));
3378 else
3379 WL_ERR((" Escan set error (%d)\n", err));
3380 } else {
3381 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_REQUESTED);
3382 }
3383 MFREE(cfg->osh, params, params_size);
3384 }
3385 else if (p2p_is_on(cfg) && p2p_scan(cfg)) {
3386 /* P2P SCAN TRIGGER */
3387 s32 _freq = 0;
3388 n_nodfs = 0;
3389
3390 #ifdef WL_NAN
3391 if (wl_cfgnan_check_state(cfg)) {
3392 WL_ERR(("nan is enabled, nan + p2p concurrency not supported\n"));
3393 return BCME_UNSUPPORTED;
3394 }
3395 #endif /* WL_NAN */
3396 if (request && request->n_channels) {
3397 num_chans = request->n_channels;
3398 WL_SCAN((" chann number : %d\n", num_chans));
3399 chan_mem = (u32)(num_chans * sizeof(*default_chan_list));
3400 default_chan_list = MALLOCZ(cfg->osh, chan_mem);
3401 if (default_chan_list == NULL) {
3402 WL_ERR(("channel list allocation failed \n"));
3403 err = -ENOMEM;
3404 goto exit;
3405 }
3406 if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) {
3407 #ifdef P2P_SKIP_DFS
3408 int is_printed = false;
3409 #endif /* P2P_SKIP_DFS */
3410 list = (wl_uint32_list_t *) chan_buf;
3411 n_valid_chan = dtoh32(list->count);
3412 if (n_valid_chan > WL_NUMCHANNELS) {
3413 WL_ERR(("wrong n_valid_chan:%d\n", n_valid_chan));
3414 MFREE(cfg->osh, default_chan_list, chan_mem);
3415 err = -EINVAL;
3416 goto exit;
3417 }
3418
3419 for (i = 0; i < num_chans; i++)
3420 {
3421 #ifdef WL_HOST_BAND_MGMT
3422 int channel_band = 0;
3423 #endif /* WL_HOST_BAND_MGMT */
3424 _freq = request->channels[i]->center_freq;
3425 channel = ieee80211_frequency_to_channel(_freq);
3426 #ifdef WL_HOST_BAND_MGMT
3427 channel_band = (channel > CH_MAX_2G_CHANNEL) ?
3428 WLC_BAND_5G : WLC_BAND_2G;
3429 if ((cfg->curr_band != WLC_BAND_AUTO) &&
3430 (cfg->curr_band != channel_band) &&
3431 !IS_P2P_SOCIAL_CHANNEL(channel))
3432 continue;
3433 #endif /* WL_HOST_BAND_MGMT */
3434
3435 /* ignore DFS channels */
3436 if (request->channels[i]->flags &
3437 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
3438 (IEEE80211_CHAN_NO_IR
3439 | IEEE80211_CHAN_RADAR))
3440 #else
3441 (IEEE80211_CHAN_RADAR
3442 | IEEE80211_CHAN_PASSIVE_SCAN))
3443 #endif // endif
3444 continue;
3445 #ifdef P2P_SKIP_DFS
3446 if (channel >= 52 && channel <= 144) {
3447 if (is_printed == false) {
3448 WL_ERR(("SKIP DFS CHANs(52~144)\n"));
3449 is_printed = true;
3450 }
3451 continue;
3452 }
3453 #endif /* P2P_SKIP_DFS */
3454
3455 for (j = 0; j < n_valid_chan; j++) {
3456 /* allows only supported channel on
3457 * current reguatory
3458 */
3459 if (n_nodfs >= num_chans) {
3460 break;
3461 }
3462 if (channel == (dtoh32(list->element[j]))) {
3463 default_chan_list[n_nodfs++] =
3464 channel;
3465 }
3466 }
3467
3468 }
3469 }
3470 if (num_chans == SOCIAL_CHAN_CNT && (
3471 (default_chan_list[0] == SOCIAL_CHAN_1) &&
3472 (default_chan_list[1] == SOCIAL_CHAN_2) &&
3473 (default_chan_list[2] == SOCIAL_CHAN_3))) {
3474 /* SOCIAL CHANNELS 1, 6, 11 */
3475 search_state = WL_P2P_DISC_ST_SEARCH;
3476 p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
3477 WL_DBG(("P2P SEARCH PHASE START \n"));
3478 } else if (((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1)) &&
3479 (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) ||
3480 ((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION2)) &&
3481 (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP))) {
3482 /* If you are already a GO, then do SEARCH only */
3483 WL_DBG(("Already a GO. Do SEARCH Only"));
3484 search_state = WL_P2P_DISC_ST_SEARCH;
3485 num_chans = n_nodfs;
3486 p2p_scan_purpose = P2P_SCAN_NORMAL;
3487
3488 } else if (num_chans == 1) {
3489 p2p_scan_purpose = P2P_SCAN_CONNECT_TRY;
3490 WL_INFORM_MEM(("Trigger p2p join scan\n"));
3491 } else if (num_chans == SOCIAL_CHAN_CNT + 1) {
3492 /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by
3493 * the supplicant
3494 */
3495 p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
3496 } else {
3497 WL_DBG(("P2P SCAN STATE START \n"));
3498 num_chans = n_nodfs;
3499 p2p_scan_purpose = P2P_SCAN_NORMAL;
3500 }
3501 } else {
3502 err = -EINVAL;
3503 goto exit;
3504 }
3505 err = wl_cfgp2p_escan(cfg, ndev, ACTIVE_SCAN, num_chans, default_chan_list,
3506 search_state, action,
3507 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE), NULL,
3508 p2p_scan_purpose);
3509
3510 if (!err)
3511 cfg->p2p->search_state = search_state;
3512
3513 MFREE(cfg->osh, default_chan_list, chan_mem);
3514 }
3515 exit:
3516 if (unlikely(err)) {
3517 /* Don't print Error incase of Scan suppress */
3518 if ((err == BCME_EPERM) && cfg->scan_suppressed)
3519 WL_DBG(("Escan failed: Scan Suppressed \n"));
3520 else
3521 WL_ERR(("scan error (%d)\n", err));
3522 }
3523 return err;
3524 }
3525
3526 static s32
3527 wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *ndev,
3528 struct cfg80211_scan_request *request)
3529 {
3530 s32 err = BCME_OK;
3531 s32 passive_scan;
3532 s32 passive_scan_time;
3533 s32 passive_scan_time_org;
3534 wl_scan_results_t *results;
3535 WL_SCAN(("Enter \n"));
3536
3537 results = wl_escan_get_buf(cfg, FALSE);
3538 results->version = 0;
3539 results->count = 0;
3540 results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
3541
3542 cfg->escan_info.ndev = ndev;
3543 cfg->escan_info.wiphy = wiphy;
3544 cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
3545 passive_scan = cfg->active_scan ? 0 : 1;
3546 err = wldev_ioctl_set(ndev, WLC_SET_PASSIVE_SCAN,
3547 &passive_scan, sizeof(passive_scan));
3548 if (unlikely(err)) {
3549 WL_ERR(("error (%d)\n", err));
3550 goto exit;
3551 }
3552
3553 if (passive_channel_skip) {
3554
3555 err = wldev_ioctl_get(ndev, WLC_GET_SCAN_PASSIVE_TIME,
3556 &passive_scan_time_org, sizeof(passive_scan_time_org));
3557 if (unlikely(err)) {
3558 WL_ERR(("== error (%d)\n", err));
3559 goto exit;
3560 }
3561
3562 WL_SCAN(("PASSIVE SCAN time : %d \n", passive_scan_time_org));
3563
3564 passive_scan_time = 0;
3565 err = wldev_ioctl_set(ndev, WLC_SET_SCAN_PASSIVE_TIME,
3566 &passive_scan_time, sizeof(passive_scan_time));
3567 if (unlikely(err)) {
3568 WL_ERR(("== error (%d)\n", err));
3569 goto exit;
3570 }
3571
3572 WL_SCAN(("PASSIVE SCAN SKIPED!! (passive_channel_skip:%d) \n",
3573 passive_channel_skip));
3574 }
3575
3576 err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START);
3577
3578 if (passive_channel_skip) {
3579 err = wldev_ioctl_set(ndev, WLC_SET_SCAN_PASSIVE_TIME,
3580 &passive_scan_time_org, sizeof(passive_scan_time_org));
3581 if (unlikely(err)) {
3582 WL_ERR(("== error (%d)\n", err));
3583 goto exit;
3584 }
3585
3586 WL_SCAN(("PASSIVE SCAN RECOVERED!! (passive_scan_time_org:%d) \n",
3587 passive_scan_time_org));
3588 }
3589
3590 exit:
3591 return err;
3592 }
3593
3594 static s32
3595 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
3596 struct cfg80211_scan_request *request,
3597 struct cfg80211_ssid *this_ssid)
3598 {
3599 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3600 struct cfg80211_ssid *ssids;
3601 struct ether_addr primary_mac;
3602 bool p2p_ssid;
3603 #ifdef WL11U
3604 bcm_tlv_t *interworking_ie;
3605 #endif // endif
3606 s32 err = 0;
3607 s32 bssidx = -1;
3608 s32 i;
3609
3610 unsigned long flags;
3611 static s32 busy_count = 0;
3612 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
3613 struct net_device *remain_on_channel_ndev = NULL;
3614 #endif // endif
3615 /*
3616 * Hostapd triggers scan before starting automatic channel selection
3617 * to collect channel characteristics. However firmware scan engine
3618 * doesn't support any channel characteristics collection along with
3619 * scan. Hence return scan success.
3620 */
3621 if (request && (scan_req_iftype(request) == NL80211_IFTYPE_AP)) {
3622 WL_DBG(("Scan Command on SoftAP Interface. Ignoring...\n"));
3623 return 0;
3624 }
3625
3626 ndev = ndev_to_wlc_ndev(ndev, cfg);
3627
3628 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
3629 WL_ERR(("Sending Action Frames. Try it again.\n"));
3630 return -EAGAIN;
3631 }
3632
3633 WL_DBG(("Enter wiphy (%p)\n", wiphy));
3634 if (wl_get_drv_status_all(cfg, SCANNING)) {
3635 if (cfg->scan_request == NULL) {
3636 wl_clr_drv_status_all(cfg, SCANNING);
3637 WL_DBG(("<<<<<<<<<<<Force Clear Scanning Status>>>>>>>>>>>\n"));
3638 } else {
3639 WL_ERR(("Scanning already\n"));
3640 return -EAGAIN;
3641 }
3642 }
3643 if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) {
3644 WL_ERR(("Scanning being aborted\n"));
3645 return -EAGAIN;
3646 }
3647 if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
3648 WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
3649 return -EOPNOTSUPP;
3650 }
3651 #ifdef WL_BCNRECV
3652 /* check fakeapscan in progress then abort */
3653 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_SCANBUSY);
3654 #endif /* WL_BCNRECV */
3655
3656 #ifdef P2P_LISTEN_OFFLOADING
3657 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
3658 WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
3659 return -EAGAIN;
3660 }
3661 #endif /* P2P_LISTEN_OFFLOADING */
3662
3663 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
3664 remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg);
3665 if (remain_on_channel_ndev) {
3666 WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n"));
3667 wl_notify_escan_complete(cfg, remain_on_channel_ndev, true, true);
3668 }
3669 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
3670
3671 if (request) { /* scan bss */
3672 ssids = request->ssids;
3673 p2p_ssid = false;
3674 for (i = 0; i < request->n_ssids; i++) {
3675 if (ssids[i].ssid_len &&
3676 IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) {
3677 p2p_ssid = true;
3678 break;
3679 }
3680 }
3681 if (p2p_ssid) {
3682 if (cfg->p2p_supported) {
3683 #ifdef WL_NAN
3684 if (cfg->nan_enable) {
3685 err = wl_cfgnan_disable(cfg, NAN_CONCURRENCY_CONFLICT);
3686 if (err != BCME_OK) {
3687 WL_ERR(("failed to disable nan, error[%d]\n", err));
3688 goto scan_out;
3689 }
3690 }
3691 #endif /* WL_NAN */
3692 /* p2p scan trigger */
3693 if (p2p_on(cfg) == false) {
3694 /* p2p on at the first time */
3695 p2p_on(cfg) = true;
3696 wl_cfgp2p_set_firm_p2p(cfg);
3697 get_primary_mac(cfg, &primary_mac);
3698 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
3699 #if defined(P2P_IE_MISSING_FIX)
3700 cfg->p2p_prb_noti = false;
3701 #endif // endif
3702 }
3703 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
3704 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
3705 p2p_scan(cfg) = true;
3706 }
3707 } else {
3708 /* legacy scan trigger
3709 * So, we have to disable p2p discovery if p2p discovery is on
3710 */
3711 if (cfg->p2p_supported) {
3712 p2p_scan(cfg) = false;
3713 /* If Netdevice is not equals to primary and p2p is on
3714 * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
3715 */
3716
3717 if (p2p_scan(cfg) == false) {
3718 if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
3719 err = wl_cfgp2p_discover_enable_search(cfg,
3720 false);
3721 if (unlikely(err)) {
3722 goto scan_out;
3723 }
3724
3725 }
3726 }
3727 }
3728 if (!cfg->p2p_supported || !p2p_scan(cfg)) {
3729 if ((bssidx = wl_get_bssidx_by_wdev(cfg,
3730 ndev->ieee80211_ptr)) < 0) {
3731 WL_ERR(("Find p2p index from ndev(%p) failed\n",
3732 ndev));
3733 err = BCME_ERROR;
3734 goto scan_out;
3735 }
3736 #ifdef WL11U
3737 if (request && (interworking_ie = wl_cfg80211_find_interworking_ie(
3738 request->ie, request->ie_len)) != NULL) {
3739 if ((err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx,
3740 VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
3741 interworking_ie->data,
3742 interworking_ie->len)) != BCME_OK) {
3743 WL_ERR(("Failed to add interworking IE"));
3744 }
3745 } else if (cfg->wl11u) {
3746 /* we have to clear IW IE and disable gratuitous APR */
3747 wl_cfg80211_clear_iw_ie(cfg, ndev, bssidx);
3748 err = wldev_iovar_setint_bsscfg(ndev, "grat_arp",
3749 0, bssidx);
3750 /* we don't care about error here
3751 * because the only failure case is unsupported,
3752 * which is fine
3753 */
3754 if (unlikely(err)) {
3755 WL_ERR(("Set grat_arp failed:(%d) Ignore!\n", err));
3756 }
3757 cfg->wl11u = FALSE;
3758 }
3759 #endif /* WL11U */
3760 if (request) {
3761 err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
3762 ndev_to_cfgdev(ndev), bssidx, VNDR_IE_PRBREQ_FLAG,
3763 request->ie, request->ie_len);
3764 }
3765
3766 if (unlikely(err)) {
3767 goto scan_out;
3768 }
3769
3770 }
3771 }
3772 } else { /* scan in ibss */
3773 ssids = this_ssid;
3774 }
3775
3776 if (request && cfg->p2p_supported) {
3777 WL_TRACE_HW4(("START SCAN\n"));
3778 DHD_OS_SCAN_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub),
3779 SCAN_WAKE_LOCK_TIMEOUT);
3780 DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)(cfg->pub));
3781 }
3782
3783 if (cfg->p2p_supported) {
3784 if (request && p2p_on(cfg) && p2p_scan(cfg)) {
3785
3786 /* find my listen channel */
3787 cfg->afx_hdl->my_listen_chan =
3788 wl_find_listen_channel(cfg, request->ie,
3789 request->ie_len);
3790 err = wl_cfgp2p_enable_discovery(cfg, ndev,
3791 request->ie, request->ie_len);
3792
3793 if (unlikely(err)) {
3794 goto scan_out;
3795 }
3796 }
3797 }
3798 err = wl_do_escan(cfg, wiphy, ndev, request);
3799 if (likely(!err))
3800 goto scan_success;
3801 else
3802 goto scan_out;
3803
3804 scan_success:
3805 busy_count = 0;
3806 cfg->scan_request = request;
3807 wl_set_drv_status(cfg, SCANNING, ndev);
3808
3809 return 0;
3810
3811 scan_out:
3812 if (err == BCME_BUSY || err == BCME_NOTREADY) {
3813 WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY));
3814 err = -EBUSY;
3815 } else if ((err == BCME_EPERM) && cfg->scan_suppressed) {
3816 WL_ERR(("Scan not permitted due to scan suppress\n"));
3817 err = -EPERM;
3818 } else {
3819 /* For all other fw errors, use a generic error code as return
3820 * value to cfg80211 stack
3821 */
3822 err = -EAGAIN;
3823 }
3824
3825 #define SCAN_EBUSY_RETRY_LIMIT 20
3826 if (err == -EBUSY) {
3827 /* Flush FW preserve buffer logs for checking failure */
3828 if (busy_count++ > (SCAN_EBUSY_RETRY_LIMIT/5)) {
3829 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
3830 }
3831 if (busy_count > SCAN_EBUSY_RETRY_LIMIT) {
3832 struct ether_addr bssid;
3833 s32 ret = 0;
3834 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
3835 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
3836 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
3837 busy_count = 0;
3838 WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n",
3839 wl_get_drv_status(cfg, SCANNING, ndev),
3840 wl_get_drv_status(cfg, SCAN_ABORTING, ndev),
3841 wl_get_drv_status(cfg, CONNECTING, ndev),
3842 wl_get_drv_status(cfg, CONNECTED, ndev),
3843 wl_get_drv_status(cfg, DISCONNECTING, ndev),
3844 wl_get_drv_status(cfg, AP_CREATING, ndev),
3845 wl_get_drv_status(cfg, AP_CREATED, ndev),
3846 wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev),
3847 wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev)));
3848
3849 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
3850 if (dhdp->memdump_enabled) {
3851 dhdp->memdump_type = DUMP_TYPE_SCAN_BUSY;
3852 dhd_bus_mem_dump(dhdp);
3853 }
3854 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
3855
3856 bzero(&bssid, sizeof(bssid));
3857 if ((ret = wldev_ioctl_get(ndev, WLC_GET_BSSID,
3858 &bssid, ETHER_ADDR_LEN)) == 0) {
3859 WL_ERR(("FW is connected with " MACDBG "/n",
3860 MAC2STRDBG(bssid.octet)));
3861 } else {
3862 WL_ERR(("GET BSSID failed with %d\n", ret));
3863 }
3864
3865 wl_cfg80211_scan_abort(cfg);
3866
3867 } else {
3868 /* Hold the context for 400msec, so that 10 subsequent scans
3869 * can give a buffer of 4sec which is enough to
3870 * cover any on-going scan in the firmware
3871 */
3872 WL_DBG(("Enforcing delay for EBUSY case \n"));
3873 msleep(400);
3874 }
3875 } else {
3876 busy_count = 0;
3877 }
3878
3879 wl_clr_drv_status(cfg, SCANNING, ndev);
3880 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
3881 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
3882 cfg->scan_request = NULL;
3883 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
3884
3885 return err;
3886 }
3887
3888 static s32
3889 wl_get_scan_timeout_val(struct bcm_cfg80211 *cfg)
3890 {
3891 u32 scan_timer_interval_ms = WL_SCAN_TIMER_INTERVAL_MS;
3892
3893 #ifdef WES_SUPPORT
3894 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
3895 if ((cfg->custom_scan_channel_time > DHD_SCAN_ASSOC_ACTIVE_TIME) |
3896 (cfg->custom_scan_unassoc_time > DHD_SCAN_UNASSOC_ACTIVE_TIME) |
3897 (cfg->custom_scan_passive_time > DHD_SCAN_PASSIVE_TIME) |
3898 (cfg->custom_scan_home_time > DHD_SCAN_HOME_TIME) |
3899 (cfg->custom_scan_home_away_time > DHD_SCAN_HOME_AWAY_TIME)) {
3900 scan_timer_interval_ms = CUSTOMER_WL_SCAN_TIMER_INTERVAL_MS;
3901 }
3902 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
3903 #endif /* WES_SUPPORT */
3904
3905 /* If NAN is enabled adding +10 sec to the existing timeout value */
3906 #ifdef WL_NAN
3907 if (cfg->nan_enable) {
3908 scan_timer_interval_ms += WL_SCAN_TIMER_INTERVAL_MS_NAN;
3909 }
3910 #endif /* WL_NAN */
3911 WL_INFORM(("scan_timer_interval_ms %d\n", scan_timer_interval_ms));
3912 return scan_timer_interval_ms;
3913 }
3914
3915 #if defined(WL_CFG80211_P2P_DEV_IF)
3916 static s32
3917 wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
3918 #else
3919 static s32
3920 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
3921 struct cfg80211_scan_request *request)
3922 #endif /* WL_CFG80211_P2P_DEV_IF */
3923 {
3924 s32 err = 0;
3925 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3926 #if defined(WL_CFG80211_P2P_DEV_IF)
3927 struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg);
3928 #endif /* WL_CFG80211_P2P_DEV_IF */
3929
3930 WL_DBG(("Enter\n"));
3931 RETURN_EIO_IF_NOT_UP(cfg);
3932
3933 #ifdef DHD_IFDEBUG
3934 #ifdef WL_CFG80211_P2P_DEV_IF
3935 PRINT_WDEV_INFO(request->wdev);
3936 #else
3937 PRINT_WDEV_INFO(ndev);
3938 #endif /* WL_CFG80211_P2P_DEV_IF */
3939 #endif /* DHD_IFDEBUG */
3940
3941 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
3942 if (wl_cfg_multip2p_operational(cfg)) {
3943 WL_ERR(("wlan0 scan failed, p2p devices are operational"));
3944 return -ENODEV;
3945 }
3946 }
3947
3948 mutex_lock(&cfg->scan_sync);
3949 err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
3950 if (unlikely(err)) {
3951 WL_ERR(("scan error (%d)\n", err));
3952 } else {
3953 /* Arm the timer */
3954 mod_timer(&cfg->scan_timeout,
3955 jiffies + msecs_to_jiffies(wl_get_scan_timeout_val(cfg)));
3956 }
3957 mutex_unlock(&cfg->scan_sync);
3958 #ifdef WL_DRV_AVOID_SCANCACHE
3959 /* Reset roam cache after successful scan request */
3960 #ifdef ROAM_CHANNEL_CACHE
3961 if (!err) {
3962 reset_roam_cache(cfg);
3963 }
3964 #endif /* ROAM_CHANNEL_CACHE */
3965 #endif /* WL_DRV_AVOID_SCANCACHE */
3966 return err;
3967 }
3968
3969 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
3970 static void
3971 wl_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev)
3972 {
3973 struct bcm_cfg80211 *cfg;
3974
3975 WL_DBG(("Enter %s\n", __FUNCTION__));
3976 cfg = wiphy_priv(wdev->wiphy);
3977
3978 /* Check if any scan in progress only then abort */
3979 if (wl_get_drv_status_all(cfg, SCANNING)) {
3980 wl_cfg80211_scan_abort(cfg);
3981 /* Only scan abort is issued here. As per the expectation of abort_scan
3982 * the status of abort is needed to be communicated using cfg80211_scan_done call.
3983 * Here we just issue abort request and let the scan complete path to indicate
3984 * abort to cfg80211 layer.
3985 */
3986 WL_DBG(("%s: Scan abort issued to FW\n", __FUNCTION__));
3987 }
3988 }
3989 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
3990
3991 static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
3992 {
3993 s32 err = 0;
3994
3995 err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
3996 if (unlikely(err)) {
3997 WL_ERR(("Error (%d)\n", err));
3998 return err;
3999 }
4000 return err;
4001 }
4002
4003 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
4004 {
4005 s32 err = 0;
4006
4007 err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
4008 if (unlikely(err)) {
4009 WL_ERR(("Error (%d)\n", err));
4010 return err;
4011 }
4012 return err;
4013 }
4014
4015 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
4016 {
4017 s32 err = 0;
4018 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
4019
4020 #ifdef CUSTOM_LONG_RETRY_LIMIT
4021 if ((cmd == WLC_SET_LRL) &&
4022 (retry != CUSTOM_LONG_RETRY_LIMIT)) {
4023 WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
4024 return err;
4025 }
4026 #endif /* CUSTOM_LONG_RETRY_LIMIT */
4027
4028 retry = htod32(retry);
4029 err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry));
4030 if (unlikely(err)) {
4031 WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
4032 return err;
4033 }
4034 return err;
4035 }
4036
4037 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
4038 {
4039 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
4040 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
4041 s32 err = 0;
4042
4043 RETURN_EIO_IF_NOT_UP(cfg);
4044 WL_DBG(("Enter\n"));
4045 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
4046 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
4047 cfg->conf->rts_threshold = wiphy->rts_threshold;
4048 err = wl_set_rts(ndev, cfg->conf->rts_threshold);
4049 if (err != BCME_OK)
4050 return err;
4051 }
4052 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
4053 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
4054 cfg->conf->frag_threshold = wiphy->frag_threshold;
4055 err = wl_set_frag(ndev, cfg->conf->frag_threshold);
4056 if (err != BCME_OK)
4057 return err;
4058 }
4059 if (changed & WIPHY_PARAM_RETRY_LONG &&
4060 (cfg->conf->retry_long != wiphy->retry_long)) {
4061 cfg->conf->retry_long = wiphy->retry_long;
4062 err = wl_set_retry(ndev, cfg->conf->retry_long, true);
4063 if (err != BCME_OK)
4064 return err;
4065 }
4066 if (changed & WIPHY_PARAM_RETRY_SHORT &&
4067 (cfg->conf->retry_short != wiphy->retry_short)) {
4068 cfg->conf->retry_short = wiphy->retry_short;
4069 err = wl_set_retry(ndev, cfg->conf->retry_short, false);
4070 if (err != BCME_OK) {
4071 return err;
4072 }
4073 }
4074
4075 return err;
4076 }
4077 static chanspec_t
4078 channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap)
4079 {
4080 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4081 u8 *buf = NULL;
4082 wl_uint32_list_t *list;
4083 int err = BCME_OK;
4084 chanspec_t c = 0, ret_c = 0;
4085 int bw = 0, tmp_bw = 0;
4086 int i;
4087 u32 tmp_c;
4088 #define LOCAL_BUF_SIZE 1024
4089 buf = (u8 *)MALLOC(cfg->osh, LOCAL_BUF_SIZE);
4090 if (!buf) {
4091 WL_ERR(("buf memory alloc failed\n"));
4092 goto exit;
4093 }
4094
4095 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
4096 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync);
4097 if (err != BCME_OK) {
4098 WL_ERR(("get chanspecs failed with %d\n", err));
4099 goto exit;
4100 }
4101
4102 list = (wl_uint32_list_t *)(void *)buf;
4103 for (i = 0; i < dtoh32(list->count); i++) {
4104 c = dtoh32(list->element[i]);
4105 if (channel <= CH_MAX_2G_CHANNEL) {
4106 if (!CHSPEC_IS20(c))
4107 continue;
4108 if (channel == CHSPEC_CHANNEL(c)) {
4109 ret_c = c;
4110 bw = 20;
4111 goto exit;
4112 }
4113 }
4114 tmp_c = wf_chspec_ctlchan(c);
4115 tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT];
4116 if (tmp_c != channel)
4117 continue;
4118
4119 if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) {
4120 bw = tmp_bw;
4121 ret_c = c;
4122 if (bw == bw_cap)
4123 goto exit;
4124 }
4125 }
4126 exit:
4127 if (buf) {
4128 MFREE(cfg->osh, buf, LOCAL_BUF_SIZE);
4129 }
4130 #undef LOCAL_BUF_SIZE
4131 WL_DBG(("return chanspec %x %d\n", ret_c, bw));
4132 return ret_c;
4133 }
4134
4135 void
4136 wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev, vndr_ie_setbuf_t *ibss_vsie,
4137 int ibss_vsie_len)
4138 {
4139 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4140
4141 if (cfg != NULL && ibss_vsie != NULL) {
4142 if (cfg->ibss_vsie != NULL) {
4143 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
4144 }
4145 cfg->ibss_vsie = ibss_vsie;
4146 cfg->ibss_vsie_len = ibss_vsie_len;
4147 }
4148 }
4149
4150 static void
4151 wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
4152 {
4153 /* free & initiralize VSIE (Vendor Specific IE) */
4154 if (cfg->ibss_vsie != NULL) {
4155 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
4156 cfg->ibss_vsie = NULL;
4157 cfg->ibss_vsie_len = 0;
4158 }
4159 }
4160
4161 s32
4162 wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
4163 {
4164 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4165 char *ioctl_buf = NULL;
4166 s32 ret = BCME_OK, bssidx;
4167
4168 if (cfg != NULL && cfg->ibss_vsie != NULL) {
4169 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
4170 if (!ioctl_buf) {
4171 WL_ERR(("ioctl memory alloc failed\n"));
4172 return -ENOMEM;
4173 }
4174 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4175 WL_ERR(("Find index failed\n"));
4176 ret = BCME_ERROR;
4177 goto end;
4178 }
4179 /* change the command from "add" to "del" */
4180 strncpy(cfg->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1);
4181 cfg->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
4182
4183 ret = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie",
4184 cfg->ibss_vsie, cfg->ibss_vsie_len,
4185 ioctl_buf, WLC_IOCTL_MEDLEN, bssidx, NULL);
4186 WL_ERR(("ret=%d\n", ret));
4187
4188 if (ret == BCME_OK) {
4189 /* free & initialize VSIE */
4190 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
4191 cfg->ibss_vsie = NULL;
4192 cfg->ibss_vsie_len = 0;
4193 }
4194 end:
4195 if (ioctl_buf) {
4196 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4197 }
4198 }
4199
4200 return ret;
4201 }
4202
4203 #ifdef WLAIBSS_MCHAN
4204 static bcm_struct_cfgdev*
4205 bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name)
4206 {
4207 int err = 0;
4208 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4209 struct wireless_dev* wdev = NULL;
4210 struct net_device *new_ndev = NULL;
4211 struct net_device *primary_ndev = NULL;
4212 long timeout;
4213 wl_aibss_if_t aibss_if;
4214 wl_if_event_info *event = NULL;
4215
4216 if (cfg->ibss_cfgdev != NULL) {
4217 WL_ERR(("IBSS interface %s already exists\n", name));
4218 return NULL;
4219 }
4220
4221 WL_ERR(("Try to create IBSS interface %s\n", name));
4222 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4223 /* generate a new MAC address for the IBSS interface */
4224 get_primary_mac(cfg, &cfg->ibss_if_addr);
4225 cfg->ibss_if_addr.octet[4] ^= 0x40;
4226 memset(&aibss_if, sizeof(aibss_if), 0);
4227 memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
4228 aibss_if.chspec = 0;
4229 aibss_if.len = sizeof(aibss_if);
4230
4231 cfg->bss_pending_op = TRUE;
4232 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4233 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
4234 sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4235 if (err) {
4236 WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
4237 goto fail;
4238 }
4239 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4240 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4241 if (timeout <= 0 || cfg->bss_pending_op)
4242 goto fail;
4243
4244 event = &cfg->if_event_info;
4245 /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
4246 * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
4247 * and will be freed by dhd_detach unless it gets unregistered before that. The
4248 * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
4249 * be freed by wl_dealloc_netinfo
4250 */
4251 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name,
4252 event->mac, event->bssidx, event->name);
4253 if (new_ndev == NULL)
4254 goto fail;
4255 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
4256 if (wdev == NULL)
4257 goto fail;
4258 wdev->wiphy = wiphy;
4259 wdev->iftype = NL80211_IFTYPE_ADHOC;
4260 wdev->netdev = new_ndev;
4261 new_ndev->ieee80211_ptr = wdev;
4262 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4263
4264 /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
4265 * needs to be modified to take one parameter (bool need_rtnl_lock)
4266 */
4267 ASSERT_RTNL();
4268 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, FALSE) != BCME_OK)
4269 goto fail;
4270
4271 wl_alloc_netinfo(cfg, new_ndev, wdev, WL_IF_TYPE_IBSS,
4272 PM_ENABLE, event->bssidx, event->ifidx);
4273 cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
4274 WL_ERR(("IBSS interface %s created\n", new_ndev->name));
4275 return cfg->ibss_cfgdev;
4276
4277 fail:
4278 WL_ERR(("failed to create IBSS interface %s \n", name));
4279 cfg->bss_pending_op = FALSE;
4280 if (new_ndev)
4281 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
4282 if (wdev) {
4283 MFREE(cfg->osh, wdev, sizeof(*wdev));
4284 }
4285 return NULL;
4286 }
4287
4288 static s32
4289 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
4290 {
4291 int err = 0;
4292 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4293 struct net_device *ndev = NULL;
4294 struct net_device *primary_ndev = NULL;
4295 long timeout;
4296
4297 if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet))
4298 return -EINVAL;
4299 ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev);
4300 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4301
4302 cfg->bss_pending_op = TRUE;
4303 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4304 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
4305 sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4306 if (err) {
4307 WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
4308 goto fail;
4309 }
4310 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4311 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4312 if (timeout <= 0 || cfg->bss_pending_op) {
4313 WL_ERR(("timeout in waiting IF_DEL event\n"));
4314 goto fail;
4315 }
4316
4317 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
4318 cfg->ibss_cfgdev = NULL;
4319 return 0;
4320
4321 fail:
4322 cfg->bss_pending_op = FALSE;
4323 return -1;
4324 }
4325 #endif /* WLAIBSS_MCHAN */
4326
4327 s32
4328 wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)
4329 {
4330 s32 ret = BCME_ERROR;
4331
4332 switch (iftype) {
4333 case WL_IF_TYPE_AP:
4334 ret = WL_INTERFACE_TYPE_AP;
4335 break;
4336 case WL_IF_TYPE_STA:
4337 ret = WL_INTERFACE_TYPE_STA;
4338 break;
4339 case WL_IF_TYPE_NAN_NMI:
4340 case WL_IF_TYPE_NAN:
4341 ret = WL_INTERFACE_TYPE_NAN;
4342 break;
4343 case WL_IF_TYPE_P2P_DISC:
4344 ret = WL_INTERFACE_TYPE_P2P_DISC;
4345 break;
4346 case WL_IF_TYPE_P2P_GO:
4347 ret = WL_INTERFACE_TYPE_P2P_GO;
4348 break;
4349 case WL_IF_TYPE_P2P_GC:
4350 ret = WL_INTERFACE_TYPE_P2P_GC;
4351 break;
4352 case WL_IF_TYPE_AWDL:
4353 ret = WL_INTERFACE_TYPE_AWDL;
4354 break;
4355
4356 default:
4357 WL_ERR(("Unsupported type:%d \n", iftype));
4358 ret = -EINVAL;
4359 break;
4360 }
4361 return ret;
4362 }
4363
4364 #ifdef CUSTOMER_HW4
4365 static bool
4366 wl_legacy_chip_check(struct bcm_cfg80211 *cfg)
4367 {
4368 int ret = FALSE;
4369 #if defined(BCMSDIO) || defined(BCMPCIE)
4370 u32 chipid, chiprevid;
4371 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
4372
4373 chipid = dhd_bus_chip_id(dhdp);
4374 chiprevid = dhd_bus_chiprev_id(dhdp);
4375 WL_DBG(("chipid=0x%x, chiprevid=%x\n", chipid, chiprevid));
4376 if (chipid == BCM4350_CHIP_ID || chipid == BCM4345_CHIP_ID) {
4377 ret = TRUE;
4378 } else {
4379 ret = FALSE;
4380 }
4381 #endif /* BCMSDIO || BCMPCIE */
4382
4383 return ret;
4384 }
4385
4386 static bool
4387 wl_check_interface_create_v0(struct bcm_cfg80211 *cfg)
4388 {
4389 int ret = FALSE;
4390 #if defined(BCMSDIO) || defined(BCMPCIE)
4391 u32 chipid, chiprevid;
4392 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
4393
4394 chipid = dhd_bus_chip_id(dhdp);
4395 chiprevid = dhd_bus_chiprev_id(dhdp);
4396 WL_DBG(("chipid=0x%x, chiprevid=%x\n", chipid, chiprevid));
4397
4398 if (chipid == BCM4359_CHIP_ID &&
4399 (chiprevid == 5 || chiprevid == 9)) {
4400 ret = TRUE;
4401 }
4402 #endif /* BCMSDIO || BCMPCIE */
4403
4404 return ret;
4405 }
4406 #endif /* CUSTOMER_HW4 */
4407
4408 s32
4409 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
4410 struct net_device *ndev, s32 bsscfg_idx,
4411 wl_iftype_t cfg_iftype, s32 del, u8 *addr)
4412 {
4413 s32 ret;
4414 wl_interface_create_v2_t iface;
4415 wl_interface_create_v3_t iface_v3;
4416 wl_interface_info_v1_t *info;
4417 wl_interface_info_v2_t *info_v2;
4418 uint32 ifflags = 0;
4419 bool use_iface_info_v2 = false;
4420 u8 ioctl_buf[WLC_IOCTL_SMLEN];
4421 s32 iftype;
4422 #ifdef CUSTOMER_HW4
4423 wl_interface_info_v0_t *info_v0;
4424 bool use_iface_info_v0 = false;
4425 #endif /* CUSTOMER_HW4 */
4426
4427 if (del) {
4428 ret = wldev_iovar_setbuf(ndev, "interface_remove",
4429 NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL);
4430 if (unlikely(ret))
4431 WL_ERR(("Interface remove failed!! ret %d\n", ret));
4432 return ret;
4433 }
4434
4435 /* Interface create */
4436 bzero(&iface, sizeof(iface));
4437
4438 /*
4439 * flags field is still used along with iftype inorder to support the old version of the
4440 * FW work with the latest app changes.
4441 */
4442
4443 iftype = wl_cfg80211_to_fw_iftype(cfg_iftype);
4444 if (iftype < 0) {
4445 return -ENOTSUPP;
4446 }
4447
4448 if (addr) {
4449 ifflags |= WL_INTERFACE_MAC_USE;
4450 }
4451
4452 #ifdef CUSTOMER_HW4
4453 /* BCM4359B0/C0 chips are using the iovar version 0 */
4454 if (wl_check_interface_create_v0(cfg)) {
4455 wl_interface_create_v0_t iface_v0;
4456
4457 WL_DBG(("interface_create version 0\n"));
4458 bzero(&iface_v0, sizeof(iface_v0));
4459 use_iface_info_v0 = true;
4460 iface_v0.ver = WL_INTERFACE_CREATE_VER_0;
4461 iface_v0.flags = ifflags;
4462 if (addr) {
4463 memcpy(&iface_v0.mac_addr.octet, addr, ETH_ALEN);
4464 }
4465 ret = wldev_iovar_getbuf(ndev, "interface_create",
4466 &iface_v0, sizeof(wl_interface_create_v0_t),
4467 ioctl_buf, sizeof(ioctl_buf), NULL);
4468 } else
4469 #endif /* CUSTOMER_HW4 */
4470 {
4471 /* Pass ver = 0 for fetching the interface_create iovar version */
4472 ret = wldev_iovar_getbuf(ndev, "interface_create",
4473 &iface, sizeof(struct wl_interface_create_v2),
4474 ioctl_buf, sizeof(ioctl_buf), NULL);
4475 if (ret == BCME_UNSUPPORTED) {
4476 WL_ERR(("interface_create iovar not supported\n"));
4477 return ret;
4478 } else if ((ret == 0) && *((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3) {
4479 WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags));
4480 use_iface_info_v2 = true;
4481 bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
4482 iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
4483 iface_v3.iftype = iftype;
4484 iface_v3.flags = ifflags;
4485 if (addr) {
4486 memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
4487 }
4488 ret = wldev_iovar_getbuf(ndev, "interface_create",
4489 &iface_v3, sizeof(wl_interface_create_v3_t),
4490 ioctl_buf, sizeof(ioctl_buf), NULL);
4491 } else {
4492 /* On any other error, attempt with iovar version 2 */
4493 WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n",
4494 ret, ifflags));
4495 iface.ver = WL_INTERFACE_CREATE_VER_2;
4496 iface.iftype = iftype;
4497 iface.flags = ifflags;
4498 if (addr) {
4499 memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
4500 }
4501 ret = wldev_iovar_getbuf(ndev, "interface_create",
4502 &iface, sizeof(struct wl_interface_create_v2),
4503 ioctl_buf, sizeof(ioctl_buf), NULL);
4504 }
4505 }
4506
4507 if (unlikely(ret)) {
4508 WL_ERR(("Interface create failed!! ret %d\n", ret));
4509 return ret;
4510 }
4511
4512 /* success case */
4513 if (use_iface_info_v2 == true) {
4514 info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
4515 ret = info_v2->bsscfgidx;
4516 }
4517 #ifdef CUSTOMER_HW4
4518 else if (use_iface_info_v0 == true) {
4519 /* Use v0 struct */
4520 info_v0 = (wl_interface_info_v0_t *)ioctl_buf;
4521 ret = info_v0->bsscfgidx;
4522 }
4523 #endif /* CUSTOMER_HW4 */
4524 else {
4525 /* Use v1 struct */
4526 info = (struct wl_interface_info_v1 *)ioctl_buf;
4527 ret = info->bsscfgidx;
4528 }
4529
4530 WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
4531 return ret;
4532 }
4533
4534 #if defined(CUSTOMER_HW4)
4535 void
4536 wl_bss_iovar_war(struct bcm_cfg80211 *cfg,
4537 struct net_device *ndev, s32 *val)
4538 {
4539 if (wl_legacy_chip_check(cfg) || wl_check_interface_create_v0(cfg))
4540 {
4541 /* Few firmware branches have issues in bss iovar handling and
4542 * that can't be changed since they are in production.
4543 */
4544 if (*val == WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE) {
4545 *val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
4546 } else if (*val == WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE) {
4547 *val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
4548 } else {
4549 /* Ignore for other bss enums */
4550 return;
4551 }
4552 WL_ERR(("wl bss %d\n", *val));
4553 }
4554 }
4555 #endif // endif
4556
4557 s32
4558 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
4559 struct net_device *ndev, s32 bsscfg_idx,
4560 wl_iftype_t brcm_iftype, s32 del, u8 *addr)
4561 {
4562 s32 ret = BCME_OK;
4563 s32 val = 0;
4564
4565 struct {
4566 s32 cfg;
4567 s32 val;
4568 struct ether_addr ea;
4569 } bss_setbuf;
4570
4571 WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype, del));
4572
4573 bzero(&bss_setbuf, sizeof(bss_setbuf));
4574
4575 /* AP=2, STA=3, up=1, down=0, val=-1 */
4576 if (del) {
4577 val = WLC_AP_IOV_OP_DELETE;
4578 } else if (brcm_iftype == WL_IF_TYPE_AP) {
4579 /* Add/role change to AP Interface */
4580 WL_DBG(("Adding AP Interface \n"));
4581 val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
4582 } else if (brcm_iftype == WL_IF_TYPE_STA) {
4583 /* Add/role change to STA Interface */
4584 WL_DBG(("Adding STA Interface \n"));
4585 val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
4586 } else {
4587 WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype));
4588 return -EINVAL;
4589 }
4590
4591 #if defined(CUSTOMER_HW4)
4592 if (!del) {
4593 wl_bss_iovar_war(cfg, ndev, &val);
4594 }
4595 #endif // endif
4596
4597 bss_setbuf.cfg = htod32(bsscfg_idx);
4598 bss_setbuf.val = htod32(val);
4599
4600 if (addr) {
4601 memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
4602 }
4603
4604 WL_INFORM_MEM(("wl bss %d bssidx:%d iface:%s \n", val, bsscfg_idx, ndev->name));
4605 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4606 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4607 if (ret != 0)
4608 WL_ERR(("'bss %d' failed with %d\n", val, ret));
4609
4610 return ret;
4611 }
4612
4613 s32
4614 wl_cfg80211_bss_up(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 bss_up)
4615 {
4616 s32 ret = BCME_OK;
4617 s32 val = bss_up ? 1 : 0;
4618
4619 struct {
4620 s32 cfg;
4621 s32 val;
4622 } bss_setbuf;
4623
4624 bss_setbuf.cfg = htod32(bsscfg_idx);
4625 bss_setbuf.val = htod32(val);
4626
4627 WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx, bss_up ? "up" : "down"));
4628 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4629 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4630
4631 if (ret != 0) {
4632 WL_ERR(("'bss %d' failed with %d\n", bss_up, ret));
4633 }
4634
4635 return ret;
4636 }
4637
4638 bool
4639 wl_cfg80211_bss_isup(struct net_device *ndev, int bsscfg_idx)
4640 {
4641 s32 result, val;
4642 bool isup = false;
4643 s8 getbuf[64];
4644
4645 /* Check if the BSS is up */
4646 *(int*)getbuf = -1;
4647 result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
4648 sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
4649 if (result != 0) {
4650 WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
4651 WL_ERR(("NOTE: this ioctl error is normal "
4652 "when the BSS has not been created yet.\n"));
4653 } else {
4654 val = *(int*)getbuf;
4655 val = dtoh32(val);
4656 WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx, val));
4657 isup = (val ? TRUE : FALSE);
4658 }
4659 return isup;
4660 }
4661
4662 s32
4663 wl_iftype_to_mode(wl_iftype_t iftype)
4664 {
4665 s32 mode = BCME_ERROR;
4666
4667 switch (iftype) {
4668 case WL_IF_TYPE_STA:
4669 case WL_IF_TYPE_P2P_GC:
4670 case WL_IF_TYPE_P2P_DISC:
4671 mode = WL_MODE_BSS;
4672 break;
4673 case WL_IF_TYPE_AP:
4674 case WL_IF_TYPE_P2P_GO:
4675 mode = WL_MODE_AP;
4676 break;
4677 case WL_IF_TYPE_NAN:
4678 mode = WL_MODE_NAN;
4679 break;
4680 case WL_IF_TYPE_AWDL:
4681 mode = WL_MODE_AWDL;
4682 break;
4683 case WL_IF_TYPE_AIBSS:
4684 /* Intentional fall through */
4685 case WL_IF_TYPE_IBSS:
4686 mode = WL_MODE_IBSS;
4687 break;
4688 default:
4689 WL_ERR(("Unsupported type:%d\n", iftype));
4690 break;
4691 }
4692 return mode;
4693 }
4694
4695 s32
4696 cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode)
4697 {
4698 switch (type) {
4699 case NL80211_IFTYPE_STATION:
4700 *role = WL_IF_TYPE_STA;
4701 *mode = WL_MODE_BSS;
4702 break;
4703 case NL80211_IFTYPE_AP:
4704 *role = WL_IF_TYPE_AP;
4705 *mode = WL_MODE_AP;
4706 break;
4707 #ifdef WL_CFG80211_P2P_DEV_IF
4708 case NL80211_IFTYPE_P2P_DEVICE:
4709 *role = WL_IF_TYPE_P2P_DISC;
4710 *mode = WL_MODE_BSS;
4711 break;
4712 #endif /* WL_CFG80211_P2P_DEV_IF */
4713 case NL80211_IFTYPE_P2P_GO:
4714 *role = WL_IF_TYPE_P2P_GO;
4715 *mode = WL_MODE_AP;
4716 break;
4717 case NL80211_IFTYPE_P2P_CLIENT:
4718 *role = WL_IF_TYPE_P2P_GC;
4719 *mode = WL_MODE_BSS;
4720 break;
4721 case NL80211_IFTYPE_MONITOR:
4722 WL_ERR(("Unsupported mode \n"));
4723 return BCME_UNSUPPORTED;
4724 case NL80211_IFTYPE_ADHOC:
4725 *role = WL_IF_TYPE_IBSS;
4726 *mode = WL_MODE_IBSS;
4727 break;
4728 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
4729 case NL80211_IFTYPE_NAN:
4730 *role = WL_IF_TYPE_NAN;
4731 *mode = WL_MODE_NAN;
4732 break;
4733 #endif // endif
4734 default:
4735 WL_ERR(("Unknown interface type:0x%x\n", type));
4736 return BCME_ERROR;
4737 }
4738 return BCME_OK;
4739 }
4740
4741 static s32
4742 wl_role_to_cfg80211_type(uint16 role, uint16 *wl_iftype, uint16 *mode)
4743 {
4744 switch (role) {
4745 *wl_iftype = WL_IF_TYPE_AWDL;
4746 *mode = WL_MODE_AWDL;
4747 return NL80211_IFTYPE_STATION;
4748 case WLC_E_IF_ROLE_STA:
4749 *wl_iftype = WL_IF_TYPE_STA;
4750 *mode = WL_MODE_BSS;
4751 return NL80211_IFTYPE_STATION;
4752 case WLC_E_IF_ROLE_AP:
4753 *wl_iftype = WL_IF_TYPE_AP;
4754 *mode = WL_MODE_AP;
4755 return NL80211_IFTYPE_AP;
4756 case WLC_E_IF_ROLE_P2P_GO:
4757 *wl_iftype = WL_IF_TYPE_P2P_GO;
4758 *mode = WL_MODE_AP;
4759 return NL80211_IFTYPE_P2P_GO;
4760 case WLC_E_IF_ROLE_P2P_CLIENT:
4761 *wl_iftype = WL_IF_TYPE_P2P_GC;
4762 *mode = WL_MODE_BSS;
4763 return NL80211_IFTYPE_P2P_CLIENT;
4764 case WLC_E_IF_ROLE_IBSS:
4765 *wl_iftype = WL_IF_TYPE_IBSS;
4766 *mode = WL_MODE_IBSS;
4767 return NL80211_IFTYPE_ADHOC;
4768 case WLC_E_IF_ROLE_NAN:
4769 *wl_iftype = WL_IF_TYPE_NAN;
4770 *mode = WL_MODE_NAN;
4771 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
4772 /* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
4773 * For Vendor HAL based NAN implementation, continue advertising
4774 * as a STA interface
4775 */
4776 return NL80211_IFTYPE_NAN;
4777 #else
4778 return NL80211_IFTYPE_STATION;
4779 #endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
4780
4781 default:
4782 WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role));
4783 return BCME_ERROR;
4784 }
4785 }
4786
4787 #define MAX_ACTIVE_IF_LINKS 2
4788 struct net_device *
4789 wl_cfg80211_post_ifcreate(struct net_device *ndev,
4790 wl_if_event_info *event, u8 *addr,
4791 const char *name, bool rtnl_lock_reqd)
4792 {
4793 struct bcm_cfg80211 *cfg;
4794 struct net_device *primary_ndev;
4795 struct net_device *new_ndev = NULL;
4796 struct wireless_dev *wdev = NULL;
4797 s32 iface_type;
4798 s32 ret = BCME_OK;
4799 u16 mode;
4800 u8 mac_addr[ETH_ALEN];
4801 u16 wl_iftype;
4802 #ifdef WL_STATIC_IF
4803 int need_legacy_war = 0;
4804 dhd_pub_t *dhd = NULL;
4805 #endif /* WL_STATIC_IF */
4806
4807 if (!ndev || !event) {
4808 WL_ERR(("Wrong arg\n"));
4809 return NULL;
4810 }
4811
4812 cfg = wl_get_cfg(ndev);
4813 if (!cfg) {
4814 WL_ERR(("cfg null\n"));
4815 return NULL;
4816 }
4817
4818 #ifdef WL_STATIC_IF
4819 {
4820 dhd = (dhd_pub_t *)(cfg->pub);
4821 if (!DHD_OPMODE_SUPPORTED(dhd, DHD_FLAG_MFG_MODE) && name) {
4822 need_legacy_war = ((wl_legacy_chip_check(cfg) ||
4823 wl_check_interface_create_v0(cfg)) &&
4824 !strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)));
4825 if (need_legacy_war) {
4826 event->role = WLC_E_IF_ROLE_AP;
4827 }
4828 }
4829 WL_DBG(("name: %s\n", name));
4830 }
4831 #endif /* WL_STATIC_IF */
4832
4833 WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
4834 event->role, event->ifidx, event->bssidx));
4835 if (!event->ifidx || !event->bssidx) {
4836 /* Fw returned primary idx (0) for virtual interface */
4837 WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
4838 event->ifidx, event->bssidx));
4839 return NULL;
4840 }
4841
4842 if (wl_get_drv_status_all(cfg, CONNECTED) > MAX_ACTIVE_IF_LINKS) {
4843 WL_ERR(("Can't support more than %d active links\n", MAX_ACTIVE_IF_LINKS));
4844 return NULL;
4845 }
4846
4847 iface_type = wl_role_to_cfg80211_type(event->role, &wl_iftype, &mode);
4848 if (iface_type < 0) {
4849 /* Unknown iface type */
4850 WL_ERR(("Wrong iface type \n"));
4851 return NULL;
4852 }
4853
4854 WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG "\n",
4855 addr, name, event->role, iface_type, MAC2STRDBG(event->mac)));
4856 if (!name) {
4857 /* If iface name is not provided, use dongle ifname */
4858 name = event->name;
4859 }
4860
4861 if (!addr) {
4862 /* If mac address is not set, use primary mac with locally administered
4863 * bit set.
4864 */
4865 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4866 memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
4867 /* For customer6 builds, use primary mac address for virtual interface */
4868 mac_addr[0] |= 0x02;
4869 addr = mac_addr;
4870 }
4871
4872 #ifdef WL_STATIC_IF
4873 if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
4874 new_ndev = wl_cfg80211_post_static_ifcreate(cfg, event, addr, iface_type);
4875 wdev = new_ndev->ieee80211_ptr;
4876
4877 if (need_legacy_war) {
4878 /* Check whether mac addr is in sync with fw. If not,
4879 * apply it using cur_etheraddr.
4880 */
4881 if (memcmp(addr, event->mac, ETH_ALEN) != 0) {
4882 ret = wldev_iovar_setbuf_bsscfg(new_ndev, "cur_etheraddr",
4883 addr, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
4884 event->bssidx, &cfg->ioctl_buf_sync);
4885 if (unlikely(ret)) {
4886 WL_ERR(("set cur_etheraddr Error (%d)\n", ret));
4887 goto fail;
4888 }
4889 memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
4890 WL_ERR(("Applying updated mac address to firmware\n"));
4891 }
4892
4893 if (!wl_get_drv_status(cfg, AP_CREATED, new_ndev)) {
4894 s32 err;
4895 WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n",
4896 new_ndev->name, event->bssidx));
4897 if ((err = wl_cfg80211_add_del_bss(cfg, new_ndev,
4898 event->bssidx, WL_IF_TYPE_AP, 0, NULL)) < 0) {
4899 WL_ERR(("wl bss ap returned error:%d\n", err));
4900 return NULL;
4901 }
4902 /* On success, mark AP creation in progress. */
4903 wl_set_drv_status(cfg, AP_CREATING, new_ndev);
4904 } else {
4905 WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
4906 }
4907 }
4908 } else
4909 #endif /* WL_STATIC_IF */
4910 {
4911 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
4912 name, addr, event->bssidx, event->name);
4913 if (!new_ndev) {
4914 WL_ERR(("I/F allocation failed! \n"));
4915 return NULL;
4916 } else {
4917 WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
4918 event->ifidx, event->bssidx));
4919 }
4920
4921 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
4922 if (!wdev) {
4923 WL_ERR(("wireless_dev alloc failed! \n"));
4924 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4925 return NULL;
4926 }
4927
4928 wdev->wiphy = bcmcfg_to_wiphy(cfg);
4929 wdev->iftype = iface_type;
4930
4931 new_ndev->ieee80211_ptr = wdev;
4932 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4933
4934 memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
4935 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd)
4936 != BCME_OK) {
4937 WL_ERR(("IFACE register failed \n"));
4938 /* Post interface registration, wdev would be freed from the netdev
4939 * destructor path. For other cases, handle it here.
4940 */
4941 MFREE(cfg->osh, wdev, sizeof(*wdev));
4942 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4943 return NULL;
4944 }
4945 }
4946
4947 /* Initialize with the station mode params */
4948 ret = wl_alloc_netinfo(cfg, new_ndev, wdev, wl_iftype,
4949 PM_ENABLE, event->bssidx, event->ifidx);
4950 if (unlikely(ret)) {
4951 WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret));
4952 goto fail;
4953 }
4954
4955 /* Apply the mode & infra setting based on iftype */
4956 if ((ret = wl_config_infra(cfg, new_ndev, wl_iftype)) < 0) {
4957 WL_ERR(("config ifmode failure (%d)\n", ret));
4958 goto fail;
4959 }
4960
4961 if (mode == WL_MODE_AP) {
4962 wl_set_drv_status(cfg, AP_CREATING, new_ndev);
4963 }
4964
4965 WL_INFORM_MEM(("Network Interface (%s) registered with host."
4966 " cfg_iftype:%d wl_role:%d " MACDBG "\n",
4967 new_ndev->name, iface_type, event->role, MAC2STRDBG(new_ndev->dev_addr)));
4968
4969 #ifdef SUPPORT_SET_CAC
4970 wl_cfg80211_set_cac(cfg, 0);
4971 #endif /* SUPPORT_SET_CAC */
4972
4973 return new_ndev;
4974
4975 fail:
4976 #ifdef WL_STATIC_IF
4977 /* remove static if from iflist */
4978 if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
4979 cfg->static_ndev_state = NDEV_STATE_FW_IF_FAILED;
4980 wl_cfg80211_update_iflist_info(cfg, new_ndev, WL_STATIC_IFIDX, addr,
4981 event->bssidx, event->name, NDEV_STATE_FW_IF_FAILED);
4982 }
4983 #endif /* WL_STATIC_IF */
4984 if (new_ndev) {
4985 /* wdev would be freed from netdev destructor call back */
4986 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4987 }
4988
4989 return NULL;
4990 }
4991
4992 void
4993 wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 *cfg, bool rtnl_lock_reqd)
4994 {
4995 struct net_info *iter, *next;
4996 struct net_device *primary_ndev;
4997
4998 /* Note: This function will clean up only the network interface and host
4999 * data structures. The firmware interface clean up will happen in the
5000 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
5001 * context for the module case).
5002 */
5003 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
5004 WL_DBG(("Enter\n"));
5005 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5006 #pragma GCC diagnostic push
5007 #pragma GCC diagnostic ignored "-Wcast-qual"
5008 #endif // endif
5009 for_each_ndev(cfg, iter, next) {
5010 if (iter->ndev && (iter->ndev != primary_ndev)) {
5011 /* Ensure interfaces are down before deleting */
5012 #ifdef WL_STATIC_IF
5013 /* Avoiding cleaning static ifaces */
5014 if (!IS_CFG80211_STATIC_IF(cfg, iter->ndev))
5015 #endif /* WL_STATIC_IF */
5016 {
5017 dev_close(iter->ndev);
5018 WL_DBG(("Cleaning up iface:%s \n", iter->ndev->name));
5019 wl_cfg80211_post_ifdel(iter->ndev, rtnl_lock_reqd, 0);
5020 }
5021 }
5022 }
5023 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5024 #pragma GCC diagnostic pop
5025 #endif // endif
5026 }
5027
5028 s32
5029 wl_cfg80211_post_ifdel(struct net_device *ndev, bool rtnl_lock_reqd, s32 ifidx)
5030 {
5031 s32 ret = BCME_OK;
5032 struct bcm_cfg80211 *cfg;
5033 u16 wl_iftype;
5034 struct net_info *netinfo = NULL;
5035
5036 if (!ndev || !ndev->ieee80211_ptr) {
5037 /* No wireless dev done for this interface */
5038 ret = -EINVAL;
5039 goto exit;
5040 }
5041
5042 cfg = wl_get_cfg(ndev);
5043 if (!cfg) {
5044 WL_ERR(("cfg null\n"));
5045 ret = BCME_ERROR;
5046 goto exit;
5047 }
5048
5049 if (ifidx <= 0) {
5050 WL_ERR(("Invalid IF idx for iface:%s\n", ndev->name));
5051 ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
5052 BCM_REFERENCE(ifidx);
5053 if (ifidx <= 0) {
5054 ASSERT(0);
5055 ret = BCME_ERROR;
5056 goto exit;
5057 }
5058 }
5059
5060 if ((netinfo = wl_get_netinfo_by_wdev(cfg, ndev_to_wdev(ndev))) == NULL) {
5061 WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev)));
5062 ret = -ENODEV;
5063 goto exit;
5064 }
5065 wl_iftype = netinfo->iftype;
5066
5067 #ifdef WL_STATIC_IF
5068 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
5069 ret = wl_cfg80211_post_static_ifdel(cfg, ndev);
5070 } else
5071 #endif /* WL_STATIC_IF */
5072 {
5073 #ifdef WL_NAN
5074 if (!((cfg->nancfg.mac_rand) && (wl_iftype == WL_IF_TYPE_NAN)))
5075 #endif /* WL_NAN */
5076 {
5077 wl_release_vif_macaddr(cfg, ndev->dev_addr, wl_iftype);
5078 }
5079 WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
5080 ndev->name, ifidx, cfg->vif_count));
5081 wl_cfg80211_remove_if(cfg, ifidx, ndev, rtnl_lock_reqd);
5082 cfg->bss_pending_op = FALSE;
5083 }
5084
5085 #ifdef SUPPORT_SET_CAC
5086 wl_cfg80211_set_cac(cfg, 1);
5087 #endif /* SUPPORT_SET_CAC */
5088 exit:
5089 return ret;
5090 }
5091 int
5092 wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 *cfg)
5093 {
5094 s32 ret = BCME_OK;
5095 bcm_struct_cfgdev *cfgdev;
5096
5097 if (cfg->p2p) {
5098 /* De-initialize the p2p discovery interface, if operational */
5099 WL_ERR(("Disabling P2P Discovery Interface \n"));
5100 #ifdef WL_CFG80211_P2P_DEV_IF
5101 cfgdev = bcmcfg_to_p2p_wdev(cfg);
5102 #else
5103 cfgdev = cfg->p2p_net;
5104 #endif // endif
5105 if (cfgdev) {
5106 ret = wl_cfg80211_scan_stop(cfg, cfgdev);
5107 if (unlikely(ret < 0)) {
5108 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
5109 }
5110 }
5111
5112 wl_cfgp2p_disable_discovery(cfg);
5113 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
5114 p2p_on(cfg) = false;
5115 }
5116 return ret;
5117 }
5118 /* Create a Generic Network Interface and initialize it depending up on
5119 * the interface type
5120 */
5121 struct wireless_dev *
5122 wl_cfg80211_create_iface(struct wiphy *wiphy,
5123 wl_iftype_t wl_iftype,
5124 u8 *mac_addr, const char *name)
5125 {
5126 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5127 struct net_device *new_ndev = NULL;
5128 struct net_device *primary_ndev = NULL;
5129 s32 ret = BCME_OK;
5130 s32 bsscfg_idx = 0;
5131 long timeout;
5132 wl_if_event_info *event = NULL;
5133 u8 addr[ETH_ALEN];
5134 struct net_info *iter, *next;
5135
5136 WL_DBG(("Enter\n"));
5137 if (!name) {
5138 WL_ERR(("Interface name not provided\n"));
5139 return NULL;
5140 }
5141 else {
5142 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5143 #pragma GCC diagnostic push
5144 #pragma GCC diagnostic ignored "-Wcast-qual"
5145 #endif // endif
5146 for_each_ndev(cfg, iter, next) {
5147 if (iter->ndev) {
5148 if (strcmp(iter->ndev->name, name) == 0) {
5149 WL_ERR(("Interface name, %s exists !\n", iter->ndev->name));
5150 return NULL;
5151 }
5152 }
5153 }
5154 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5155 #pragma GCC diagnostic pop
5156 #endif // endif
5157 }
5158
5159 /* If any scan is going on, abort it */
5160 if (wl_abort_scan_and_check(cfg) != TRUE) {
5161 return NULL;
5162 }
5163
5164 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
5165 if (likely(!mac_addr)) {
5166 /* Use primary MAC with the locally administered bit for the
5167 * Secondary STA I/F
5168 */
5169 memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
5170 addr[0] |= 0x02;
5171 } else {
5172 /* Use the application provided mac address (if any) */
5173 memcpy(addr, mac_addr, ETH_ALEN);
5174 }
5175
5176 cfg->bss_pending_op = TRUE;
5177 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
5178
5179 /* De-initialize the p2p discovery interface, if operational */
5180 wl_cfg80211_deinit_p2p_discovery(cfg);
5181
5182 /*
5183 * Intialize the firmware I/F.
5184 */
5185 #if defined(CUSTOMER_HW4)
5186 if (wl_legacy_chip_check(cfg))
5187 {
5188 /* Use bss iovar instead of interface_create iovar */
5189 ret = BCME_UNSUPPORTED;
5190 } else
5191 #endif // endif
5192 {
5193 ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
5194 wl_iftype, 0, addr);
5195 }
5196 if (ret == BCME_UNSUPPORTED) {
5197 /* Use bssidx 1 by default */
5198 bsscfg_idx = 1;
5199 if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
5200 bsscfg_idx, wl_iftype, 0, addr)) < 0) {
5201 goto exit;
5202 }
5203 } else if (ret < 0) {
5204 WL_ERR(("Interface create failed!! ret:%d \n", ret));
5205 goto exit;
5206 } else {
5207 /* Success */
5208 bsscfg_idx = ret;
5209 }
5210
5211 WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
5212 /*
5213 * Wait till the firmware send a confirmation event back.
5214 */
5215 WL_DBG(("Wait for the FW I/F Event\n"));
5216 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
5217 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
5218 if (timeout <= 0 || cfg->bss_pending_op) {
5219 WL_ERR(("ADD_IF event, didn't come. Return \n"));
5220 goto exit;
5221 }
5222
5223 event = &cfg->if_event_info;
5224 /*
5225 * Since FW operation is successful,we can go ahead with the
5226 * the host interface creation.
5227 */
5228 new_ndev = wl_cfg80211_post_ifcreate(primary_ndev,
5229 event, addr, name, false);
5230
5231 if (new_ndev) {
5232 /* Iface post ops successful. Return ndev/wdev ptr */
5233 return new_ndev->ieee80211_ptr;
5234 }
5235
5236 exit:
5237 cfg->bss_pending_op = FALSE;
5238 return NULL;
5239 }
5240
5241 s32
5242 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
5243 {
5244 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5245 struct net_device *ndev = NULL;
5246 s32 ret = BCME_OK;
5247 s32 bsscfg_idx = 1;
5248 long timeout;
5249 u16 wl_iftype;
5250 u16 wl_mode;
5251
5252 WL_DBG(("Enter\n"));
5253
5254 /* If any scan is going on, abort it */
5255 if (wl_get_drv_status_all(cfg, SCANNING)) {
5256 WL_DBG(("Scan in progress. Aborting the scan!\n"));
5257 wl_cfg80211_cancel_scan(cfg);
5258 }
5259
5260 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, wdev);
5261 if (bsscfg_idx <= 0) {
5262 /* validate bsscfgidx */
5263 WL_ERR(("Wrong bssidx! \n"));
5264 return -EINVAL;
5265 }
5266
5267 /* Handle p2p iface */
5268 if ((ret = wl_cfg80211_p2p_if_del(wiphy, wdev)) != BCME_NOTFOUND) {
5269 WL_DBG(("P2P iface del handled \n"));
5270 #ifdef SUPPORT_SET_CAC
5271 wl_cfg80211_set_cac(cfg, 1);
5272 #endif /* SUPPORT_SET_CAC */
5273 return ret;
5274 }
5275
5276 ndev = wdev->netdev;
5277 if (unlikely(!ndev)) {
5278 WL_ERR(("ndev null! \n"));
5279 return -EINVAL;
5280 }
5281
5282 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
5283
5284 if (cfg80211_to_wl_iftype(ndev->ieee80211_ptr->iftype,
5285 &wl_iftype, &wl_mode) < 0) {
5286 return -EINVAL;
5287 }
5288
5289 WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d",
5290 bsscfg_idx, ndev->ieee80211_ptr->iftype, wl_iftype));
5291 /* Delete the firmware interface. "interface_remove" command
5292 * should go on the interface to be deleted
5293 */
5294 if (wl_cfg80211_get_bus_state(cfg)) {
5295 WL_ERR(("Bus state is down: %s: %d\n", __FUNCTION__, __LINE__));
5296 ret = BCME_DONGLE_DOWN;
5297 goto exit;
5298 }
5299
5300 cfg->bss_pending_op = true;
5301 ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx,
5302 wl_iftype, 1, NULL);
5303 if (ret == BCME_UNSUPPORTED) {
5304 if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
5305 bsscfg_idx, wl_iftype, true, NULL)) < 0) {
5306 WL_ERR(("DEL bss failed ret:%d \n", ret));
5307 goto exit;
5308 }
5309 } else if ((ret == BCME_NOTAP) || (ret == BCME_NOTSTA)) {
5310 /* De-init sequence involving role downgrade not happened.
5311 * Do nothing and return error. The del command should be
5312 * retried.
5313 */
5314 WL_ERR(("ifdel role mismatch:%d\n", ret));
5315 ret = -EBADTYPE;
5316 goto exit;
5317 } else if (ret < 0) {
5318 WL_ERR(("Interface DEL failed ret:%d \n", ret));
5319 goto exit;
5320 }
5321
5322 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
5323 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
5324 if (timeout <= 0 || cfg->bss_pending_op) {
5325 WL_ERR(("timeout in waiting IF_DEL event\n"));
5326 /* The interface unregister will happen from wifi reset context */
5327 ret = -ETIMEDOUT;
5328 /* fall through */
5329 }
5330
5331 exit:
5332 if (ret < 0) {
5333 WL_ERR(("iface del failed:%d\n", ret));
5334 #ifdef WL_STATIC_IF
5335 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
5336 /*
5337 * For static interface, clean up the host data,
5338 * irrespective of fw status. For dynamic
5339 * interfaces it gets cleaned from dhd_stop context
5340 */
5341 wl_cfg80211_post_static_ifdel(cfg, ndev);
5342 }
5343 #endif /* WL_STATIC_IF */
5344 } else {
5345 ret = wl_cfg80211_post_ifdel(ndev, false, cfg->if_event_info.ifidx);
5346 if (unlikely(ret)) {
5347 WL_ERR(("post_ifdel failed\n"));
5348 }
5349 }
5350
5351 cfg->bss_pending_op = false;
5352 return ret;
5353 }
5354
5355 static s32
5356 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
5357 struct cfg80211_ibss_params *params)
5358 {
5359 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5360 struct cfg80211_bss *bss;
5361 struct ieee80211_channel *chan;
5362 struct wl_join_params join_params;
5363 int scan_suppress;
5364 struct cfg80211_ssid ssid;
5365 s32 scan_retry = 0;
5366 s32 err = 0;
5367 size_t join_params_size;
5368 chanspec_t chanspec = 0;
5369 u32 param[2] = {0, 0};
5370 u32 bw_cap = 0;
5371
5372 WL_TRACE(("In\n"));
5373 RETURN_EIO_IF_NOT_UP(cfg);
5374 WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
5375 if (!params->ssid || params->ssid_len <= 0 ||
5376 params->ssid_len > DOT11_MAX_SSID_LEN) {
5377 WL_ERR(("Invalid parameter\n"));
5378 return -EINVAL;
5379 }
5380 #if defined(WL_CFG80211_P2P_DEV_IF)
5381 chan = params->chandef.chan;
5382 #else
5383 chan = params->channel;
5384 #endif /* WL_CFG80211_P2P_DEV_IF */
5385 if (chan)
5386 cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
5387 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
5388 struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
5389 u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
5390 u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
5391 if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
5392 (memcmp(params->ssid, lssid->SSID, lssid->SSID_len) == 0) &&
5393 (*channel == cfg->channel))) {
5394 WL_ERR(("Connection already existed to " MACDBG "\n",
5395 MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
5396 return -EISCONN;
5397 }
5398 WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n",
5399 lssid->SSID, MAC2STRDBG(bssid)));
5400 }
5401
5402 /* remove the VSIE */
5403 wl_cfg80211_ibss_vsie_delete(dev);
5404
5405 bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
5406 if (!bss) {
5407 if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
5408 memcpy(ssid.ssid, params->ssid, params->ssid_len);
5409 ssid.ssid_len = params->ssid_len;
5410 do {
5411 if (unlikely
5412 (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
5413 -EBUSY)) {
5414 wl_delay(150);
5415 } else {
5416 break;
5417 }
5418 } while (++scan_retry < WL_SCAN_RETRY_MAX);
5419
5420 /* rtnl lock code is removed here. don't see why rtnl lock
5421 * needs to be released.
5422 */
5423
5424 /* wait 4 secons till scan done.... */
5425 schedule_timeout_interruptible(msecs_to_jiffies(4000));
5426
5427 bss = cfg80211_get_ibss(wiphy, NULL,
5428 params->ssid, params->ssid_len);
5429 }
5430 }
5431 if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
5432 ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
5433 !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
5434 cfg->ibss_starter = false;
5435 WL_DBG(("Found IBSS\n"));
5436 } else {
5437 cfg->ibss_starter = true;
5438 }
5439
5440 if (bss) {
5441 CFG80211_PUT_BSS(wiphy, bss);
5442 }
5443
5444 if (chan) {
5445 if (chan->band == NL80211_BAND_5GHZ)
5446 param[0] = WLC_BAND_5G;
5447 else if (chan->band == NL80211_BAND_2GHZ)
5448 param[0] = WLC_BAND_2G;
5449 err = wldev_iovar_getint(dev, "bw_cap", param);
5450 if (unlikely(err)) {
5451 WL_ERR(("Get bw_cap Failed (%d)\n", err));
5452 return err;
5453 }
5454 bw_cap = param[0];
5455 chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap);
5456 }
5457 /*
5458 * Join with specific BSSID and cached SSID
5459 * If SSID is zero join based on BSSID only
5460 */
5461 memset(&join_params, 0, sizeof(join_params));
5462 memcpy((void *)join_params.ssid.SSID, (const void *)params->ssid,
5463 params->ssid_len);
5464 join_params.ssid.SSID_len = htod32(params->ssid_len);
5465 if (params->bssid) {
5466 memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
5467 err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
5468 ETHER_ADDR_LEN);
5469 if (unlikely(err)) {
5470 WL_ERR(("Error (%d)\n", err));
5471 return err;
5472 }
5473 } else
5474 memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
5475
5476 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5477 scan_suppress = TRUE;
5478 /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
5479 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5480 &scan_suppress, sizeof(int));
5481 if (unlikely(err)) {
5482 WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
5483 return err;
5484 }
5485 }
5486
5487 join_params.params.chanspec_list[0] = chanspec;
5488 join_params.params.chanspec_num = 1;
5489 wldev_iovar_setint(dev, "chanspec", chanspec);
5490 join_params_size = sizeof(join_params);
5491
5492 /* Disable Authentication, IBSS will add key if it required */
5493 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
5494 wldev_iovar_setint(dev, "wsec", 0);
5495
5496 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
5497 join_params_size);
5498 if (unlikely(err)) {
5499 WL_ERR(("IBSS set_ssid Error (%d)\n", err));
5500 return err;
5501 }
5502
5503 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5504 scan_suppress = FALSE;
5505 /* Reset the SCAN SUPPRESS Flag */
5506 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5507 &scan_suppress, sizeof(int));
5508 if (unlikely(err)) {
5509 WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
5510 return err;
5511 }
5512 }
5513 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
5514 wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
5515 #ifdef WLAIBSS
5516 cfg->aibss_txfail_seq = 0; /* initialize the sequence */
5517 #endif /* WLAIBSS */
5518 #ifdef WL_RELMCAST
5519 cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
5520 #endif /* WL_RELMCAST */
5521 return err;
5522 }
5523
5524 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
5525 {
5526 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5527 s32 err = 0;
5528 scb_val_t scbval;
5529 u8 *curbssid;
5530
5531 RETURN_EIO_IF_NOT_UP(cfg);
5532 wl_link_down(cfg);
5533
5534 WL_INFORM_MEM(("Leave IBSS\n"));
5535 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
5536 wl_set_drv_status(cfg, DISCONNECTING, dev);
5537 scbval.val = 0;
5538 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
5539 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
5540 sizeof(scb_val_t));
5541 if (unlikely(err)) {
5542 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5543 WL_ERR(("error(%d)\n", err));
5544 return err;
5545 }
5546
5547 /* remove the VSIE */
5548 wl_cfg80211_ibss_vsie_delete(dev);
5549
5550 return err;
5551 }
5552
5553 #ifdef MFP
5554 static
5555 int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie,
5556 const u8** rsn_cap)
5557 {
5558 u16 suite_count;
5559 const wpa_suite_mcast_t *mcast;
5560 const wpa_suite_ucast_t *ucast;
5561 int len;
5562 const wpa_suite_auth_key_mgmt_t *mgmt;
5563
5564 if (!wpa2ie)
5565 return BCME_BADARG;
5566
5567 len = wpa2ie->len;
5568
5569 /* check for Multicast cipher suite */
5570 if ((len -= (WPA_SUITE_LEN + WPA2_VERSION_LEN)) <= 0) {
5571 return BCME_NOTFOUND;
5572 }
5573
5574 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
5575
5576 /* Check for the unicast suite(s) */
5577 if (len < WPA_IE_SUITE_COUNT_LEN) {
5578 return BCME_NOTFOUND;
5579 }
5580
5581 ucast = (const wpa_suite_ucast_t *)&mcast[1];
5582 suite_count = ltoh16_ua(&ucast->count);
5583 if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
5584 (len -= (WPA_IE_SUITE_COUNT_LEN +
5585 (WPA_SUITE_LEN * suite_count))) <= 0)
5586 return BCME_BADLEN;
5587
5588 /* Check for AUTH key management suite(s) */
5589 if (len < WPA_IE_SUITE_COUNT_LEN) {
5590 return BCME_NOTFOUND;
5591 }
5592
5593 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
5594 suite_count = ltoh16_ua(&mgmt->count);
5595
5596 if ((suite_count <= NL80211_MAX_NR_CIPHER_SUITES) &&
5597 (len -= (WPA_IE_SUITE_COUNT_LEN +
5598 (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
5599 rsn_cap[0] = (const u8 *)&mgmt->list[suite_count];
5600 } else {
5601 return BCME_BADLEN;
5602 }
5603
5604 return BCME_OK;
5605 }
5606 #endif /* MFP */
5607
5608 static s32
5609 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
5610 {
5611 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5612 struct wl_security *sec;
5613 s32 val = 0;
5614 s32 err = 0;
5615 s32 bssidx;
5616
5617 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5618 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5619 return BCME_ERROR;
5620 }
5621
5622 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
5623 val = WPA_AUTH_PSK |
5624 #ifdef BCMCCX
5625 WPA_AUTH_CCKM |
5626 #endif // endif
5627 WPA_AUTH_UNSPECIFIED;
5628 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
5629 val = WPA2_AUTH_PSK|
5630 #ifdef BCMCCX
5631 WPA2_AUTH_CCKM |
5632 #endif // endif
5633 WPA2_AUTH_UNSPECIFIED;
5634 else
5635 val = WPA_AUTH_DISABLED;
5636
5637 if (is_wps_conn(sme))
5638 val = WPA_AUTH_DISABLED;
5639
5640 #ifdef BCMWAPI_WPI
5641 if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) {
5642 WL_DBG((" * wl_set_wpa_version, set wpa_auth"
5643 " to WPA_AUTH_WAPI 0x400"));
5644 val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5645 }
5646 #endif // endif
5647 WL_INFORM_MEM(("[%s] wl wpa_auth 0x%0x\n", dev->name, val));
5648 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
5649 if (unlikely(err)) {
5650 WL_ERR(("set wpa_auth failed (%d)\n", err));
5651 return err;
5652 }
5653 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5654 sec->wpa_versions = sme->crypto.wpa_versions;
5655 return err;
5656 }
5657
5658 #ifdef BCMWAPI_WPI
5659 static s32
5660 wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme)
5661 {
5662 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5663 s32 err = 0;
5664 s32 bssidx;
5665
5666 WL_DBG((" %s \n", __FUNCTION__));
5667 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5668 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5669 return BCME_ERROR;
5670 }
5671
5672 err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", (const void *)sme->ie, sme->ie_len,
5673 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5674 if (unlikely(err)) {
5675 WL_ERR(("set_wapi_ie Error (%d)\n", err));
5676 return err;
5677 }
5678 WL_INFORM_MEM(("wapi_ie successfully (%s)\n", dev->name));
5679 return err;
5680 }
5681 #endif /* BCMWAPI_WPI */
5682
5683 static s32
5684 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
5685 {
5686 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5687 struct wl_security *sec;
5688 s32 val = 0;
5689 s32 err = 0;
5690 s32 bssidx;
5691
5692 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5693 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5694 return BCME_ERROR;
5695 }
5696
5697 switch (sme->auth_type) {
5698 case NL80211_AUTHTYPE_OPEN_SYSTEM:
5699 val = WL_AUTH_OPEN_SYSTEM;
5700 WL_DBG(("open system\n"));
5701 break;
5702 case NL80211_AUTHTYPE_SHARED_KEY:
5703 val = WL_AUTH_SHARED_KEY;
5704 WL_DBG(("shared key\n"));
5705 break;
5706 case NL80211_AUTHTYPE_AUTOMATIC:
5707 val = WL_AUTH_OPEN_SHARED;
5708 WL_DBG(("automatic\n"));
5709 break;
5710 #ifdef BCMCCX
5711 case NL80211_AUTHTYPE_NETWORK_EAP:
5712 WL_DBG(("network eap\n"));
5713 val = DOT11_LEAP_AUTH;
5714 break;
5715 #endif // endif
5716 default:
5717 val = 2;
5718 WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
5719 break;
5720 }
5721
5722 WL_INFORM_MEM(("[%s] wl auth 0x%0x \n", dev->name, val));
5723 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
5724 if (unlikely(err)) {
5725 WL_ERR(("set auth failed (%d)\n", err));
5726 return err;
5727 }
5728 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5729 sec->auth_type = sme->auth_type;
5730 return err;
5731 }
5732
5733 static s32
5734 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
5735 {
5736 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5737 struct wl_security *sec;
5738 s32 pval = 0;
5739 s32 gval = 0;
5740 s32 err = 0;
5741 s32 wsec_val = 0;
5742 #ifdef BCMWAPI_WPI
5743 s32 wapi_val = 0;
5744 s32 val = 0;
5745 #endif // endif
5746 s32 bssidx;
5747
5748 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5749 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5750 return BCME_ERROR;
5751 }
5752
5753 if (sme->crypto.n_ciphers_pairwise) {
5754 switch (sme->crypto.ciphers_pairwise[0]) {
5755 case WLAN_CIPHER_SUITE_WEP40:
5756 case WLAN_CIPHER_SUITE_WEP104:
5757 pval = WEP_ENABLED;
5758 break;
5759 case WLAN_CIPHER_SUITE_TKIP:
5760 pval = TKIP_ENABLED;
5761 break;
5762 case WLAN_CIPHER_SUITE_CCMP:
5763 case WLAN_CIPHER_SUITE_AES_CMAC:
5764 pval = AES_ENABLED;
5765 break;
5766 #ifdef BCMWAPI_WPI
5767 case WLAN_CIPHER_SUITE_SMS4:
5768 val = SMS4_ENABLED;
5769 pval = SMS4_ENABLED;
5770 err = wl_set_set_wapi_ie(dev, sme);
5771 if (unlikely(err)) {
5772 WL_DBG(("Set wapi ie failed \n"));
5773 return err;
5774 } else {
5775 WL_DBG(("Set wapi ie succeded\n"));
5776 }
5777 wapi_val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5778 WL_INFORM_MEM(("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val, dev->name));
5779 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wapi_val, bssidx);
5780 if (unlikely(err)) {
5781 WL_ERR(("set wpa_auth failed (%d)\n", err));
5782 return err;
5783 }
5784 break;
5785 #endif /* BCMWAPI_WPI */
5786 default:
5787 WL_ERR(("invalid cipher pairwise (%d)\n",
5788 sme->crypto.ciphers_pairwise[0]));
5789 return -EINVAL;
5790 }
5791 }
5792 #if defined(BCMSUP_4WAY_HANDSHAKE)
5793 /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
5794 * handshake.
5795 * Note that the FW feature flag only exists on kernels that support the
5796 * FT-EAP AKM suite.
5797 */
5798 if (cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) {
5799 err = wldev_iovar_setint_bsscfg(dev, "sup_wpa", 1, bssidx);
5800 if (err) {
5801 WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err));
5802 return err;
5803 } else {
5804 WL_INFORM_MEM(("idsup enabled.\n"));
5805 }
5806 }
5807 #endif /* BCMSUP_4WAY_HANDSHAKE */
5808 if (sme->crypto.cipher_group) {
5809 switch (sme->crypto.cipher_group) {
5810 case WLAN_CIPHER_SUITE_WEP40:
5811 case WLAN_CIPHER_SUITE_WEP104:
5812 gval = WEP_ENABLED;
5813 break;
5814 case WLAN_CIPHER_SUITE_TKIP:
5815 gval = TKIP_ENABLED;
5816 break;
5817 case WLAN_CIPHER_SUITE_CCMP:
5818 gval = AES_ENABLED;
5819 break;
5820 case WLAN_CIPHER_SUITE_AES_CMAC:
5821 gval = AES_ENABLED;
5822 break;
5823 #ifdef BCMWAPI_WPI
5824 case WLAN_CIPHER_SUITE_SMS4:
5825 val = SMS4_ENABLED;
5826 gval = SMS4_ENABLED;
5827 break;
5828 #endif // endif
5829 default:
5830 WL_ERR(("invalid cipher group (%d)\n",
5831 sme->crypto.cipher_group));
5832 return -EINVAL;
5833 }
5834 }
5835
5836 WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
5837
5838 if (is_wps_conn(sme)) {
5839 if (sme->privacy) {
5840 wsec_val = 4;
5841 } else {
5842 /* WPS-2.0 allows no security */
5843 wsec_val = 0;
5844 }
5845 } else {
5846 #ifdef BCMWAPI_WPI
5847 if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) {
5848 WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
5849 wsec_val = val;
5850 } else
5851 #endif // endif
5852 {
5853 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
5854 wsec_val = pval | gval;
5855 }
5856 }
5857
5858 WL_INFORM_MEM(("[%s] wl wsec 0x%x\n", dev->name, wsec_val));
5859 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec_val, bssidx);
5860 if (unlikely(err)) {
5861 WL_ERR(("error (%d)\n", err));
5862 return err;
5863 }
5864
5865 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5866 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
5867 sec->cipher_group = sme->crypto.cipher_group;
5868 return err;
5869 }
5870
5871 #ifdef MFP
5872 static s32
5873 wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
5874 struct net_device *dev,
5875 struct cfg80211_connect_params *sme)
5876 {
5877 s32 mfp = WL_MFP_NONE;
5878 s32 current_mfp = WL_MFP_NONE;
5879 const bcm_tlv_t *wpa2_ie;
5880 const u8* rsn_cap = NULL;
5881 bool fw_support = false;
5882 int err, count = 0;
5883 const u8 *eptr = NULL, *ptr = NULL;
5884 const u8* group_mgmt_cs = NULL;
5885 const wpa_pmkid_list_t* pmkid = NULL;
5886
5887 if (!sme) {
5888 /* No connection params from userspace, Do nothing. */
5889 return 0;
5890 }
5891
5892 /* Check fw support and retreive current mfp val */
5893 err = wldev_iovar_getint(dev, "mfp", &current_mfp);
5894 if (!err) {
5895 fw_support = true;
5896 }
5897
5898 /* Parse the wpa2ie to decode the MFP capablity */
5899 if (((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
5900 DOT11_MNG_RSN_ID)) != NULL) &&
5901 (wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) {
5902 WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap[0], rsn_cap[1]));
5903 /* Check for MFP cap in the RSN capability field */
5904 if (sme->mfp) {
5905 if (rsn_cap[0] & RSN_CAP_MFPR) {
5906 mfp = WL_MFP_REQUIRED;
5907 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
5908 mfp = WL_MFP_CAPABLE;
5909 }
5910 }
5911 /*
5912 * eptr --> end/last byte addr of wpa2_ie
5913 * ptr --> to keep track of current/required byte addr
5914 */
5915 eptr = (const u8*)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN);
5916 /* pointing ptr to the next byte after rns_cap */
5917 ptr = (const u8*)rsn_cap + RSN_CAP_LEN;
5918 if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) {
5919 /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
5920 pmkid = (const wpa_pmkid_list_t*)ptr;
5921 count = pmkid->count.low | (pmkid->count.high << 8);
5922 /* ptr now to point to last byte addr of pmkid */
5923 ptr = (const u8*)pmkid + (count * WPA2_PMKID_LEN
5924 + WPA2_PMKID_COUNT_LEN);
5925 if ((eptr - ptr) >= WPA_SUITE_LEN) {
5926 /* group_mgmt_cs now to point to first byte addr of bip */
5927 group_mgmt_cs = ptr;
5928 }
5929 }
5930 }
5931
5932 WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n",
5933 mfp, wpa2_ie, fw_support));
5934
5935 if (fw_support == false) {
5936 if (mfp) {
5937 /* if mfp > 0, mfp capability set in wpa ie, but
5938 * FW indicated error for mfp. Propagate the error up.
5939 */
5940 WL_ERR(("mfp capability found in wpaie. But fw doesn't"
5941 "seem to support MFP\n"));
5942 err = -EINVAL;
5943 goto exit;
5944 } else {
5945 /* Firmware doesn't support mfp. But since connection request
5946 * is for non-mfp case, don't bother.
5947 */
5948 err = BCME_OK;
5949 goto exit;
5950 }
5951 } else if (mfp != current_mfp) {
5952 err = wldev_iovar_setint(dev, "mfp", mfp);
5953 if (unlikely(err)) {
5954 WL_ERR(("mfp (%d) set failed ret:%d \n", mfp, err));
5955 goto exit;
5956 }
5957 WL_INFORM_MEM(("[%s] wl mfp 0x%x\n", dev->name, mfp));
5958 }
5959
5960 if (group_mgmt_cs && bcmp((const uint8 *)WPA2_OUI,
5961 group_mgmt_cs, (WPA_SUITE_LEN - 1)) == 0) {
5962 WL_DBG(("BIP is found\n"));
5963 err = wldev_iovar_setbuf(dev, "bip",
5964 group_mgmt_cs, WPA_SUITE_LEN, cfg->ioctl_buf,
5965 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5966 /*
5967 * Dont return failure for unsupported cases
5968 * of bip iovar for backward compatibility
5969 */
5970 if (err != BCME_UNSUPPORTED && err < 0) {
5971 WL_ERR(("bip set error (%d)\n", err));
5972 #if defined(CUSTOMER_HW4)
5973 if (wl_legacy_chip_check(cfg))
5974 {
5975 /* Ignore bip error: Some older firmwares doesn't
5976 * support bip iovar/ return BCME_NOTUP while trying
5977 * to set bip from connect context. These firmares
5978 * include bip in RSNIE by default. So its okay to
5979 * ignore the error.
5980 */
5981 err = BCME_OK;
5982 goto exit;
5983 } else
5984 #endif // endif
5985 {
5986 goto exit;
5987 }
5988 } else {
5989 WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n",
5990 dev->name, group_mgmt_cs[0], group_mgmt_cs[1],
5991 group_mgmt_cs[2]));
5992 }
5993 }
5994
5995 exit:
5996 if (err) {
5997 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
5998 FW_LOGSET_MASK_ALL);
5999 }
6000 return 0;
6001 }
6002 #endif /* MFP */
6003
6004 static s32
6005 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
6006 {
6007 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6008 struct wl_security *sec;
6009 s32 val = 0;
6010 s32 err = 0;
6011 s32 bssidx;
6012
6013 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6014 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6015 return BCME_ERROR;
6016 }
6017
6018 if (sme->crypto.n_akm_suites) {
6019 err = wldev_iovar_getint(dev, "wpa_auth", &val);
6020 if (unlikely(err)) {
6021 WL_ERR(("could not get wpa_auth (%d)\n", err));
6022 return err;
6023 }
6024 if (val & (WPA_AUTH_PSK |
6025 #ifdef BCMCCX
6026 WPA_AUTH_CCKM |
6027 #endif // endif
6028 WPA_AUTH_UNSPECIFIED)) {
6029 switch (sme->crypto.akm_suites[0]) {
6030 case WLAN_AKM_SUITE_8021X:
6031 val = WPA_AUTH_UNSPECIFIED;
6032 break;
6033 case WLAN_AKM_SUITE_PSK:
6034 val = WPA_AUTH_PSK;
6035 break;
6036 #ifdef BCMCCX
6037 case WLAN_AKM_SUITE_CCKM:
6038 val = WPA_AUTH_CCKM;
6039 break;
6040 #endif // endif
6041 default:
6042 WL_ERR(("invalid akm suite (0x%x)\n",
6043 sme->crypto.akm_suites[0]));
6044 return -EINVAL;
6045 }
6046 } else if (val & (WPA2_AUTH_PSK |
6047 #ifdef BCMCCX
6048 WPA2_AUTH_CCKM |
6049 #endif // endif
6050 WPA2_AUTH_UNSPECIFIED)) {
6051 switch (sme->crypto.akm_suites[0]) {
6052 case WLAN_AKM_SUITE_8021X:
6053 val = WPA2_AUTH_UNSPECIFIED;
6054 break;
6055 #ifdef MFP
6056 case WL_AKM_SUITE_SHA256_1X:
6057 val = WPA2_AUTH_1X_SHA256;
6058 break;
6059 case WL_AKM_SUITE_SHA256_PSK:
6060 val = WPA2_AUTH_PSK_SHA256;
6061 break;
6062 #endif /* MFP */
6063 case WLAN_AKM_SUITE_PSK:
6064 val = WPA2_AUTH_PSK;
6065 break;
6066 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
6067 case WLAN_AKM_SUITE_FT_8021X:
6068 val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT;
6069 break;
6070 #endif // endif
6071 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
6072 case WLAN_AKM_SUITE_FT_PSK:
6073 val = WPA2_AUTH_PSK | WPA2_AUTH_FT;
6074 break;
6075 #endif // endif
6076 #ifdef BCMCCX
6077 case WLAN_AKM_SUITE_CCKM:
6078 val = WPA2_AUTH_CCKM;
6079 break;
6080 #endif // endif
6081 case WLAN_AKM_SUITE_FILS_SHA256:
6082 val = WPA2_AUTH_FILS_SHA256;
6083 break;
6084 case WLAN_AKM_SUITE_FILS_SHA384:
6085 val = WPA2_AUTH_FILS_SHA384;
6086 break;
6087 default:
6088 WL_ERR(("invalid akm suite (0x%x)\n",
6089 sme->crypto.akm_suites[0]));
6090 return -EINVAL;
6091 }
6092 }
6093 #ifdef BCMWAPI_WPI
6094 else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) {
6095 switch (sme->crypto.akm_suites[0]) {
6096 case WLAN_AKM_SUITE_WAPI_CERT:
6097 val = WAPI_AUTH_UNSPECIFIED;
6098 break;
6099 case WLAN_AKM_SUITE_WAPI_PSK:
6100 val = WAPI_AUTH_PSK;
6101 break;
6102 default:
6103 WL_ERR(("invalid akm suite (0x%x)\n",
6104 sme->crypto.akm_suites[0]));
6105 return -EINVAL;
6106 }
6107 }
6108 #endif // endif
6109
6110 #ifdef MFP
6111 if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) {
6112 WL_ERR(("MFP set failed err:%d\n", err));
6113 return -EINVAL;
6114 }
6115 #endif /* MFP */
6116
6117 WL_INFORM_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val));
6118 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
6119 if (unlikely(err)) {
6120 WL_ERR(("could not set wpa_auth (0x%x)\n", err));
6121 return err;
6122 }
6123 }
6124 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6125 sec->wpa_auth = sme->crypto.akm_suites[0];
6126
6127 return err;
6128 }
6129
6130 static s32
6131 wl_set_set_sharedkey(struct net_device *dev,
6132 struct cfg80211_connect_params *sme)
6133 {
6134 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6135 struct wl_security *sec;
6136 struct wl_wsec_key key;
6137 s32 val;
6138 s32 err = 0;
6139 s32 bssidx;
6140
6141 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6142 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6143 return BCME_ERROR;
6144 }
6145
6146 WL_DBG(("key len (%d)\n", sme->key_len));
6147 if (sme->key_len) {
6148 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6149 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
6150 sec->wpa_versions, sec->cipher_pairwise));
6151 if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
6152 NL80211_WPA_VERSION_2)) &&
6153 #ifdef BCMWAPI_WPI
6154 !is_wapi(sec->cipher_pairwise) &&
6155 #endif // endif
6156 (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
6157 WLAN_CIPHER_SUITE_WEP104)))
6158 {
6159 memset(&key, 0, sizeof(key));
6160 key.len = (u32) sme->key_len;
6161 key.index = (u32) sme->key_idx;
6162 if (unlikely(key.len > sizeof(key.data))) {
6163 WL_ERR(("Too long key length (%u)\n", key.len));
6164 return -EINVAL;
6165 }
6166 memcpy(key.data, sme->key, key.len);
6167 key.flags = WL_PRIMARY_KEY;
6168 switch (sec->cipher_pairwise) {
6169 case WLAN_CIPHER_SUITE_WEP40:
6170 key.algo = CRYPTO_ALGO_WEP1;
6171 break;
6172 case WLAN_CIPHER_SUITE_WEP104:
6173 key.algo = CRYPTO_ALGO_WEP128;
6174 break;
6175 default:
6176 WL_ERR(("Invalid algorithm (%d)\n",
6177 sme->crypto.ciphers_pairwise[0]));
6178 return -EINVAL;
6179 }
6180 /* Set the new key/index */
6181 WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
6182 key.len, key.index, key.algo));
6183 WL_DBG(("key \"%s\"\n", key.data));
6184 swap_key_from_BE(&key);
6185 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6186 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6187 if (unlikely(err)) {
6188 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6189 return err;
6190 }
6191 WL_INFORM_MEM(("key applied to fw\n"));
6192 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
6193 WL_DBG(("set auth_type to shared key\n"));
6194 val = WL_AUTH_SHARED_KEY; /* shared key */
6195 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
6196 if (unlikely(err)) {
6197 WL_ERR(("set auth failed (%d)\n", err));
6198 return err;
6199 }
6200 }
6201 }
6202 }
6203 return err;
6204 }
6205
6206 #if defined(ESCAN_RESULT_PATCH)
6207 static u8 connect_req_bssid[6];
6208 static u8 broad_bssid[6];
6209 #endif /* ESCAN_RESULT_PATCH */
6210
6211 #if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
6212 static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
6213 {
6214 u32 chanspec = 0;
6215 bool isvht80 = 0;
6216
6217 if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK)
6218 chanspec = wl_chspec_driver_to_host(chanspec);
6219
6220 isvht80 = chanspec & WL_CHANSPEC_BW_80;
6221 WL_DBG(("%s: chanspec(%x:%d)\n", __FUNCTION__, chanspec, isvht80));
6222
6223 return isvht80;
6224 }
6225 #endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
6226
6227 int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80211 *cfg,
6228 bool disassociate)
6229 {
6230 scb_val_t scbval;
6231 int err = TRUE;
6232 int wait_cnt;
6233
6234 if (disassociate) {
6235 WL_ERR(("Disassociate previous connection!\n"));
6236 wl_set_drv_status(cfg, DISCONNECTING, dev);
6237 scbval.val = DOT11_RC_DISASSOC_LEAVING;
6238 scbval.val = htod32(scbval.val);
6239
6240 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6241 sizeof(scb_val_t));
6242 if (unlikely(err)) {
6243 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6244 WL_ERR(("error (%d)\n", err));
6245 return err;
6246 }
6247 wait_cnt = 500/10;
6248 } else {
6249 wait_cnt = 200/10;
6250 WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
6251 if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6252 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6253 }
6254 }
6255
6256 while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
6257 WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
6258 wait_cnt));
6259 wait_cnt--;
6260 OSL_SLEEP(10);
6261 }
6262
6263 if (wait_cnt == 0) {
6264 WL_ERR(("DISCONNECING clean up failed!\n"));
6265 return BCME_NOTREADY;
6266 }
6267 return BCME_OK;
6268 }
6269
6270 #define MAX_SCAN_ABORT_WAIT_CNT 20
6271 #define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
6272
6273 static s32
6274 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
6275 struct cfg80211_connect_params *sme)
6276 {
6277 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6278 struct ieee80211_channel *chan = sme->channel;
6279 wl_extjoin_params_t *ext_join_params;
6280 struct wl_join_params join_params;
6281 size_t join_params_size;
6282 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6283 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6284 s32 roam_trigger[2] = {0, 0};
6285 #endif /* ROAM_AP_ENV_DETECTION */
6286 s32 err = 0;
6287 const wpa_ie_fixed_t *wpa_ie;
6288 const bcm_tlv_t *wpa2_ie;
6289 const u8* wpaie = 0;
6290 u32 wpaie_len = 0;
6291 u32 chan_cnt = 0;
6292 struct ether_addr bssid;
6293 s32 bssidx = -1;
6294 #ifdef ESCAN_CHANNEL_CACHE
6295 chanspec_t chanspec_list[MAX_ROAM_CHANNEL];
6296 #endif /* ESCAN_CHANNEL_CACHE */
6297 int wait_cnt;
6298
6299 WL_DBG(("In\n"));
6300 if (!dev) {
6301 WL_ERR(("dev is null\n"));
6302 return -EINVAL;
6303 }
6304 BCM_REFERENCE(dhdp);
6305
6306 #ifdef ESCAN_CHANNEL_CACHE
6307 memset(chanspec_list, 0, (sizeof(chanspec_t) * MAX_ROAM_CHANNEL));
6308 #endif /* ESCAN_CHANNEL_CACHE */
6309
6310 /* Connection attempted via linux-wireless */
6311 wl_set_drv_status(cfg, CFG80211_CONNECT, dev);
6312 #ifdef DHDTCPSYNC_FLOOD_BLK
6313 dhd_reset_tcpsync_info_by_dev(dev);
6314 #endif /* DHDTCPSYNC_FLOOD_BLK */
6315
6316 #if defined(SUPPORT_RANDOM_MAC_SCAN)
6317 wl_cfg80211_random_mac_disable(dev);
6318 #endif /* SUPPORT_RANDOM_MAC_SCAN */
6319
6320 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6321 if (sme->channel_hint) {
6322 chan = sme->channel_hint;
6323 WL_INFORM_MEM(("channel_hint (%d), channel_hint center_freq (%d)\n",
6324 ieee80211_frequency_to_channel(sme->channel_hint->center_freq),
6325 sme->channel_hint->center_freq));
6326 }
6327 if (sme->bssid_hint) {
6328 sme->bssid = sme->bssid_hint;
6329 WL_INFORM_MEM(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
6330 }
6331 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6332
6333 if (unlikely(!sme->ssid)) {
6334 WL_ERR(("Invalid ssid\n"));
6335 return -EOPNOTSUPP;
6336 }
6337
6338 if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) {
6339 WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n",
6340 sme->ssid, sme->ssid_len));
6341 return -EINVAL;
6342 }
6343
6344 WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
6345 if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
6346 prhex(NULL, sme->ie, sme->ie_len);
6347 }
6348
6349 RETURN_EIO_IF_NOT_UP(cfg);
6350 /*
6351 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
6352 */
6353 if (cfg->scan_request) {
6354 WL_TRACE_HW4(("Aborting the scan! \n"));
6355 wl_cfg80211_scan_abort(cfg);
6356 wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
6357 while (wl_get_drv_status(cfg, SCANNING, dev) && wait_cnt) {
6358 WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
6359 wait_cnt--;
6360 OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
6361 }
6362 if (wl_get_drv_status(cfg, SCANNING, dev)) {
6363 wl_cfg80211_cancel_scan(cfg);
6364 }
6365 }
6366 #ifdef WL_SCHED_SCAN
6367 /* Locks are taken in wl_cfg80211_sched_scan_stop()
6368 * A start scan occuring during connect is unlikely
6369 */
6370 if (cfg->sched_scan_req) {
6371 wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg));
6372 }
6373 #endif /* WL_SCHED_SCAN */
6374 #ifdef WL_CFG80211_GON_COLLISION
6375 /* init block gon req count */
6376 cfg->block_gon_req_tx_count = 0;
6377 cfg->block_gon_req_rx_count = 0;
6378 #endif /* WL_CFG80211_GON_COLLISION */
6379 #if defined(ESCAN_RESULT_PATCH)
6380 if (sme->bssid)
6381 memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN);
6382 else
6383 bzero(connect_req_bssid, ETHER_ADDR_LEN);
6384 bzero(broad_bssid, ETHER_ADDR_LEN);
6385 #endif // endif
6386 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
6387 maxrxpktglom = 0;
6388 #endif // endif
6389 if (wl_get_drv_status(cfg, CONNECTING, dev) || wl_get_drv_status(cfg, CONNECTED, dev)) {
6390 /* set nested connect bit to identify the context */
6391 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6392 /* DHD prev status is CONNECTING/CONNECTED */
6393 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
6394 } else if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6395 /* DHD prev status is DISCONNECTING */
6396 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, false);
6397 } else if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6398 /* DHD previous status is not connected and FW connected */
6399 if (wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) == 0) {
6400 /* set nested connect bit to identify the context */
6401 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6402 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, true);
6403 }
6404 }
6405
6406 if (sme->bssid) {
6407 wl_update_prof(cfg, dev, NULL, sme->bssid, WL_PROF_LATEST_BSSID);
6408 } else {
6409 wl_update_prof(cfg, dev, NULL, &ether_bcast, WL_PROF_LATEST_BSSID);
6410 }
6411
6412 /* 'connect' request received */
6413 wl_set_drv_status(cfg, CONNECTING, dev);
6414 /* clear nested connect bit on proceeding for connection */
6415 wl_clr_drv_status(cfg, NESTED_CONNECT, dev);
6416
6417 /* Clean BSSID */
6418 bzero(&bssid, sizeof(bssid));
6419 if (!wl_get_drv_status(cfg, DISCONNECTING, dev))
6420 wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
6421
6422 if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) {
6423 /* we only allow to connect using virtual interface in case of P2P */
6424 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6425 WL_ERR(("Find p2p index from wdev(%p) failed\n",
6426 dev->ieee80211_ptr));
6427 err = BCME_ERROR;
6428 goto exit;
6429 }
6430 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6431 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
6432 } else if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6433 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6434 WL_ERR(("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr));
6435 err = BCME_ERROR;
6436 goto exit;
6437 }
6438
6439 /* find the RSN_IE */
6440 if ((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
6441 DOT11_MNG_RSN_ID)) != NULL) {
6442 WL_DBG((" WPA2 IE is found\n"));
6443 }
6444 /* find the WPA_IE */
6445 if ((wpa_ie = wl_cfgp2p_find_wpaie(sme->ie,
6446 sme->ie_len)) != NULL) {
6447 WL_DBG((" WPA IE is found\n"));
6448 }
6449 if (wpa_ie != NULL || wpa2_ie != NULL) {
6450 wpaie = (wpa_ie != NULL) ? (const u8 *)wpa_ie : (const u8 *)wpa2_ie;
6451 wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
6452 wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
6453 err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
6454 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6455 if (unlikely(err)) {
6456 WL_ERR(("wpaie set error (%d)\n", err));
6457 goto exit;
6458 }
6459 } else {
6460 err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
6461 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6462 if (unlikely(err)) {
6463 WL_ERR(("wpaie set error (%d)\n", err));
6464 goto exit;
6465 }
6466 }
6467 err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6468 VNDR_IE_ASSOCREQ_FLAG, (const u8 *)sme->ie, sme->ie_len);
6469 if (unlikely(err)) {
6470 goto exit;
6471 }
6472 }
6473 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6474 if (dhdp->roam_env_detection) {
6475 bool is_roamtrig_reset = TRUE;
6476 bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection",
6477 AP_ENV_DETECT_NOT_USED) == BCME_OK);
6478
6479 #ifdef SKIP_ROAM_TRIGGER_RESET
6480 roam_trigger[1] = WLC_BAND_2G;
6481 is_roamtrig_reset =
6482 (wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
6483 sizeof(roam_trigger)) == BCME_OK) &&
6484 (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER-10);
6485 #endif /* SKIP_ROAM_TRIGGER_RESET */
6486 if (is_roamtrig_reset && is_roam_env_ok) {
6487 roam_trigger[0] = WL_AUTO_ROAM_TRIGGER;
6488 roam_trigger[1] = WLC_BAND_ALL;
6489 err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
6490 sizeof(roam_trigger));
6491 if (unlikely(err)) {
6492 WL_ERR((" failed to restore roam_trigger for auto env"
6493 " detection\n"));
6494 }
6495 }
6496 }
6497 #endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
6498 if (chan) {
6499 cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
6500 chan_cnt = 1;
6501 WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel,
6502 chan->center_freq, chan_cnt));
6503 } else {
6504 WL_DBG(("No channel info from user space\n"));
6505 cfg->channel = 0;
6506 }
6507 #ifdef ESCAN_CHANNEL_CACHE
6508 /*
6509 * No channel information from user space. if ECC is enabled, the ECC
6510 * would prepare the channel list, else no channel would be provided
6511 * and firmware would need to do a full channel scan.
6512 *
6513 * Use cached channels. This might take slightly longer time compared
6514 * to using a single channel based join. But ECC would help choose
6515 * a better AP for a given ssid. For a given SSID there might multiple
6516 * APs on different channels and ECC would scan all those channels
6517 * before deciding up on the AP. This accounts for the additional delay.
6518 */
6519 if (cfg->rcc_enabled || cfg->channel == 0)
6520 {
6521 wlc_ssid_t ssid;
6522 int band;
6523
6524 err = wldev_get_band(dev, &band);
6525 if (!err) {
6526 set_roam_band(band);
6527 }
6528
6529 memcpy(ssid.SSID, sme->ssid, sme->ssid_len);
6530 ssid.SSID_len = (uint32)sme->ssid_len;
6531 chan_cnt = get_roam_channel_list(cfg->channel, chanspec_list,
6532 MAX_ROAM_CHANNEL, &ssid, ioctl_version);
6533 WL_DBG(("RCC channel count:%d \n", chan_cnt));
6534 }
6535 #endif /* ESCAN_CHANNEL_CACHE */
6536 WL_DBG(("3. set wpa version \n"));
6537
6538 err = wl_set_wpa_version(dev, sme);
6539 if (unlikely(err)) {
6540 WL_ERR(("Invalid wpa_version\n"));
6541 goto exit;
6542 }
6543 #ifdef BCMWAPI_WPI
6544 if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1)
6545 WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n"));
6546 else {
6547 WL_DBG(("4. wl_set_auth_type\n"));
6548 #endif // endif
6549 err = wl_set_auth_type(dev, sme);
6550 if (unlikely(err)) {
6551 WL_ERR(("Invalid auth type\n"));
6552 goto exit;
6553 }
6554 #ifdef BCMWAPI_WPI
6555 }
6556 #endif // endif
6557
6558 err = wl_set_set_cipher(dev, sme);
6559 if (unlikely(err)) {
6560 WL_ERR(("Invalid ciper\n"));
6561 goto exit;
6562 }
6563
6564 err = wl_set_key_mgmt(dev, sme);
6565 if (unlikely(err)) {
6566 WL_ERR(("Invalid key mgmt\n"));
6567 goto exit;
6568 }
6569
6570 err = wl_set_set_sharedkey(dev, sme);
6571 if (unlikely(err)) {
6572 WL_ERR(("Invalid shared key\n"));
6573 goto exit;
6574 }
6575
6576 /*
6577 * Join with specific BSSID and cached SSID
6578 * If SSID is zero join based on BSSID only
6579 */
6580 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
6581 chan_cnt * sizeof(chanspec_t);
6582 ext_join_params = (wl_extjoin_params_t *)MALLOCZ(cfg->osh, join_params_size);
6583 if (ext_join_params == NULL) {
6584 err = -ENOMEM;
6585 wl_clr_drv_status(cfg, CONNECTING, dev);
6586 goto exit;
6587 }
6588 ext_join_params->ssid.SSID_len =
6589 (uint32)min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
6590 memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
6591 wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
6592 ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
6593 /* increate dwell time to receive probe response or detect Beacon
6594 * from target AP at a noisy air only during connect command
6595 */
6596 ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
6597 ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
6598 /* Set up join scan parameters */
6599 ext_join_params->scan.scan_type = -1;
6600 ext_join_params->scan.nprobes = chan_cnt ?
6601 (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
6602 ext_join_params->scan.home_time = -1;
6603
6604 if (sme->bssid)
6605 memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
6606 else
6607 memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
6608 ext_join_params->assoc.chanspec_num = chan_cnt;
6609
6610 if (chan_cnt && !cfg->rcc_enabled) {
6611 if (cfg->channel) {
6612 /*
6613 * Use the channel provided by userspace
6614 */
6615 u16 channel, band, bw, ctl_sb;
6616 chanspec_t chspec;
6617 channel = cfg->channel;
6618 band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
6619 : WL_CHANSPEC_BAND_5G;
6620
6621 /* Get min_bw set for the interface */
6622 bw = WL_CHANSPEC_BW_20;
6623 if (bw == INVCHANSPEC) {
6624 WL_ERR(("Invalid chanspec \n"));
6625 MFREE(cfg->osh, ext_join_params, join_params_size);
6626 err = BCME_ERROR;
6627 goto exit;
6628 }
6629
6630 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
6631 chspec = (channel | band | bw | ctl_sb);
6632 ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
6633 ext_join_params->assoc.chanspec_list[0] |= chspec;
6634 ext_join_params->assoc.chanspec_list[0] =
6635 wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]);
6636 }
6637 }
6638 #ifdef ESCAN_CHANNEL_CACHE
6639 else {
6640 memcpy(ext_join_params->assoc.chanspec_list, chanspec_list,
6641 sizeof(chanspec_t) * chan_cnt);
6642 }
6643 #endif /* ESCAN_CHANNEL_CACHE */
6644 ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
6645 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
6646 WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
6647 ext_join_params->ssid.SSID_len));
6648 }
6649
6650 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6651 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6652 MFREE(cfg->osh, ext_join_params, join_params_size);
6653 err = BCME_ERROR;
6654 goto exit;
6655 }
6656 #ifdef DHD_EVENT_LOG_FILTER
6657 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6658 /* inform only for STA Interface */
6659 dhd_event_log_filter_notify_connect_request(dhdp,
6660 (uint8 *)(&ext_join_params->assoc.bssid), cfg->channel);
6661 }
6662 #endif /* DHD_EVENT_LOG_FILTER */
6663 #ifdef WLTDLS
6664 /* disable TDLS if number of connected interfaces is >= 1 */
6665 wl_cfg80211_tdls_config(cfg, TDLS_STATE_CONNECT, false);
6666 #endif /* WLTDLS */
6667 err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
6668 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6669 if (cfg->rcc_enabled) {
6670 WL_INFORM_MEM(("[%s] Connecting with " MACDBG " ssid \"%s\","
6671 " len (%d) with rcc channels. chan_cnt:%d \n\n",
6672 dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
6673 "*****", ext_join_params->ssid.SSID_len, chan_cnt));
6674 } else {
6675 WL_INFORM_MEM(("[%s] Connecting with " MACDBG " ssid \"%s\","
6676 "len (%d) channel:%d\n\n",
6677 dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
6678 "*****", ext_join_params->ssid.SSID_len, cfg->channel));
6679 }
6680 SUPP_LOG(("[%s] Connecting with " MACDBG " ssid \"%s\","
6681 "channel:%d rcc:%d\n",
6682 dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
6683 ext_join_params->ssid.SSID, cfg->channel, cfg->rcc_enabled));
6684 MFREE(cfg->osh, ext_join_params, join_params_size);
6685 if (err) {
6686 wl_clr_drv_status(cfg, CONNECTING, dev);
6687 if (err == BCME_UNSUPPORTED) {
6688 WL_DBG(("join iovar is not supported\n"));
6689 goto set_ssid;
6690 } else {
6691 WL_ERR(("join iovar error (%d)\n", err));
6692 goto exit;
6693 }
6694 } else
6695 goto exit;
6696
6697 set_ssid:
6698 #if defined(ROAMEXP_SUPPORT)
6699 /* Clear Blacklist bssid and Whitelist ssid list before join issue
6700 * This is temporary fix since currently firmware roaming is not
6701 * disabled by android framework before SSID join from framework
6702 */
6703 /* Flush blacklist bssid content */
6704 dhd_dev_set_blacklist_bssid(dev, NULL, 0, true);
6705 /* Flush whitelist ssid content */
6706 dhd_dev_set_whitelist_ssid(dev, NULL, 0, true);
6707 #endif /* OEM_ANDROID && ROAMEXP_SUPPORT */
6708 memset(&join_params, 0, sizeof(join_params));
6709 join_params_size = sizeof(join_params.ssid);
6710
6711 join_params.ssid.SSID_len = (uint32)min(sizeof(join_params.ssid.SSID), sme->ssid_len);
6712 memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
6713 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
6714 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
6715 if (sme->bssid)
6716 memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
6717 else
6718 memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
6719
6720 if (wl_ch_to_chanspec(dev, cfg->channel, &join_params, &join_params_size) < 0) {
6721 WL_ERR(("Invalid chanspec\n"));
6722 return -EINVAL;
6723 }
6724
6725 WL_DBG(("join_param_size %zu\n", join_params_size));
6726
6727 if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
6728 WL_INFORM_MEM(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
6729 join_params.ssid.SSID_len));
6730 }
6731 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, join_params_size);
6732 exit:
6733 if (err) {
6734 WL_ERR(("error (%d)\n", err));
6735 wl_clr_drv_status(cfg, CONNECTING, dev);
6736 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
6737 #ifdef WLTDLS
6738 /* If connect fails, check whether we can enable back TDLS */
6739 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
6740 #endif /* WLTDLS */
6741 }
6742 #ifdef DBG_PKT_MON
6743 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && !err) {
6744 DHD_DBG_PKT_MON_START(dhdp);
6745 }
6746 #endif /* DBG_PKT_MON */
6747 return err;
6748 }
6749
6750 #define WAIT_FOR_DISCONNECT_MAX 10
6751 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev)
6752 {
6753 uint8 wait_cnt;
6754
6755 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
6756 while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
6757 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
6758 wait_cnt--;
6759 OSL_SLEEP(50);
6760 }
6761
6762 return;
6763 }
6764
6765 static s32
6766 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
6767 u16 reason_code)
6768 {
6769 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6770 scb_val_t scbval;
6771 bool act = false;
6772 s32 err = 0;
6773 u8 *curbssid = NULL;
6774 u8 null_bssid[ETHER_ADDR_LEN];
6775 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6776 WL_ERR(("Reason %d\n", reason_code));
6777 RETURN_EIO_IF_NOT_UP(cfg);
6778 act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
6779 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
6780
6781 BCM_REFERENCE(dhdp);
6782
6783 #ifdef ESCAN_RESULT_PATCH
6784 if (wl_get_drv_status(cfg, CONNECTING, dev) && curbssid &&
6785 (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0)) {
6786 WL_ERR(("Disconnecting from connecting device: " MACDBG "\n",
6787 MAC2STRDBG(curbssid)));
6788 act = true;
6789 }
6790 #endif /* ESCAN_RESULT_PATCH */
6791
6792 if (!curbssid) {
6793 WL_ERR(("Disconnecting while CONNECTING status %d\n", (int)sizeof(null_bssid)));
6794 bzero(null_bssid, sizeof(null_bssid));
6795 curbssid = null_bssid;
6796 }
6797
6798 if (act) {
6799 #ifdef DBG_PKT_MON
6800 /* Stop packet monitor */
6801 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6802 DHD_DBG_PKT_MON_STOP(dhdp);
6803 }
6804 #endif /* DBG_PKT_MON */
6805 /*
6806 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
6807 */
6808 /* Let scan aborted by F/W */
6809 if (cfg->scan_request) {
6810 WL_TRACE_HW4(("Aborting the scan! \n"));
6811 wl_cfg80211_cancel_scan(cfg);
6812 }
6813 if (wl_get_drv_status(cfg, CONNECTING, dev) ||
6814 wl_get_drv_status(cfg, CONNECTED, dev)) {
6815 wl_set_drv_status(cfg, DISCONNECTING, dev);
6816 scbval.val = reason_code;
6817 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
6818 scbval.val = htod32(scbval.val);
6819 WL_INFORM_MEM(("[%s] wl disassoc\n", dev->name));
6820 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6821 sizeof(scb_val_t));
6822 if (unlikely(err)) {
6823 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6824 WL_ERR(("error (%d)\n", err));
6825 return err;
6826 }
6827 }
6828 #ifdef WL_WPS_SYNC
6829 /* If are in WPS reauth state, then we would be
6830 * dropping the link down events. Ensure that
6831 * Event is sent up for the disconnect Req
6832 */
6833 if (wl_wps_session_update(dev,
6834 WPS_STATE_DISCONNECT, curbssid) == BCME_OK) {
6835 WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
6836 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6837 }
6838 #endif /* WPS_SYNC */
6839 wl_cfg80211_wait_for_disconnection(cfg, dev);
6840 if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6841 CFG80211_CONNECT_RESULT(dev, NULL, NULL,
6842 NULL, 0, NULL, 0,
6843 WLAN_STATUS_UNSPECIFIED_FAILURE,
6844 GFP_KERNEL);
6845 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6846 }
6847 } else {
6848 WL_INFORM_MEM(("act is false\n"));
6849 CFG80211_CONNECT_RESULT(dev, NULL, NULL,
6850 NULL, 0, NULL, 0,
6851 WLAN_STATUS_UNSPECIFIED_FAILURE,
6852 GFP_KERNEL);
6853 }
6854 #ifdef CUSTOM_SET_CPUCORE
6855 /* set default cpucore */
6856 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6857 dhdp->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
6858 if (!(dhdp->chan_isvht80))
6859 dhd_set_cpucore(dhdp, FALSE);
6860 }
6861 #endif /* CUSTOM_SET_CPUCORE */
6862
6863 cfg->rssi = 0; /* reset backup of rssi */
6864
6865 return err;
6866 }
6867
6868 #if defined(WL_CFG80211_P2P_DEV_IF)
6869 static s32
6870 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
6871 enum nl80211_tx_power_setting type, s32 mbm)
6872 #else
6873 static s32
6874 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
6875 enum nl80211_tx_power_setting type, s32 dbm)
6876 #endif /* WL_CFG80211_P2P_DEV_IF */
6877 {
6878
6879 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6880 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6881 s32 err = 0;
6882 #if defined(WL_CFG80211_P2P_DEV_IF)
6883 s32 dbm = MBM_TO_DBM(mbm);
6884 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
6885 defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
6886 dbm = MBM_TO_DBM(dbm);
6887 #endif /* WL_CFG80211_P2P_DEV_IF */
6888
6889 RETURN_EIO_IF_NOT_UP(cfg);
6890 switch (type) {
6891 case NL80211_TX_POWER_AUTOMATIC:
6892 break;
6893 case NL80211_TX_POWER_LIMITED:
6894 if (dbm < 0) {
6895 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
6896 return -EINVAL;
6897 }
6898 break;
6899 case NL80211_TX_POWER_FIXED:
6900 if (dbm < 0) {
6901 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
6902 return -EINVAL;
6903 }
6904 break;
6905 }
6906
6907 err = wl_set_tx_power(ndev, type, dbm);
6908 if (unlikely(err)) {
6909 WL_ERR(("error (%d)\n", err));
6910 return err;
6911 }
6912
6913 cfg->conf->tx_power = dbm;
6914
6915 return err;
6916 }
6917
6918 #if defined(WL_CFG80211_P2P_DEV_IF)
6919 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
6920 struct wireless_dev *wdev, s32 *dbm)
6921 #else
6922 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
6923 #endif /* WL_CFG80211_P2P_DEV_IF */
6924 {
6925 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6926 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6927 s32 err = 0;
6928
6929 RETURN_EIO_IF_NOT_UP(cfg);
6930 err = wl_get_tx_power(ndev, dbm);
6931 if (unlikely(err))
6932 WL_ERR(("error (%d)\n", err));
6933
6934 return err;
6935 }
6936
6937 static s32
6938 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
6939 u8 key_idx, bool unicast, bool multicast)
6940 {
6941 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6942 u32 index;
6943 s32 wsec;
6944 s32 err = 0;
6945 s32 bssidx;
6946
6947 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6948 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
6949 return BCME_ERROR;
6950 }
6951
6952 WL_DBG(("key index (%d)\n", key_idx));
6953 RETURN_EIO_IF_NOT_UP(cfg);
6954 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
6955 if (unlikely(err)) {
6956 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
6957 return err;
6958 }
6959 if (wsec == WEP_ENABLED) {
6960 /* Just select a new current key */
6961 index = (u32) key_idx;
6962 index = htod32(index);
6963 err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index,
6964 sizeof(index));
6965 if (unlikely(err)) {
6966 WL_ERR(("error (%d)\n", err));
6967 }
6968 }
6969 return err;
6970 }
6971
6972 static s32
6973 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
6974 u8 key_idx, const u8 *mac_addr, struct key_params *params)
6975 {
6976 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6977 struct wl_wsec_key key;
6978 s32 err = 0;
6979 s32 bssidx;
6980 s32 mode = wl_get_mode_by_netdev(cfg, dev);
6981
6982 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6983 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6984 return BCME_ERROR;
6985 }
6986 memset(&key, 0, sizeof(key));
6987 key.index = (u32) key_idx;
6988
6989 if (!ETHER_ISMULTI(mac_addr))
6990 memcpy((char *)&key.ea, (const void *)mac_addr, ETHER_ADDR_LEN);
6991 key.len = (u32) params->key_len;
6992
6993 /* check for key index change */
6994 if (key.len == 0) {
6995 /* key delete */
6996 swap_key_from_BE(&key);
6997 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6998 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6999 if (unlikely(err)) {
7000 WL_ERR(("key delete error (%d)\n", err));
7001 return err;
7002 }
7003 } else {
7004 if (key.len > sizeof(key.data)) {
7005 WL_ERR(("Invalid key length (%d)\n", key.len));
7006 return -EINVAL;
7007 }
7008 WL_DBG(("Setting the key index %d\n", key.index));
7009 memcpy(key.data, params->key, key.len);
7010
7011 if ((mode == WL_MODE_BSS) &&
7012 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
7013 u8 keybuf[8];
7014 memcpy(keybuf, &key.data[24], sizeof(keybuf));
7015 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
7016 memcpy(&key.data[16], keybuf, sizeof(keybuf));
7017 }
7018
7019 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
7020 if (params->seq && params->seq_len == 6) {
7021 /* rx iv */
7022 const u8 *ivptr;
7023 ivptr = (const u8 *) params->seq;
7024 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
7025 (ivptr[3] << 8) | ivptr[2];
7026 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
7027 key.iv_initialized = true;
7028 }
7029
7030 switch (params->cipher) {
7031 case WLAN_CIPHER_SUITE_WEP40:
7032 key.algo = CRYPTO_ALGO_WEP1;
7033 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7034 break;
7035 case WLAN_CIPHER_SUITE_WEP104:
7036 key.algo = CRYPTO_ALGO_WEP128;
7037 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7038 break;
7039 case WLAN_CIPHER_SUITE_TKIP:
7040 key.algo = CRYPTO_ALGO_TKIP;
7041 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7042 break;
7043 case WLAN_CIPHER_SUITE_AES_CMAC:
7044 key.algo = CRYPTO_ALGO_AES_CCM;
7045 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7046 break;
7047 case WLAN_CIPHER_SUITE_CCMP:
7048 key.algo = CRYPTO_ALGO_AES_CCM;
7049 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
7050 break;
7051 #ifdef BCMWAPI_WPI
7052 case WLAN_CIPHER_SUITE_SMS4:
7053 key.algo = CRYPTO_ALGO_SMS4;
7054 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7055 break;
7056 #endif // endif
7057 default:
7058 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7059 return -EINVAL;
7060 }
7061 swap_key_from_BE(&key);
7062 /* need to guarantee EAPOL 4/4 send out before set key */
7063 dhd_wait_pend8021x(dev);
7064 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7065 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7066 if (unlikely(err)) {
7067 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7068 return err;
7069 }
7070 WL_INFORM_MEM(("[%s] wsec key set\n", dev->name));
7071 }
7072 return err;
7073 }
7074
7075 int
7076 wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
7077 {
7078 int err;
7079 wl_eventmsg_buf_t ev_buf;
7080 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7081
7082 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7083 /* roam offload is only for the primary device */
7084 return -1;
7085 }
7086
7087 WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev->name, enable));
7088 err = wldev_iovar_setint(dev, "roam_offload", enable);
7089 if (err)
7090 return err;
7091
7092 bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
7093 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
7094 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
7095 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
7096 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
7097 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
7098 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
7099 err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
7100 if (!err) {
7101 cfg->roam_offload = enable;
7102 }
7103 return err;
7104 }
7105
7106 struct wireless_dev *
7107 wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 *cfg, const char *name)
7108 {
7109 struct net_info *iter, *next;
7110
7111 if (name == NULL) {
7112 return NULL;
7113 }
7114
7115 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
7116 #pragma GCC diagnostic push
7117 #pragma GCC diagnostic ignored "-Wcast-qual"
7118 #endif // endif
7119 for_each_ndev(cfg, iter, next) {
7120 if (iter->ndev) {
7121 if (strcmp(iter->ndev->name, name) == 0) {
7122 return iter->ndev->ieee80211_ptr;
7123 }
7124 }
7125 }
7126 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
7127 #pragma GCC diagnostic pop
7128 #endif // endif
7129 WL_DBG(("Iface %s not found\n", name));
7130 return NULL;
7131 }
7132
7133 #if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
7134 void
7135 wl_cfg80211_block_arp(struct net_device *dev, int enable)
7136 {
7137 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7138 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7139
7140 WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev->name, enable));
7141 if (!dhd_pkt_filter_enable) {
7142 WL_DBG(("Packet filter isn't enabled\n"));
7143 return;
7144 }
7145
7146 /* Block/Unblock ARP frames only if STA is connected to
7147 * the upstream AP in case of STA+SoftAP Concurrenct mode
7148 */
7149 if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
7150 WL_DBG(("STA not connected to upstream AP\n"));
7151 return;
7152 }
7153
7154 if (enable) {
7155 WL_DBG(("Enable ARP Filter\n"));
7156 /* Add ARP filter */
7157 dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
7158
7159 /* Enable ARP packet filter - blacklist */
7160 dhd_master_mode = FALSE;
7161 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7162 TRUE, dhd_master_mode);
7163 } else {
7164 WL_DBG(("Disable ARP Filter\n"));
7165 /* Disable ARP packet filter */
7166 dhd_master_mode = TRUE;
7167 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7168 FALSE, dhd_master_mode);
7169
7170 /* Delete ARP filter */
7171 dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
7172 }
7173 }
7174 #endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
7175
7176 static s32
7177 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
7178 u8 key_idx, bool pairwise, const u8 *mac_addr,
7179 struct key_params *params)
7180 {
7181 struct wl_wsec_key key;
7182 s32 val = 0;
7183 s32 wsec = 0;
7184 s32 err = 0;
7185 u8 keybuf[8];
7186 s32 bssidx = 0;
7187 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7188 s32 mode = wl_get_mode_by_netdev(cfg, dev);
7189 WL_DBG(("key index (%d)\n", key_idx));
7190 RETURN_EIO_IF_NOT_UP(cfg);
7191
7192 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7193 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
7194 return BCME_ERROR;
7195 }
7196
7197 if (mac_addr &&
7198 ((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
7199 (params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
7200 wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
7201 goto exit;
7202 }
7203 memset(&key, 0, sizeof(key));
7204 /* Clear any buffered wep key */
7205 memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
7206
7207 key.len = (u32) params->key_len;
7208 key.index = (u32) key_idx;
7209
7210 if (unlikely(key.len > sizeof(key.data))) {
7211 WL_ERR(("Too long key length (%u)\n", key.len));
7212 return -EINVAL;
7213 }
7214 memcpy(key.data, params->key, key.len);
7215
7216 key.flags = WL_PRIMARY_KEY;
7217 switch (params->cipher) {
7218 case WLAN_CIPHER_SUITE_WEP40:
7219 key.algo = CRYPTO_ALGO_WEP1;
7220 val = WEP_ENABLED;
7221 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7222 break;
7223 case WLAN_CIPHER_SUITE_WEP104:
7224 key.algo = CRYPTO_ALGO_WEP128;
7225 val = WEP_ENABLED;
7226 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7227 break;
7228 case WLAN_CIPHER_SUITE_TKIP:
7229 key.algo = CRYPTO_ALGO_TKIP;
7230 val = TKIP_ENABLED;
7231 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
7232 if (mode == WL_MODE_BSS) {
7233 bcopy(&key.data[24], keybuf, sizeof(keybuf));
7234 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
7235 bcopy(keybuf, &key.data[16], sizeof(keybuf));
7236 }
7237 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7238 break;
7239 case WLAN_CIPHER_SUITE_AES_CMAC:
7240 key.algo = CRYPTO_ALGO_AES_CCM;
7241 val = AES_ENABLED;
7242 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7243 break;
7244 case WLAN_CIPHER_SUITE_CCMP:
7245 key.algo = CRYPTO_ALGO_AES_CCM;
7246 val = AES_ENABLED;
7247 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
7248 break;
7249 #ifdef BCMWAPI_WPI
7250 case WLAN_CIPHER_SUITE_SMS4:
7251 key.algo = CRYPTO_ALGO_SMS4;
7252 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7253 val = SMS4_ENABLED;
7254 break;
7255 #endif /* BCMWAPI_WPI */
7256 #if defined(WLAN_CIPHER_SUITE_PMK)
7257 case WLAN_CIPHER_SUITE_PMK: {
7258 int j;
7259 wsec_pmk_t pmk;
7260 char keystring[WSEC_MAX_PSK_LEN + 1];
7261 char* charptr = keystring;
7262 u16 len;
7263 struct wl_security *sec;
7264
7265 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7266 if (sec->wpa_auth == WLAN_AKM_SUITE_8021X) {
7267 err = wldev_iovar_setbuf(dev, "okc_info_pmk", (const void *)params->key,
7268 WSEC_MAX_PSK_LEN / 2, keystring, sizeof(keystring), NULL);
7269 if (err) {
7270 /* could fail in case that 'okc' is not supported */
7271 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err));
7272 }
7273 }
7274 /* copy the raw hex key to the appropriate format */
7275 for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) {
7276 charptr += snprintf(charptr, sizeof(keystring), "%02x", params->key[j]);
7277 }
7278 len = (u16)strlen(keystring);
7279 pmk.key_len = htod16(len);
7280 bcopy(keystring, pmk.key, len);
7281 pmk.flags = htod16(WSEC_PASSPHRASE);
7282
7283 err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
7284 if (err)
7285 return err;
7286 /* Clear key length to delete key */
7287 key.len = 0;
7288 } break;
7289 #endif /* WLAN_CIPHER_SUITE_PMK */
7290 default:
7291 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7292 return -EINVAL;
7293 }
7294
7295 /* Set the new key/index */
7296 if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
7297 WL_ERR(("IBSS KEY setted\n"));
7298 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
7299 }
7300 swap_key_from_BE(&key);
7301 if ((params->cipher == WLAN_CIPHER_SUITE_WEP40) ||
7302 (params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
7303 /*
7304 * For AP role, since we are doing a wl down before bringing up AP,
7305 * the plumbed keys will be lost. So for AP once we bring up AP, we
7306 * need to plumb keys again. So buffer the keys for future use. This
7307 * is more like a WAR. If firmware later has the capability to do
7308 * interface upgrade without doing a "wl down" and "wl apsta 0", then
7309 * this will not be required.
7310 */
7311 WL_DBG(("Buffering WEP Keys \n"));
7312 memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key));
7313 }
7314 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7315 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7316 if (unlikely(err)) {
7317 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7318 return err;
7319 }
7320
7321 exit:
7322 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7323 if (unlikely(err)) {
7324 WL_ERR(("get wsec error (%d)\n", err));
7325 return err;
7326 }
7327
7328 wsec |= val;
7329 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
7330 if (unlikely(err)) {
7331 WL_ERR(("set wsec error (%d)\n", err));
7332 return err;
7333 }
7334
7335 return err;
7336 }
7337
7338 static s32
7339 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
7340 u8 key_idx, bool pairwise, const u8 *mac_addr)
7341 {
7342 struct wl_wsec_key key;
7343 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7344 s32 err = 0;
7345 s32 bssidx;
7346
7347 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7348 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7349 return BCME_ERROR;
7350 }
7351 WL_DBG(("Enter\n"));
7352
7353 #ifndef MFP
7354 if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
7355 return -EINVAL;
7356 #endif // endif
7357
7358 RETURN_EIO_IF_NOT_UP(cfg);
7359 memset(&key, 0, sizeof(key));
7360
7361 key.flags = WL_PRIMARY_KEY;
7362 key.algo = CRYPTO_ALGO_OFF;
7363 key.index = (u32) key_idx;
7364
7365 WL_DBG(("key index (%d)\n", key_idx));
7366 /* Set the new key/index */
7367 swap_key_from_BE(&key);
7368 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7369 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7370 if (unlikely(err)) {
7371 if (err == -EINVAL) {
7372 if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
7373 /* we ignore this key index in this case */
7374 WL_DBG(("invalid key index (%d)\n", key_idx));
7375 }
7376 } else {
7377 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7378 }
7379 return err;
7380 }
7381 return err;
7382 }
7383
7384 /* NOTE : this function cannot work as is and is never called */
7385 static s32
7386 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
7387 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
7388 void (*callback) (void *cookie, struct key_params * params))
7389 {
7390 struct key_params params;
7391 struct wl_wsec_key key;
7392 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7393 struct wl_security *sec;
7394 s32 wsec;
7395 s32 err = 0;
7396 s32 bssidx;
7397
7398 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7399 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7400 return BCME_ERROR;
7401 }
7402 WL_DBG(("key index (%d)\n", key_idx));
7403 RETURN_EIO_IF_NOT_UP(cfg);
7404 memset(&key, 0, sizeof(key));
7405 key.index = key_idx;
7406 swap_key_to_BE(&key);
7407 memset(&params, 0, sizeof(params));
7408 params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
7409 params.key = key.data;
7410
7411 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7412 if (unlikely(err)) {
7413 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7414 return err;
7415 }
7416 switch (WSEC_ENABLED(wsec)) {
7417 case WEP_ENABLED:
7418 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7419 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
7420 params.cipher = WLAN_CIPHER_SUITE_WEP40;
7421 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7422 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
7423 params.cipher = WLAN_CIPHER_SUITE_WEP104;
7424 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7425 }
7426 break;
7427 case TKIP_ENABLED:
7428 params.cipher = WLAN_CIPHER_SUITE_TKIP;
7429 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7430 break;
7431 case AES_ENABLED:
7432 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7433 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7434 break;
7435 #ifdef BCMWAPI_WPI
7436 case SMS4_ENABLED:
7437 params.cipher = WLAN_CIPHER_SUITE_SMS4;
7438 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7439 break;
7440 #endif // endif
7441 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
7442 /* to connect to mixed mode AP */
7443 case (AES_ENABLED | TKIP_ENABLED): /* TKIP CCMP */
7444 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7445 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7446 break;
7447 #endif // endif
7448 default:
7449 WL_ERR(("Invalid algo (0x%x)\n", wsec));
7450 return -EINVAL;
7451 }
7452
7453 callback(cookie, &params);
7454 return err;
7455 }
7456
7457 static s32
7458 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
7459 struct net_device *dev, u8 key_idx)
7460 {
7461 #ifdef MFP
7462 return 0;
7463 #else
7464 WL_INFORM_MEM(("Not supported\n"));
7465 return -EOPNOTSUPP;
7466 #endif /* MFP */
7467 }
7468
7469 static int
7470 wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data, uint16 type, uint16 len)
7471 {
7472 switch (type) {
7473 case WL_IFSTATS_XTLV_IF_INDEX:
7474 WL_DBG(("Stats received on interface index: %d\n", *data));
7475 break;
7476 case WL_IFSTATS_XTLV_GENERIC: {
7477 if (len > sizeof(wl_if_stats_t)) {
7478 WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n",
7479 type, len, (int)sizeof(wl_if_stats_t)));
7480 }
7481 memcpy(ctx, data, sizeof(wl_if_stats_t));
7482 break;
7483 }
7484 default:
7485 WL_DBG(("Unsupported counter type 0x%x\n", type));
7486 break;
7487 }
7488
7489 return BCME_OK;
7490 }
7491
7492 /* Parameters to if_counters iovar need to be converted to XTLV format
7493 * before sending to FW. The length of the top level XTLV container
7494 * containing parameters should not exceed 228 bytes
7495 */
7496 #define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228
7497
7498 int
7499 wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats)
7500 {
7501 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7502 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7503 uint8 *pbuf = NULL;
7504 bcm_xtlvbuf_t xtlvbuf, local_xtlvbuf;
7505 bcm_xtlv_t *xtlv;
7506 uint16 expected_resp_len;
7507 wl_stats_report_t *request = NULL, *response = NULL;
7508 int bsscfg_idx;
7509 int ret = BCME_OK;
7510
7511 pbuf = (uint8 *)MALLOCZ(dhdp->osh, WLC_IOCTL_MEDLEN);
7512 if (!pbuf) {
7513 WL_ERR(("Failed to allocate local pbuf\n"));
7514 return BCME_NOMEM;
7515 }
7516
7517 /* top level container length cannot exceed 228 bytes.
7518 * This is because the output buffer is 1535 bytes long.
7519 * Allow 1300 bytes for reporting stats coming in XTLV format
7520 */
7521 request = (wl_stats_report_t *)
7522 MALLOCZ(dhdp->osh, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7523 if (!request) {
7524 WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
7525 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX));
7526 ret = BCME_NOMEM;
7527 goto fail;
7528 }
7529
7530 request->version = WL_STATS_REPORT_REQUEST_VERSION_V2;
7531
7532 /* Top level container... we will create it ourselves */
7533 /* Leave space for report version, length, and top level XTLV
7534 * WL_IFSTATS_XTLV_IF.
7535 */
7536 ret = bcm_xtlv_buf_init(&local_xtlvbuf,
7537 (uint8*)(request->data) + BCM_XTLV_HDR_SIZE,
7538 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7539 offsetof(wl_stats_report_t, data) - BCM_XTLV_HDR_SIZE,
7540 BCM_XTLV_OPTION_ALIGN32);
7541
7542 if (ret) {
7543 goto fail;
7544 }
7545
7546 /* Populate requests using this the local_xtlvbuf context. The xtlvbuf
7547 * is used to fill the container containing the XTLVs populated using
7548 * local_xtlvbuf.
7549 */
7550 ret = bcm_xtlv_buf_init(&xtlvbuf,
7551 (uint8*)(request->data),
7552 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7553 offsetof(wl_stats_report_t, data),
7554 BCM_XTLV_OPTION_ALIGN32);
7555
7556 if (ret) {
7557 goto fail;
7558 }
7559
7560 /* Request generic stats */
7561 ret = bcm_xtlv_put_data(&local_xtlvbuf,
7562 WL_IFSTATS_XTLV_GENERIC, NULL, 0);
7563 if (ret) {
7564 goto fail;
7565 }
7566
7567 /* Complete the outer container with type and length
7568 * only.
7569 */
7570 ret = bcm_xtlv_put_data(&xtlvbuf,
7571 WL_IFSTATS_XTLV_IF,
7572 NULL, bcm_xtlv_buf_len(&local_xtlvbuf));
7573
7574 if (ret) {
7575 goto fail;
7576 }
7577
7578 request->length = bcm_xtlv_buf_len(&xtlvbuf) +
7579 offsetof(wl_stats_report_t, data);
7580 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
7581
7582 /* send the command over to the device and get teh output */
7583 ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request,
7584 request->length, pbuf, WLC_IOCTL_MEDLEN, bsscfg_idx,
7585 &cfg->ioctl_buf_sync);
7586 if (ret < 0) {
7587 WL_ERR(("if_counters not supported ret=%d\n", ret));
7588 goto fail;
7589 }
7590
7591 /* Reuse request to process response */
7592 response = (wl_stats_report_t *)pbuf;
7593
7594 /* version check */
7595 if (response->version != WL_STATS_REPORT_REQUEST_VERSION_V2) {
7596 ret = BCME_VERSION;
7597 goto fail;
7598 }
7599
7600 xtlv = (bcm_xtlv_t *)(response->data);
7601
7602 expected_resp_len =
7603 (BCM_XTLV_LEN(xtlv) + OFFSETOF(wl_stats_report_t, data));
7604
7605 /* Check if the received length is as expected */
7606 if ((response->length > WLC_IOCTL_MEDLEN) ||
7607 (response->length < expected_resp_len)) {
7608 ret = BCME_ERROR;
7609 WL_ERR(("Illegal response length received. Got: %d"
7610 " Expected: %d. Expected len must be <= %u\n",
7611 response->length, expected_resp_len, WLC_IOCTL_MEDLEN));
7612 goto fail;
7613 }
7614
7615 /* check the type. The return data will be in
7616 * WL_IFSTATS_XTLV_IF container. So check if that container is
7617 * present
7618 */
7619 if (BCM_XTLV_ID(xtlv) != WL_IFSTATS_XTLV_IF) {
7620 ret = BCME_ERROR;
7621 WL_ERR(("unexpected type received: %d Expected: %d\n",
7622 BCM_XTLV_ID(xtlv), WL_IFSTATS_XTLV_IF));
7623 goto fail;
7624 }
7625
7626 /* Process XTLVs within WL_IFSTATS_XTLV_IF container */
7627 ret = bcm_unpack_xtlv_buf(if_stats,
7628 (uint8*)response->data + BCM_XTLV_HDR_SIZE,
7629 BCM_XTLV_LEN(xtlv), /* total length of all TLVs in container */
7630 BCM_XTLV_OPTION_ALIGN32, wl_cfg80211_ifstats_counters_cb);
7631 if (ret) {
7632 WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret));
7633 }
7634
7635 fail:
7636 if (pbuf) {
7637 MFREE(dhdp->osh, pbuf, WLC_IOCTL_MEDLEN);
7638 }
7639
7640 if (request) {
7641 MFREE(dhdp->osh, request, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7642 }
7643 return ret;
7644 }
7645 #undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
7646
7647 static bool
7648 wl_check_assoc_state(struct bcm_cfg80211 *cfg, struct net_device *dev)
7649 {
7650 wl_assoc_info_t asinfo;
7651 uint32 state = 0;
7652 int err;
7653
7654 err = wldev_iovar_getbuf_bsscfg(dev, "assoc_info",
7655 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
7656 if (unlikely(err)) {
7657 WL_ERR(("failed to get assoc_info : err=%d\n", err));
7658 return FALSE;
7659 } else {
7660 memcpy(&asinfo, cfg->ioctl_buf, sizeof(wl_assoc_info_t));
7661 state = dtoh32(asinfo.state);
7662 WL_DBG(("assoc state=%d\n", state));
7663 }
7664
7665 return (state > 0)? TRUE:FALSE;
7666 }
7667
7668 static s32
7669 wl_cfg80211_get_rssi(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 *rssi)
7670 {
7671 s32 err = BCME_OK;
7672 scb_val_t scb_val;
7673 #ifdef SUPPORT_RSSI_SUM_REPORT
7674 wl_rssi_ant_mimo_t rssi_ant_mimo;
7675 #endif /* SUPPORT_RSSI_SUM_REPORT */
7676
7677 if (dev == NULL || cfg == NULL) {
7678 return BCME_ERROR;
7679 }
7680
7681 /* initialize rssi */
7682 *rssi = 0;
7683
7684 #ifdef SUPPORT_RSSI_SUM_REPORT
7685 /* Query RSSI sum across antennas */
7686 memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
7687 err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
7688 if (err) {
7689 WL_ERR(("Could not get rssi sum (%d)\n", err));
7690 /* set rssi to zero and do not return error,
7691 * because iovar phy_rssi_ant could return BCME_UNSUPPORTED
7692 * when bssid was null during roaming
7693 */
7694 err = BCME_OK;
7695 } else {
7696 cfg->rssi_sum_report = TRUE;
7697 if ((*rssi = rssi_ant_mimo.rssi_sum) >= 0) {
7698 *rssi = 0;
7699 }
7700 }
7701 #endif /* SUPPORT_RSSI_SUM_REPORT */
7702
7703 /* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore */
7704 if (cfg->rssi_sum_report == FALSE) {
7705 memset(&scb_val, 0, sizeof(scb_val));
7706 scb_val.val = 0;
7707 err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val,
7708 sizeof(scb_val_t));
7709 if (err) {
7710 WL_ERR(("Could not get rssi (%d)\n", err));
7711 return err;
7712 }
7713 *rssi = wl_rssi_offset(dtoh32(scb_val.val));
7714 }
7715
7716 if (*rssi >= 0) {
7717 /* check assoc status including roaming */
7718 DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub));
7719 if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_check_assoc_state(cfg, dev)) {
7720 *rssi = cfg->rssi; /* use previous RSSI */
7721 WL_DBG(("use previous RSSI %d dBm\n", cfg->rssi));
7722 } else {
7723 *rssi = 0;
7724 }
7725 DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
7726 } else {
7727 /* backup the current rssi */
7728 cfg->rssi = *rssi;
7729 }
7730
7731 return err;
7732 }
7733
7734 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
7735 static s32
7736 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7737 const u8 *mac, struct station_info *sinfo)
7738 #else
7739 static s32
7740 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7741 u8 *mac, struct station_info *sinfo)
7742 #endif // endif
7743 {
7744 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7745 s32 rssi = 0;
7746 s32 rate;
7747 s32 err = 0;
7748 sta_info_v4_t *sta;
7749 s32 mode;
7750 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
7751 s8 eabuf[ETHER_ADDR_STR_LEN];
7752 #endif // endif
7753 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
7754 bool fw_assoc_state = FALSE;
7755 u32 dhd_assoc_state = 0;
7756 void *buf;
7757 RETURN_EIO_IF_NOT_UP(cfg);
7758
7759 mode = wl_get_mode_by_netdev(cfg, dev);
7760 if (mode < 0) {
7761 return -ENODEV;
7762 }
7763
7764 buf = MALLOC(cfg->osh, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
7765 if (buf == NULL) {
7766 WL_ERR(("%s(%d): MALLOC failed\n", __FUNCTION__, __LINE__));
7767 goto error;
7768 }
7769 if (mode == WL_MODE_AP) {
7770 err = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac,
7771 ETHER_ADDR_LEN, buf, WLC_IOCTL_SMLEN, NULL);
7772 if (err < 0) {
7773 WL_ERR(("GET STA INFO failed, %d\n", err));
7774 goto error;
7775 }
7776 sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
7777 sta = (sta_info_v4_t *)buf;
7778 if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
7779 WL_ERR(("GET STA INFO version mismatch, %d\n", err));
7780 return BCME_VERSION;
7781 }
7782 sta->len = dtoh16(sta->len);
7783 sta->cap = dtoh16(sta->cap);
7784 sta->flags = dtoh32(sta->flags);
7785 sta->idle = dtoh32(sta->idle);
7786 sta->in = dtoh32(sta->in);
7787 sinfo->inactive_time = sta->idle * 1000;
7788 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
7789 if (sta->flags & WL_STA_ASSOC) {
7790 sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
7791 sinfo->connected_time = sta->in;
7792 }
7793 WL_INFORM_MEM(("[%s] STA %s : idle time : %d sec, connected time :%d ms\n",
7794 dev->name, bcm_ether_ntoa((const struct ether_addr *)mac, eabuf),
7795 sinfo->inactive_time, sta->idle * 1000));
7796 #endif // endif
7797 } else if ((mode == WL_MODE_BSS) || (mode == WL_MODE_IBSS)) {
7798 get_pktcnt_t pktcnt;
7799 wl_if_stats_t *if_stats = NULL;
7800 u8 *curmacp;
7801
7802 if (cfg->roam_offload) {
7803 struct ether_addr bssid;
7804 memset(&bssid, 0, sizeof(bssid));
7805 err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
7806 if (err) {
7807 WL_ERR(("Failed to get current BSSID\n"));
7808 } else {
7809 if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
7810 /* roaming is detected */
7811 err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
7812 if (err)
7813 WL_ERR(("Failed to handle the delayed roam, "
7814 "err=%d", err));
7815 mac = (u8 *)bssid.octet;
7816 }
7817 }
7818 }
7819 dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
7820 DHD_OS_WAKE_LOCK(dhd);
7821 fw_assoc_state = dhd_is_associated(dhd, 0, &err);
7822 if (dhd_assoc_state && !fw_assoc_state) {
7823 /* check roam (join) status */
7824 if (wl_check_assoc_state(cfg, dev)) {
7825 fw_assoc_state = TRUE;
7826 WL_DBG(("roam status\n"));
7827 }
7828 }
7829 DHD_OS_WAKE_UNLOCK(dhd);
7830 if (!dhd_assoc_state || !fw_assoc_state) {
7831 WL_ERR(("NOT assoc\n"));
7832 if (err == -ENODATA)
7833 goto error;
7834 if (!dhd_assoc_state) {
7835 WL_TRACE_HW4(("drv state is not connected \n"));
7836 }
7837 if (!fw_assoc_state) {
7838 WL_TRACE_HW4(("fw state is not associated \n"));
7839 }
7840 /* Disconnect due to fw is not associated for FW_ASSOC_WATCHDOG_TIME ms.
7841 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
7842 * means that BSSID is null.
7843 */
7844 if (dhd_assoc_state && !fw_assoc_state && !err) {
7845 if (!fw_assoc_watchdog_started) {
7846 fw_assoc_watchdog_ms = OSL_SYSUPTIME();
7847 fw_assoc_watchdog_started = TRUE;
7848 WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
7849 } else {
7850 if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
7851 FW_ASSOC_WATCHDOG_TIME) {
7852 fw_assoc_watchdog_started = FALSE;
7853 err = -ENODEV;
7854 WL_TRACE_HW4(("fw is not associated for %d ms \n",
7855 (OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
7856 goto get_station_err;
7857 }
7858 }
7859 }
7860 err = -ENODEV;
7861 goto error;
7862 }
7863 if (dhd_is_associated(dhd, 0, NULL)) {
7864 fw_assoc_watchdog_started = FALSE;
7865 }
7866 curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
7867 if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
7868 WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
7869 MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
7870 }
7871
7872 /* Report the current tx rate */
7873 rate = 0;
7874 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
7875 if (err) {
7876 WL_ERR(("Could not get rate (%d)\n", err));
7877 } else {
7878 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7879 int rxpktglom;
7880 #endif // endif
7881 rate = dtoh32(rate);
7882 sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
7883 sinfo->txrate.legacy = rate * 5;
7884 WL_DBG(("Rate %d Mbps\n", (rate / 2)));
7885 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7886 rxpktglom = ((rate/2) > 150) ? 20 : 10;
7887
7888 if (maxrxpktglom != rxpktglom) {
7889 maxrxpktglom = rxpktglom;
7890 WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2),
7891 maxrxpktglom));
7892 err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
7893 (char*)&maxrxpktglom, 4, cfg->ioctl_buf,
7894 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
7895 if (err < 0) {
7896 WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
7897 }
7898 }
7899 #endif // endif
7900 }
7901
7902 if ((err = wl_cfg80211_get_rssi(dev, cfg, &rssi)) != BCME_OK) {
7903 goto get_station_err;
7904 }
7905 sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
7906 sinfo->signal = rssi;
7907 WL_DBG(("RSSI %d dBm\n", rssi));
7908
7909 if_stats = (wl_if_stats_t *)buf;
7910 memset(if_stats, 0, sizeof(*if_stats));
7911
7912 if (FW_SUPPORTED(dhd, ifst)) {
7913 err = wl_cfg80211_ifstats_counters(dev, if_stats);
7914 } else
7915 {
7916 err = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
7917 (char *)if_stats, sizeof(*if_stats), NULL);
7918 }
7919
7920 if (err) {
7921 WL_ERR(("if_counters not supported ret=%d\n", err));
7922 memset(&pktcnt, 0, sizeof(pktcnt));
7923 err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt,
7924 sizeof(pktcnt));
7925 if (!err) {
7926 sinfo->rx_packets = pktcnt.rx_good_pkt;
7927 sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
7928 sinfo->tx_packets = pktcnt.tx_good_pkt;
7929 sinfo->tx_failed = pktcnt.tx_bad_pkt;
7930 }
7931 } else {
7932 sinfo->rx_packets = (uint32)dtoh64(if_stats->rxframe);
7933 sinfo->rx_dropped_misc = 0;
7934 sinfo->tx_packets = (uint32)dtoh64(if_stats->txfrmsnt);
7935 sinfo->tx_failed = (uint32)dtoh64(if_stats->txnobuf) +
7936 (uint32)dtoh64(if_stats->txrunt) +
7937 (uint32)dtoh64(if_stats->txfail);
7938 }
7939
7940 sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
7941 STA_INFO_BIT(INFO_RX_DROP_MISC) |
7942 STA_INFO_BIT(INFO_TX_PACKETS) |
7943 STA_INFO_BIT(INFO_TX_FAILED));
7944
7945 get_station_err:
7946 if (err && (err != -ENODATA)) {
7947 /* Disconnect due to zero BSSID or error to get RSSI */
7948 scb_val_t scbval;
7949 scbval.val = htod32(DOT11_RC_DISASSOC_LEAVING);
7950 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
7951 if (unlikely(err)) {
7952 WL_ERR(("disassoc error (%d)\n", err));
7953 }
7954
7955 WL_ERR(("force cfg80211_disconnected: %d\n", err));
7956 wl_clr_drv_status(cfg, CONNECTED, dev);
7957 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
7958 wl_link_down(cfg);
7959 }
7960 }
7961 else {
7962 WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
7963 }
7964 error:
7965 if (buf) {
7966 MFREE(cfg->osh, buf, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
7967 }
7968 return err;
7969 }
7970
7971 static s32
7972 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
7973 bool enabled, s32 timeout)
7974 {
7975 s32 pm;
7976 s32 err = 0;
7977 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7978 struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
7979 s32 mode;
7980 #ifdef RTT_SUPPORT
7981 dhd_pub_t *dhd = cfg->pub;
7982 rtt_status_info_t *rtt_status;
7983 #endif /* RTT_SUPPORT */
7984 RETURN_EIO_IF_NOT_UP(cfg);
7985
7986 WL_DBG(("Enter\n"));
7987 mode = wl_get_mode_by_netdev(cfg, dev);
7988 if (cfg->p2p_net == dev || _net_info == NULL ||
7989 !wl_get_drv_status(cfg, CONNECTED, dev) ||
7990 ((mode != WL_MODE_BSS) &&
7991 (mode != WL_MODE_IBSS))) {
7992 return err;
7993 }
7994
7995 /* Enlarge pm_enable_work */
7996 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
7997
7998 pm = enabled ? PM_FAST : PM_OFF;
7999 if (_net_info->pm_block) {
8000 WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
8001 dev->name, _net_info->pm_block));
8002 pm = PM_OFF;
8003 }
8004 pm = htod32(pm);
8005 WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
8006 #ifdef RTT_SUPPORT
8007 rtt_status = GET_RTTSTATE(dhd);
8008 if (rtt_status->status != RTT_ENABLED) {
8009 #endif /* RTT_SUPPORT */
8010 err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
8011 if (unlikely(err)) {
8012 if (err == -ENODEV)
8013 WL_DBG(("net_device is not ready yet\n"));
8014 else
8015 WL_ERR(("error (%d)\n", err));
8016 return err;
8017 }
8018 #ifdef RTT_SUPPORT
8019 }
8020 #endif /* RTT_SUPPORT */
8021 wl_cfg80211_update_power_mode(dev);
8022 return err;
8023 }
8024
8025 void wl_cfg80211_update_power_mode(struct net_device *dev)
8026 {
8027 int err, pm = -1;
8028
8029 err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
8030 if (err)
8031 WL_ERR(("%s:error (%d)\n", __FUNCTION__, err));
8032 else if (pm != -1 && dev->ieee80211_ptr)
8033 dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
8034 }
8035
8036 void wl_cfg80211_set_passive_scan(struct net_device *dev, char *command)
8037 {
8038 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8039
8040 if (strcmp(command, "SCAN-ACTIVE") == 0) {
8041 cfg->active_scan = 1;
8042 } else if (strcmp(command, "SCAN-PASSIVE") == 0) {
8043 cfg->active_scan = 0;
8044 } else
8045 WL_ERR(("Unknown command \n"));
8046 return;
8047 }
8048
8049 static __used u32 wl_find_msb(u16 bit16)
8050 {
8051 u32 ret = 0;
8052
8053 if (bit16 & 0xff00) {
8054 ret += 8;
8055 bit16 >>= 8;
8056 }
8057
8058 if (bit16 & 0xf0) {
8059 ret += 4;
8060 bit16 >>= 4;
8061 }
8062
8063 if (bit16 & 0xc) {
8064 ret += 2;
8065 bit16 >>= 2;
8066 }
8067
8068 if (bit16 & 2)
8069 ret += bit16 & 2;
8070 else if (bit16)
8071 ret += bit16;
8072
8073 return ret;
8074 }
8075
8076 static s32 wl_cfg80211_resume(struct wiphy *wiphy)
8077 {
8078 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8079 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8080 s32 err = BCME_OK;
8081
8082 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8083 WL_INFORM_MEM(("device is not ready\n"));
8084 return err;
8085 }
8086
8087 return err;
8088 }
8089
8090 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
8091 static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
8092 #else
8093 static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
8094 #endif // endif
8095 {
8096 s32 err = BCME_OK;
8097 #ifdef DHD_CLEAR_ON_SUSPEND
8098 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8099 struct net_info *iter, *next;
8100 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8101 unsigned long flags;
8102 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8103 WL_INFORM_MEM(("device is not ready : status (%d)\n",
8104 (int)cfg->status));
8105 return err;
8106 }
8107 for_each_ndev(cfg, iter, next) {
8108 /* p2p discovery iface doesn't have a ndev associated with it (for kernel > 3.8) */
8109 if (iter->ndev)
8110 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8111 }
8112 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
8113 if (cfg->scan_request) {
8114 cfg80211_scan_done(cfg->scan_request, true);
8115 cfg->scan_request = NULL;
8116 }
8117 for_each_ndev(cfg, iter, next) {
8118 if (iter->ndev) {
8119 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
8120 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8121 }
8122 }
8123 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
8124 for_each_ndev(cfg, iter, next) {
8125 if (iter->ndev) {
8126 if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
8127 wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false);
8128 }
8129 }
8130 }
8131 #endif /* DHD_CLEAR_ON_SUSPEND */
8132
8133 return err;
8134 }
8135
8136 static s32
8137 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
8138 s32 err)
8139 {
8140 int i, j;
8141 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8142 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
8143
8144 if (!pmk_list) {
8145 WL_INFORM_MEM(("pmk_list is NULL\n"));
8146 return -EINVAL;
8147 }
8148 /* pmk list is supported only for STA interface i.e. primary interface
8149 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
8150 */
8151 if (primary_dev != dev) {
8152 WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
8153 " interfaces than primary interface\n"));
8154 return err;
8155 }
8156
8157 WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
8158 for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
8159 WL_DBG(("PMKID[%d]: %pM =\n", i,
8160 &pmk_list->pmkids.pmkid[i].BSSID));
8161 for (j = 0; j < WPA2_PMKID_LEN; j++) {
8162 WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]));
8163 }
8164 }
8165 if (likely(!err)) {
8166 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8167 sizeof(*pmk_list), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8168 }
8169
8170 return err;
8171 }
8172
8173 static s32
8174 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
8175 struct cfg80211_pmksa *pmksa)
8176 {
8177 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8178 s32 err = 0;
8179 int i;
8180
8181 RETURN_EIO_IF_NOT_UP(cfg);
8182 for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
8183 if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
8184 ETHER_ADDR_LEN))
8185 break;
8186 if (i < WL_NUM_PMKIDS_MAX) {
8187 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid,
8188 ETHER_ADDR_LEN);
8189 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid,
8190 WPA2_PMKID_LEN);
8191 if (i == cfg->pmk_list->pmkids.npmkid)
8192 cfg->pmk_list->pmkids.npmkid++;
8193 } else {
8194 err = -EINVAL;
8195 }
8196 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
8197 &cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].BSSID));
8198 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8199 WL_DBG(("%02x\n",
8200 cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].
8201 PMKID[i]));
8202 }
8203
8204 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8205
8206 return err;
8207 }
8208
8209 static s32
8210 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
8211 struct cfg80211_pmksa *pmksa)
8212 {
8213 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8214
8215 pmkid_list_t pmkid = {.npmkid = 0};
8216 s32 err = 0;
8217 int i;
8218
8219 RETURN_EIO_IF_NOT_UP(cfg);
8220 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
8221 memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
8222
8223 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
8224 &pmkid.pmkid[0].BSSID));
8225 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8226 WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i]));
8227 }
8228
8229 for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
8230 if (!memcmp
8231 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
8232 ETHER_ADDR_LEN))
8233 break;
8234
8235 if ((cfg->pmk_list->pmkids.npmkid > 0) &&
8236 (i < cfg->pmk_list->pmkids.npmkid)) {
8237 memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t));
8238 for (; i < (cfg->pmk_list->pmkids.npmkid - 1); i++) {
8239 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
8240 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
8241 ETHER_ADDR_LEN);
8242 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
8243 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
8244 WPA2_PMKID_LEN);
8245 }
8246 cfg->pmk_list->pmkids.npmkid--;
8247 } else {
8248 err = -EINVAL;
8249 }
8250
8251 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8252
8253 return err;
8254
8255 }
8256
8257 static s32
8258 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
8259 {
8260 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8261 s32 err = 0;
8262 RETURN_EIO_IF_NOT_UP(cfg);
8263 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
8264 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8265 return err;
8266 }
8267
8268 static wl_scan_params_t *
8269 wl_cfg80211_scan_alloc_params(struct bcm_cfg80211 *cfg, int channel, int nprobes,
8270 int *out_params_size)
8271 {
8272 wl_scan_params_t *params;
8273 int params_size;
8274 int num_chans;
8275
8276 *out_params_size = 0;
8277
8278 /* Our scan params only need space for 1 channel and 0 ssids */
8279 params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16);
8280 params = (wl_scan_params_t *)MALLOCZ(cfg->osh, params_size);
8281 if (params == NULL) {
8282 WL_ERR(("mem alloc failed (%d bytes)\n", params_size));
8283 return params;
8284 }
8285 memset(params, 0, params_size);
8286 params->nprobes = nprobes;
8287
8288 num_chans = (channel == 0) ? 0 : 1;
8289
8290 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
8291 params->bss_type = DOT11_BSSTYPE_ANY;
8292 params->scan_type = DOT11_SCANTYPE_ACTIVE;
8293 params->nprobes = htod32(1);
8294 params->active_time = htod32(-1);
8295 params->passive_time = htod32(-1);
8296 params->home_time = htod32(10);
8297 if (channel == -1)
8298 params->channel_list[0] = htodchanspec(channel);
8299 else
8300 params->channel_list[0] = wl_ch_host_to_driver(channel);
8301
8302 /* Our scan params have 1 channel and 0 ssids */
8303 params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
8304 (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
8305
8306 *out_params_size = params_size; /* rtn size to the caller */
8307 return params;
8308 }
8309
8310 #if defined(WL_CFG80211_P2P_DEV_IF)
8311 static s32
8312 wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
8313 struct ieee80211_channel *channel, unsigned int duration, u64 *cookie)
8314 #else
8315 static s32
8316 wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
8317 struct ieee80211_channel * channel,
8318 enum nl80211_channel_type channel_type,
8319 unsigned int duration, u64 *cookie)
8320 #endif /* WL_CFG80211_P2P_DEV_IF */
8321 {
8322 s32 target_channel;
8323 u32 id;
8324 s32 err = BCME_OK;
8325 struct ether_addr primary_mac;
8326 struct net_device *ndev = NULL;
8327 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8328
8329 RETURN_EIO_IF_NOT_UP(cfg);
8330 #ifdef DHD_IFDEBUG
8331 PRINT_WDEV_INFO(cfgdev);
8332 #endif /* DHD_IFDEBUG */
8333
8334 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
8335
8336 #ifdef WL_NAN
8337 if (wl_cfgnan_check_state(cfg)) {
8338 WL_ERR(("nan is enabled, nan + p2p concurrency not supported\n"));
8339 return BCME_UNSUPPORTED;
8340 }
8341 #endif /* WL_NAN */
8342
8343 mutex_lock(&cfg->usr_sync);
8344 WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
8345 ieee80211_frequency_to_channel(channel->center_freq),
8346 duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO"));
8347
8348 if (!cfg->p2p) {
8349 WL_ERR(("cfg->p2p is not initialized\n"));
8350 err = BCME_ERROR;
8351 goto exit;
8352 }
8353
8354 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8355 if (wl_get_drv_status_all(cfg, SCANNING)) {
8356 wl_cfg80211_cancel_scan(cfg);
8357 }
8358 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8359
8360 #ifdef P2P_LISTEN_OFFLOADING
8361 wl_cfg80211_cancel_p2plo(cfg);
8362 #endif /* P2P_LISTEN_OFFLOADING */
8363
8364 target_channel = ieee80211_frequency_to_channel(channel->center_freq);
8365 memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel));
8366 #if defined(WL_ENABLE_P2P_IF)
8367 cfg->remain_on_chan_type = channel_type;
8368 #endif /* WL_ENABLE_P2P_IF */
8369 id = ++cfg->last_roc_id;
8370 if (id == 0)
8371 id = ++cfg->last_roc_id;
8372 *cookie = id;
8373
8374 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8375 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
8376 struct timer_list *_timer;
8377 WL_DBG(("scan is running. go to fake listen state\n"));
8378
8379 if (duration > LONG_LISTEN_TIME) {
8380 wl_cfg80211_scan_abort(cfg);
8381 } else {
8382 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8383
8384 if (timer_pending(&cfg->p2p->listen_timer)) {
8385 WL_DBG(("cancel current listen timer \n"));
8386 del_timer_sync(&cfg->p2p->listen_timer);
8387 }
8388
8389 _timer = &cfg->p2p->listen_timer;
8390 wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
8391
8392 INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0);
8393
8394 err = BCME_OK;
8395 goto exit;
8396 }
8397 }
8398 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8399
8400 #ifdef WL_BCNRECV
8401 /* check fakeapscan in progress then abort */
8402 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_LISTENBUSY);
8403 #endif /* WL_BCNRECV */
8404 #ifdef WL_CFG80211_SYNC_GON
8405 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
8406 /* do not enter listen mode again if we are in listen mode already for next af.
8407 * remain on channel completion will be returned by waiting next af completion.
8408 */
8409 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8410 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8411 #else
8412 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8413 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8414 goto exit;
8415 }
8416 #endif /* WL_CFG80211_SYNC_GON */
8417 if (cfg->p2p && !cfg->p2p->on) {
8418 /* In case of p2p_listen command, supplicant send remain_on_channel
8419 * without turning on P2P
8420 */
8421 get_primary_mac(cfg, &primary_mac);
8422 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
8423 p2p_on(cfg) = true;
8424 }
8425
8426 if (p2p_is_on(cfg)) {
8427 err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
8428 if (unlikely(err)) {
8429 goto exit;
8430 }
8431 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8432 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8433 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8434 err = wl_cfgp2p_discover_listen(cfg, target_channel, duration);
8435
8436 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8437 if (err == BCME_OK) {
8438 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8439 } else {
8440 /* if failed, firmware may be internal scanning state.
8441 * so other scan request shall not abort it
8442 */
8443 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8444 }
8445 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8446
8447 if (err) {
8448 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
8449 }
8450
8451 /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant
8452 * and expire timer will send a completion to the upper layer
8453 */
8454 err = BCME_OK;
8455 }
8456
8457 exit:
8458 if (err == BCME_OK) {
8459 WL_DBG(("Success\n"));
8460 #if defined(WL_CFG80211_P2P_DEV_IF)
8461 cfg80211_ready_on_channel(cfgdev, *cookie, channel,
8462 duration, GFP_KERNEL);
8463 #else
8464 cfg80211_ready_on_channel(cfgdev, *cookie, channel,
8465 channel_type, duration, GFP_KERNEL);
8466 #endif /* WL_CFG80211_P2P_DEV_IF */
8467 } else {
8468 WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie));
8469 }
8470 mutex_unlock(&cfg->usr_sync);
8471 return err;
8472 }
8473
8474 static s32
8475 wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
8476 bcm_struct_cfgdev *cfgdev, u64 cookie)
8477 {
8478 s32 err = 0;
8479
8480 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8481
8482 #ifdef P2PLISTEN_AP_SAMECHN
8483 struct net_device *dev;
8484 #endif /* P2PLISTEN_AP_SAMECHN */
8485
8486 RETURN_EIO_IF_NOT_UP(cfg);
8487
8488 #ifdef DHD_IFDEBUG
8489 PRINT_WDEV_INFO(cfgdev);
8490 #endif /* DHD_IFDEBUG */
8491
8492 #if defined(WL_CFG80211_P2P_DEV_IF)
8493 if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
8494 WL_DBG((" enter ) on P2P dedicated discover interface\n"));
8495 }
8496 #else
8497 WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex));
8498 #endif /* WL_CFG80211_P2P_DEV_IF */
8499
8500 #ifdef P2PLISTEN_AP_SAMECHN
8501 if (cfg && cfg->p2p_resp_apchn_status) {
8502 dev = bcmcfg_to_prmry_ndev(cfg);
8503 wl_cfg80211_set_p2p_resp_ap_chn(dev, 0);
8504 cfg->p2p_resp_apchn_status = false;
8505 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
8506 }
8507 #endif /* P2PLISTEN_AP_SAMECHN */
8508
8509 if (cfg->last_roc_id == cookie) {
8510 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
8511 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
8512 } else {
8513 WL_ERR(("%s : ignore, request cookie(%llu) is not matched. (cur : %llu)\n",
8514 __FUNCTION__, cookie, cfg->last_roc_id));
8515 }
8516
8517 return err;
8518 }
8519
8520 static void
8521 wl_cfg80211_afx_handler(struct work_struct *work)
8522 {
8523 struct afx_hdl *afx_instance;
8524 struct bcm_cfg80211 *cfg;
8525 s32 ret = BCME_OK;
8526
8527 BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
8528 if (afx_instance) {
8529 cfg = wl_get_cfg(afx_instance->dev);
8530 if (cfg != NULL && cfg->afx_hdl->is_active) {
8531 if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
8532 ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
8533 (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
8534 } else {
8535 ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
8536 cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
8537 NULL);
8538 }
8539 if (unlikely(ret != BCME_OK)) {
8540 WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
8541 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
8542 complete(&cfg->act_frm_scan);
8543 }
8544 }
8545 }
8546 }
8547
8548 static s32
8549 wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
8550 {
8551 u32 max_retry = WL_CHANNEL_SYNC_RETRY;
8552 bool is_p2p_gas = false;
8553
8554 if (dev == NULL)
8555 return -1;
8556
8557 WL_DBG((" enter ) \n"));
8558
8559 wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8560 cfg->afx_hdl->is_active = TRUE;
8561
8562 if (cfg->afx_hdl->pending_tx_act_frm) {
8563 wl_action_frame_t *action_frame;
8564 action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
8565 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len))
8566 is_p2p_gas = true;
8567 }
8568
8569 /* Loop to wait until we find a peer's channel or the
8570 * pending action frame tx is cancelled.
8571 */
8572 while ((cfg->afx_hdl->retry < max_retry) &&
8573 (cfg->afx_hdl->peer_chan == WL_INVALID)) {
8574 cfg->afx_hdl->is_listen = FALSE;
8575 wl_set_drv_status(cfg, SCANNING, dev);
8576 WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
8577 cfg->afx_hdl->retry));
8578 /* search peer on peer's listen channel */
8579 schedule_work(&cfg->afx_hdl->work);
8580 wait_for_completion_timeout(&cfg->act_frm_scan,
8581 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8582
8583 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8584 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8585 break;
8586
8587 if (is_p2p_gas)
8588 break;
8589
8590 if (cfg->afx_hdl->my_listen_chan) {
8591 WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
8592 cfg->afx_hdl->my_listen_chan));
8593 /* listen on my listen channel */
8594 cfg->afx_hdl->is_listen = TRUE;
8595 schedule_work(&cfg->afx_hdl->work);
8596 wait_for_completion_timeout(&cfg->act_frm_scan,
8597 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8598 }
8599 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8600 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8601 break;
8602
8603 cfg->afx_hdl->retry++;
8604
8605 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
8606 }
8607
8608 cfg->afx_hdl->is_active = FALSE;
8609
8610 wl_clr_drv_status(cfg, SCANNING, dev);
8611 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8612
8613 return (cfg->afx_hdl->peer_chan);
8614 }
8615
8616 struct p2p_config_af_params {
8617 s32 max_tx_retry; /* max tx retry count if tx no ack */
8618 #ifdef WL_CFG80211_GON_COLLISION
8619 /* drop tx go nego request if go nego collision occurs */
8620 bool drop_tx_req;
8621 #endif // endif
8622 #ifdef WL_CFG80211_SYNC_GON
8623 bool extra_listen;
8624 #endif // endif
8625 bool search_channel; /* 1: search peer's channel to send af */
8626 };
8627
8628 static s32
8629 wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
8630 wl_action_frame_t *action_frame, wl_af_params_t *af_params,
8631 struct p2p_config_af_params *config_af_params)
8632 {
8633 s32 err = BCME_OK;
8634 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8635 wifi_p2p_pub_act_frame_t *act_frm =
8636 (wifi_p2p_pub_act_frame_t *) (action_frame->data);
8637
8638 /* initialize default value */
8639 #ifdef WL_CFG80211_GON_COLLISION
8640 config_af_params->drop_tx_req = false;
8641 #endif // endif
8642 #ifdef WL_CFG80211_SYNC_GON
8643 config_af_params->extra_listen = true;
8644 #endif // endif
8645 config_af_params->search_channel = false;
8646 config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
8647 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
8648
8649 switch (act_frm->subtype) {
8650 case P2P_PAF_GON_REQ: {
8651 WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
8652 wl_set_p2p_status(cfg, GO_NEG_PHASE);
8653
8654 config_af_params->search_channel = true;
8655 cfg->next_af_subtype = act_frm->subtype + 1;
8656
8657 /* increase dwell time to wait for RESP frame */
8658 af_params->dwell_time = WL_MED_DWELL_TIME;
8659
8660 #ifdef WL_CFG80211_GON_COLLISION
8661 config_af_params->drop_tx_req = true;
8662 #endif /* WL_CFG80211_GON_COLLISION */
8663 break;
8664 }
8665 case P2P_PAF_GON_RSP: {
8666 cfg->next_af_subtype = act_frm->subtype + 1;
8667 /* increase dwell time to wait for CONF frame */
8668 af_params->dwell_time = WL_MED_DWELL_TIME + 100;
8669 break;
8670 }
8671 case P2P_PAF_GON_CONF: {
8672 /* If we reached till GO Neg confirmation reset the filter */
8673 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
8674 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
8675
8676 /* minimize dwell time */
8677 af_params->dwell_time = WL_MIN_DWELL_TIME;
8678
8679 #ifdef WL_CFG80211_GON_COLLISION
8680 /* if go nego formation done, clear it */
8681 cfg->block_gon_req_tx_count = 0;
8682 cfg->block_gon_req_rx_count = 0;
8683 #endif /* WL_CFG80211_GON_COLLISION */
8684 #ifdef WL_CFG80211_SYNC_GON
8685 config_af_params->extra_listen = false;
8686 #endif /* WL_CFG80211_SYNC_GON */
8687 break;
8688 }
8689 case P2P_PAF_INVITE_REQ: {
8690 config_af_params->search_channel = true;
8691 cfg->next_af_subtype = act_frm->subtype + 1;
8692
8693 /* increase dwell time */
8694 af_params->dwell_time = WL_MED_DWELL_TIME;
8695 break;
8696 }
8697 case P2P_PAF_INVITE_RSP:
8698 /* minimize dwell time */
8699 af_params->dwell_time = WL_MIN_DWELL_TIME;
8700 #ifdef WL_CFG80211_SYNC_GON
8701 config_af_params->extra_listen = false;
8702 #endif /* WL_CFG80211_SYNC_GON */
8703 break;
8704 case P2P_PAF_DEVDIS_REQ: {
8705 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
8706 action_frame->len)) {
8707 config_af_params->search_channel = true;
8708 }
8709
8710 cfg->next_af_subtype = act_frm->subtype + 1;
8711 /* maximize dwell time to wait for RESP frame */
8712 af_params->dwell_time = WL_LONG_DWELL_TIME;
8713 break;
8714 }
8715 case P2P_PAF_DEVDIS_RSP:
8716 /* minimize dwell time */
8717 af_params->dwell_time = WL_MIN_DWELL_TIME;
8718 #ifdef WL_CFG80211_SYNC_GON
8719 config_af_params->extra_listen = false;
8720 #endif /* WL_CFG80211_SYNC_GON */
8721 break;
8722 case P2P_PAF_PROVDIS_REQ: {
8723 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
8724 action_frame->len)) {
8725 config_af_params->search_channel = true;
8726 }
8727
8728 cfg->next_af_subtype = act_frm->subtype + 1;
8729 /* increase dwell time to wait for RESP frame */
8730 af_params->dwell_time = WL_MED_DWELL_TIME;
8731 break;
8732 }
8733 case P2P_PAF_PROVDIS_RSP: {
8734 cfg->next_af_subtype = P2P_PAF_GON_REQ;
8735 af_params->dwell_time = WL_MED_DWELL_TIME;
8736 #ifdef WL_CFG80211_SYNC_GON
8737 config_af_params->extra_listen = false;
8738 #endif /* WL_CFG80211_SYNC_GON */
8739 break;
8740 }
8741 default:
8742 WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
8743 act_frm->subtype));
8744 err = BCME_BADARG;
8745 }
8746 return err;
8747 }
8748
8749 #ifdef WL11U
8750 static bool
8751 wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params,
8752 void *frame, u16 frame_len)
8753 {
8754 struct wl_scan_results *bss_list;
8755 wl_bss_info_t *bi = NULL;
8756 bool result = false;
8757 s32 i;
8758 chanspec_t chanspec;
8759
8760 /* If DFS channel is 52~148, check to block it or not */
8761 if (af_params &&
8762 (af_params->channel >= 52 && af_params->channel <= 148)) {
8763 if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
8764 bss_list = cfg->bss_list;
8765 bi = next_bss(bss_list, bi);
8766 for_each_bss(bss_list, bi, i) {
8767 chanspec = wl_chspec_driver_to_host(bi->chanspec);
8768 if (CHSPEC_IS5G(chanspec) &&
8769 ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec))
8770 == af_params->channel)) {
8771 result = true; /* do not block the action frame */
8772 break;
8773 }
8774 }
8775 }
8776 }
8777 else {
8778 result = true;
8779 }
8780
8781 WL_DBG(("result=%s", result?"true":"false"));
8782 return result;
8783 }
8784 #endif /* WL11U */
8785 static bool
8786 wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies)
8787 {
8788 if ((requested_dwell & CUSTOM_RETRY_MASK) &&
8789 (jiffies_to_msecs(jiffies - dwell_jiffies) >
8790 (requested_dwell & ~CUSTOM_RETRY_MASK))) {
8791 WL_ERR(("Action frame TX retry time over dwell time!\n"));
8792 return true;
8793 }
8794 return false;
8795 }
8796
8797 static bool
8798 wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
8799 bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
8800 wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
8801 {
8802 #ifdef WL11U
8803 struct net_device *ndev = NULL;
8804 #endif /* WL11U */
8805 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8806 bool ack = false;
8807 u8 category, action;
8808 s32 tx_retry;
8809 struct p2p_config_af_params config_af_params;
8810 struct net_info *netinfo;
8811 #ifdef VSDB
8812 ulong off_chan_started_jiffies = 0;
8813 #endif // endif
8814 ulong dwell_jiffies = 0;
8815 bool dwell_overflow = false;
8816 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
8817
8818 int32 requested_dwell = af_params->dwell_time;
8819
8820 /* Add the default dwell time
8821 * Dwell time to stay off-channel to wait for a response action frame
8822 * after transmitting an GO Negotiation action frame
8823 */
8824 af_params->dwell_time = WL_DWELL_TIME;
8825
8826 #ifdef WL11U
8827 #if defined(WL_CFG80211_P2P_DEV_IF)
8828 ndev = dev;
8829 #else
8830 ndev = ndev_to_cfgdev(cfgdev);
8831 #endif /* WL_CFG80211_P2P_DEV_IF */
8832 #endif /* WL11U */
8833
8834 category = action_frame->data[DOT11_ACTION_CAT_OFF];
8835 action = action_frame->data[DOT11_ACTION_ACT_OFF];
8836
8837 /* initialize variables */
8838 tx_retry = 0;
8839 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
8840 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
8841 config_af_params.search_channel = false;
8842 #ifdef WL_CFG80211_GON_COLLISION
8843 config_af_params.drop_tx_req = false;
8844 #endif // endif
8845 #ifdef WL_CFG80211_SYNC_GON
8846 config_af_params.extra_listen = false;
8847 #endif // endif
8848
8849 /* config parameters */
8850 /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
8851 if (category == DOT11_ACTION_CAT_PUBLIC) {
8852 if ((action == P2P_PUB_AF_ACTION) &&
8853 (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
8854 /* p2p public action frame process */
8855 if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy,
8856 action_frame, af_params, &config_af_params)) {
8857 WL_DBG(("Unknown subtype.\n"));
8858 }
8859
8860 #ifdef WL_CFG80211_GON_COLLISION
8861 if (config_af_params.drop_tx_req) {
8862 if (cfg->block_gon_req_tx_count) {
8863 /* drop gon req tx action frame */
8864 WL_DBG(("Drop gon req tx action frame: count %d\n",
8865 cfg->block_gon_req_tx_count));
8866 goto exit;
8867 }
8868 }
8869 #endif /* WL_CFG80211_GON_COLLISION */
8870 } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
8871 /* service discovery process */
8872 if (action == P2PSD_ACTION_ID_GAS_IREQ ||
8873 action == P2PSD_ACTION_ID_GAS_CREQ) {
8874 /* configure service discovery query frame */
8875
8876 config_af_params.search_channel = true;
8877
8878 /* save next af suptype to cancel remained dwell time */
8879 cfg->next_af_subtype = action + 1;
8880
8881 af_params->dwell_time = WL_MED_DWELL_TIME;
8882 if (requested_dwell & CUSTOM_RETRY_MASK) {
8883 config_af_params.max_tx_retry =
8884 (requested_dwell & CUSTOM_RETRY_MASK) >> 24;
8885 af_params->dwell_time =
8886 (requested_dwell & ~CUSTOM_RETRY_MASK);
8887 WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
8888 config_af_params.max_tx_retry,
8889 af_params->dwell_time));
8890 }
8891 } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
8892 action == P2PSD_ACTION_ID_GAS_CRESP) {
8893 /* configure service discovery response frame */
8894 af_params->dwell_time = WL_MIN_DWELL_TIME;
8895 } else {
8896 WL_DBG(("Unknown action type: %d\n", action));
8897 }
8898 } else {
8899 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
8900 category, action, action_frame_len));
8901 }
8902 } else if (category == P2P_AF_CATEGORY) {
8903 /* do not configure anything. it will be sent with a default configuration */
8904 } else {
8905 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
8906 category, action));
8907 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
8908 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
8909 return false;
8910 }
8911 }
8912
8913 netinfo = wl_get_netinfo_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
8914 /* validate channel and p2p ies */
8915 if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) &&
8916 netinfo && netinfo->bss.ies.probe_req_ie_len) {
8917 config_af_params.search_channel = true;
8918 } else {
8919 config_af_params.search_channel = false;
8920 }
8921 #ifdef WL11U
8922 if (ndev == bcmcfg_to_prmry_ndev(cfg))
8923 config_af_params.search_channel = false;
8924 #endif /* WL11U */
8925
8926 #ifdef VSDB
8927 /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
8928 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
8929 OSL_SLEEP(50);
8930 }
8931 #endif // endif
8932
8933 /* if scan is ongoing, abort current scan. */
8934 if (wl_get_drv_status_all(cfg, SCANNING)) {
8935 wl_cfg80211_cancel_scan(cfg);
8936 }
8937
8938 /* Abort P2P listen */
8939 if (discover_cfgdev(cfgdev, cfg)) {
8940 if (cfg->p2p_supported && cfg->p2p) {
8941 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
8942 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
8943 }
8944 }
8945
8946 #ifdef WL11U
8947 /* handling DFS channel exceptions */
8948 if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) {
8949 return false; /* the action frame was blocked */
8950 }
8951 #endif /* WL11U */
8952
8953 /* set status and destination address before sending af */
8954 if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
8955 /* set this status to cancel the remained dwell time in rx process */
8956 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
8957 }
8958 wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
8959 memcpy(cfg->afx_hdl->tx_dst_addr.octet,
8960 af_params->action_frame.da.octet,
8961 sizeof(cfg->afx_hdl->tx_dst_addr.octet));
8962
8963 /* save af_params for rx process */
8964 cfg->afx_hdl->pending_tx_act_frm = af_params;
8965
8966 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
8967 WL_DBG(("Set GAS action frame config.\n"));
8968 config_af_params.search_channel = false;
8969 config_af_params.max_tx_retry = 1;
8970 }
8971
8972 /* search peer's channel */
8973 if (config_af_params.search_channel) {
8974 /* initialize afx_hdl */
8975 if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
8976 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
8977 goto exit;
8978 }
8979 cfg->afx_hdl->dev = dev;
8980 cfg->afx_hdl->retry = 0;
8981 cfg->afx_hdl->peer_chan = WL_INVALID;
8982
8983 if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
8984 WL_ERR(("couldn't find peer's channel.\n"));
8985 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
8986 af_params->channel);
8987 /* Even if we couldn't find peer channel, try to send the frame
8988 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
8989 * respond to probe request (Ideally it has to be in listen and
8990 * responsd to probe request). However if we send Go neg req, the
8991 * peer is sending GO-neg resp. So instead of giving up here, just
8992 * proceed and attempt sending out the action frame.
8993 */
8994 }
8995
8996 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
8997 /*
8998 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
8999 * but after the check of piggyback algorithm.
9000 * To take care of current piggback algo, lets abort the scan here itself.
9001 */
9002 wl_cfg80211_cancel_scan(cfg);
9003 /* Suspend P2P discovery's search-listen to prevent it from
9004 * starting a scan or changing the channel.
9005 */
9006 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9007 WL_ERR(("Can not disable discovery mode\n"));
9008 goto exit;
9009 }
9010
9011 /* update channel */
9012 if (cfg->afx_hdl->peer_chan != WL_INVALID) {
9013 af_params->channel = cfg->afx_hdl->peer_chan;
9014 WL_ERR(("Attempt tx on peer listen channel:%d ",
9015 cfg->afx_hdl->peer_chan));
9016 } else {
9017 WL_ERR(("Attempt tx with the channel provided by userspace."
9018 "Channel: %d\n", af_params->channel));
9019 }
9020 }
9021
9022 #ifdef VSDB
9023 off_chan_started_jiffies = jiffies;
9024 #endif /* VSDB */
9025
9026 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel);
9027
9028 wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
9029
9030 dwell_jiffies = jiffies;
9031 /* Now send a tx action frame */
9032 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
9033 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9034
9035 /* if failed, retry it. tx_retry_max value is configure by .... */
9036 while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry) &&
9037 !dwell_overflow) {
9038 #ifdef VSDB
9039 if (af_params->channel) {
9040 if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
9041 OFF_CHAN_TIME_THRESHOLD_MS) {
9042 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
9043 off_chan_started_jiffies = jiffies;
9044 } else
9045 OSL_SLEEP(AF_RETRY_DELAY_TIME);
9046 }
9047 #endif /* VSDB */
9048 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
9049 false : true;
9050 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9051 }
9052
9053 if (ack == false) {
9054 WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
9055 }
9056 WL_DBG(("Complete to send action frame\n"));
9057 exit:
9058 /* Clear SENDING_ACT_FRM after all sending af is done */
9059 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9060
9061 #ifdef WL_CFG80211_SYNC_GON
9062 /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
9063 * if we coundn't get the next action response frame and dongle does not keep
9064 * the dwell time, go to listen state again to get next action response frame.
9065 */
9066 if (ack && config_af_params.extra_listen &&
9067 #ifdef WL_CFG80211_GON_COLLISION
9068 !cfg->block_gon_req_tx_count &&
9069 #endif /* WL_CFG80211_GON_COLLISION */
9070 wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
9071 cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
9072 s32 extar_listen_time;
9073
9074 extar_listen_time = af_params->dwell_time -
9075 jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
9076
9077 if (extar_listen_time > 50) {
9078 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9079 WL_DBG(("Wait more time! actual af time:%d,"
9080 "calculated extar listen:%d\n",
9081 af_params->dwell_time, extar_listen_time));
9082 if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
9083 extar_listen_time + 100) == BCME_OK) {
9084 wait_for_completion_timeout(&cfg->wait_next_af,
9085 msecs_to_jiffies(extar_listen_time + 100 + 300));
9086 }
9087 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9088 }
9089 }
9090 #endif /* WL_CFG80211_SYNC_GON */
9091 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9092
9093 cfg->afx_hdl->pending_tx_act_frm = NULL;
9094
9095 if (ack) {
9096 WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
9097 cfg->afx_hdl->my_listen_chan));
9098 } else {
9099 WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
9100 cfg->afx_hdl->my_listen_chan));
9101 }
9102
9103 #ifdef WL_CFG80211_GON_COLLISION
9104 if (cfg->block_gon_req_tx_count) {
9105 cfg->block_gon_req_tx_count--;
9106 /* if ack is ture, supplicant will wait more time(100ms).
9107 * so we will return it as a success to get more time .
9108 */
9109 ack = true;
9110 }
9111 #endif /* WL_CFG80211_GON_COLLISION */
9112 return ack;
9113 }
9114
9115 #define MAX_NUM_OF_ASSOCIATED_DEV 64
9116 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9117 static s32
9118 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9119 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
9120 #else
9121 static s32
9122 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9123 struct ieee80211_channel *channel, bool offchan,
9124 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
9125 enum nl80211_channel_type channel_type,
9126 bool channel_type_valid,
9127 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
9128 unsigned int wait, const u8* buf, size_t len,
9129 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
9130 bool no_cck,
9131 #endif // endif
9132 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
9133 bool dont_wait_for_ack,
9134 #endif // endif
9135 u64 *cookie)
9136 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9137 {
9138 wl_action_frame_t *action_frame;
9139 wl_af_params_t *af_params;
9140 scb_val_t scb_val;
9141 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9142 struct ieee80211_channel *channel = params->chan;
9143 const u8 *buf = params->buf;
9144 size_t len = params->len;
9145 #endif // endif
9146 const struct ieee80211_mgmt *mgmt;
9147 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9148 struct net_device *dev = NULL;
9149 s32 err = BCME_OK;
9150 s32 bssidx = 0;
9151 u32 id;
9152 bool ack = false;
9153 s8 eabuf[ETHER_ADDR_STR_LEN];
9154
9155 WL_DBG(("Enter \n"));
9156
9157 if (len > ACTION_FRAME_SIZE) {
9158 WL_ERR(("bad length:%zu\n", len));
9159 return BCME_BADLEN;
9160 }
9161 #ifdef DHD_IFDEBUG
9162 PRINT_WDEV_INFO(cfgdev);
9163 #endif /* DHD_IFDEBUG */
9164
9165 dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
9166
9167 if (!dev) {
9168 WL_ERR(("dev is NULL\n"));
9169 return -EINVAL;
9170 }
9171
9172 /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
9173 if (discover_cfgdev(cfgdev, cfg)) {
9174 if (!cfg->p2p_supported || !cfg->p2p) {
9175 WL_ERR(("P2P doesn't setup completed yet\n"));
9176 return -EINVAL;
9177 }
9178 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9179 }
9180 else {
9181 if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
9182 WL_ERR(("Find p2p index failed\n"));
9183 return BCME_ERROR;
9184 }
9185 }
9186
9187 WL_DBG(("TX target bssidx=%d\n", bssidx));
9188
9189 if (p2p_is_on(cfg)) {
9190 /* Suspend P2P discovery search-listen to prevent it from changing the
9191 * channel.
9192 */
9193 if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9194 WL_ERR(("Can not disable discovery mode\n"));
9195 return -EFAULT;
9196 }
9197 }
9198 *cookie = 0;
9199 id = cfg->send_action_id++;
9200 if (id == 0)
9201 id = cfg->send_action_id++;
9202 *cookie = id;
9203 mgmt = (const struct ieee80211_mgmt *)buf;
9204 if (ieee80211_is_mgmt(mgmt->frame_control)) {
9205 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
9206 s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
9207 s32 ie_len = len - ie_offset;
9208 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9209 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9210 }
9211 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
9212 VNDR_IE_PRBRSP_FLAG, (const u8 *)(buf + ie_offset), ie_len);
9213 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9214 #if defined(P2P_IE_MISSING_FIX)
9215 if (!cfg->p2p_prb_noti) {
9216 cfg->p2p_prb_noti = true;
9217 WL_DBG(("%s: TX 802_1X Probe Response first time.\n",
9218 __FUNCTION__));
9219 }
9220 #endif // endif
9221 goto exit;
9222 } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
9223 ieee80211_is_deauth(mgmt->frame_control)) {
9224 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
9225 sizeof(struct ether_addr) + sizeof(uint)] = {0};
9226 int num_associated = 0;
9227 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9228 if (!bcmp((const uint8 *)BSSID_BROADCAST,
9229 (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
9230 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9231 err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST,
9232 assoc_maclist, sizeof(mac_buf));
9233 if (err < 0)
9234 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9235 else
9236 num_associated = assoc_maclist->count;
9237 }
9238 memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
9239 scb_val.val = mgmt->u.disassoc.reason_code;
9240 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
9241 sizeof(scb_val_t));
9242 if (err < 0)
9243 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
9244 WL_ERR(("Disconnect STA : " MACDBG " scb_val.val %d\n",
9245 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mgmt->da,
9246 eabuf)), scb_val.val));
9247
9248 if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
9249 wl_delay(400);
9250
9251 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9252 goto exit;
9253
9254 } else if (ieee80211_is_action(mgmt->frame_control)) {
9255 /* Abort the dwell time of any previous off-channel
9256 * action frame that may be still in effect. Sending
9257 * off-channel action frames relies on the driver's
9258 * scan engine. If a previous off-channel action frame
9259 * tx is still in progress (including the dwell time),
9260 * then this new action frame will not be sent out.
9261 */
9262 /* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
9263 * And previous off-channel action frame must be ended before new af tx.
9264 */
9265 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9266 wl_cfg80211_cancel_scan(cfg);
9267 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9268 }
9269
9270 } else {
9271 WL_ERR(("Driver only allows MGMT packet type\n"));
9272 goto exit;
9273 }
9274
9275 af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
9276
9277 if (af_params == NULL)
9278 {
9279 WL_ERR(("unable to allocate frame\n"));
9280 return -ENOMEM;
9281 }
9282
9283 action_frame = &af_params->action_frame;
9284
9285 /* Add the packet Id */
9286 action_frame->packetId = *cookie;
9287 WL_DBG(("action frame %d\n", action_frame->packetId));
9288 /* Add BSSID */
9289 memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
9290 memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
9291
9292 /* Add the length exepted for 802.11 header */
9293 action_frame->len = len - DOT11_MGMT_HDR_LEN;
9294 WL_DBG(("action_frame->len: %d\n", action_frame->len));
9295
9296 /* Add the channel */
9297 af_params->channel =
9298 ieee80211_frequency_to_channel(channel->center_freq);
9299 /* Save listen_chan for searching common channel */
9300 cfg->afx_hdl->peer_listen_chan = af_params->channel;
9301 WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
9302
9303 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9304 af_params->dwell_time = params->wait;
9305 #else
9306 af_params->dwell_time = wait;
9307 #endif // endif
9308
9309 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
9310
9311 ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params,
9312 action_frame, action_frame->len, bssidx);
9313 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9314
9315 MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
9316 exit:
9317 return err;
9318 }
9319
9320 static void
9321 wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9322 u16 frame, bool reg)
9323 {
9324
9325 WL_DBG(("frame_type: %x, reg: %d\n", frame, reg));
9326
9327 if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
9328 return;
9329
9330 return;
9331 }
9332
9333 static s32
9334 wl_cfg80211_change_bss(struct wiphy *wiphy,
9335 struct net_device *dev,
9336 struct bss_parameters *params)
9337 {
9338 s32 err = 0;
9339 s32 ap_isolate = 0;
9340 #ifdef PCIE_FULL_DONGLE
9341 s32 ifidx = DHD_BAD_IF;
9342 #endif // endif
9343 #if defined(PCIE_FULL_DONGLE)
9344 dhd_pub_t *dhd;
9345 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9346 dhd = (dhd_pub_t *)(cfg->pub);
9347 #if defined(WL_ENABLE_P2P_IF)
9348 if (cfg->p2p_net == dev)
9349 dev = bcmcfg_to_prmry_ndev(cfg);
9350 #endif // endif
9351 #endif // endif
9352
9353 if (params->use_cts_prot >= 0) {
9354 }
9355
9356 if (params->use_short_preamble >= 0) {
9357 }
9358
9359 if (params->use_short_slot_time >= 0) {
9360 }
9361
9362 if (params->basic_rates) {
9363 }
9364
9365 if (params->ap_isolate >= 0) {
9366 ap_isolate = params->ap_isolate;
9367 #ifdef PCIE_FULL_DONGLE
9368 ifidx = dhd_net2idx(dhd->info, dev);
9369
9370 if (ifidx != DHD_BAD_IF) {
9371 err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate);
9372 } else {
9373 WL_ERR(("Failed to set ap_isolate\n"));
9374 }
9375 #else
9376 err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
9377 if (unlikely(err))
9378 {
9379 WL_ERR(("set ap_isolate Error (%d)\n", err));
9380 }
9381 #endif /* PCIE_FULL_DONGLE */
9382 }
9383
9384 if (params->ht_opmode >= 0) {
9385 }
9386
9387 return err;
9388 }
9389
9390 static s32
9391 wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
9392 struct ieee80211_channel *chan,
9393 enum nl80211_channel_type channel_type)
9394 {
9395 s32 _chan;
9396 u32 _band;
9397 chanspec_t chspec = 0;
9398 chanspec_t fw_chspec = 0;
9399 u32 bw = WL_CHANSPEC_BW_20;
9400
9401 s32 err = BCME_OK;
9402 s32 bw_cap = 0;
9403 struct {
9404 u32 band;
9405 u32 bw_cap;
9406 } param = {0, 0};
9407 u8 ioctl_buf[WLC_IOCTL_SMLEN];
9408 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9409 #if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL)
9410 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
9411 #endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
9412 #if defined(WL_VIRTUAL_APSTA) && defined(APSTA_RESTRICTED_CHANNEL)
9413 struct net_device *prmry_ndev = bcmcfg_to_prmry_ndev(cfg);
9414 #endif /* WL_VIRTUAL_APSTA && APSTA_RESTRICTED_CHANNEL */
9415
9416 dev = ndev_to_wlc_ndev(dev, cfg);
9417 _chan = ieee80211_frequency_to_channel(chan->center_freq);
9418 _band = chan->band;
9419 WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
9420 dev->ifindex, channel_type, _chan));
9421
9422 #ifdef NOT_YET
9423 switch (channel_type) {
9424 case NL80211_CHAN_HT40MINUS:
9425 /* secondary channel is below the control channel */
9426 chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_UPPER);
9427 break;
9428 case NL80211_CHAN_HT40PLUS:
9429 /* secondary channel is above the control channel */
9430 chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_LOWER);
9431 break;
9432 default:
9433 chspec = CH20MHZ_CHSPEC(channel);
9434
9435 }
9436 #endif /* NOT_YET */
9437
9438 #if defined(APSTA_RESTRICTED_CHANNEL)
9439 #define DEFAULT_2G_SOFTAP_CHANNEL 1
9440 #define DEFAULT_5G_SOFTAP_CHANNEL 149
9441 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
9442 DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
9443 wl_get_drv_status(cfg, CONNECTED, prmry_ndev)) {
9444 u32 *sta_chan = (u32 *)wl_read_prof(cfg,
9445 prmry_ndev, WL_PROF_CHAN);
9446
9447 #ifdef WL_RESTRICTED_APSTA_SCC
9448 _chan = *sta_chan;
9449
9450 /* Check if current channel is restricted */
9451 if (wl_cfg80211_check_indoor_channels(prmry_ndev, _chan)) {
9452 wl_cfg80211_disassoc(prmry_ndev);
9453 WL_ERR(("Force to disconnect existing AP as "
9454 "channel %d is indoor channel\n", _chan));
9455
9456 /* Set channel to default 2.4GHz channel */
9457 _chan = DEFAULT_2G_SOFTAP_CHANNEL;
9458 }
9459 #else
9460 u32 sta_band = (*sta_chan > CH_MAX_2G_CHANNEL) ?
9461 NL80211_BAND_5GHZ : NL80211_BAND_2GHZ;
9462 if (chan->band == sta_band) {
9463 _chan = (sta_band == NL80211_BAND_5GHZ &&
9464 *sta_chan != DEFAULT_5G_SOFTAP_CHANNEL) ?
9465 DEFAULT_2G_SOFTAP_CHANNEL : *sta_chan;
9466 }
9467 #endif /* WL_RESTRICTED_APSTA_SCC */
9468 _band = (_chan <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
9469 WL_ERR(("Target SoftAP channel will be set to %d\n", _chan));
9470 }
9471 #undef DEFAULT_2G_SOFTAP_CHANNEL
9472 #undef DEFAULT_5G_SOFTAP_CHANNEL
9473 #endif /* APSTA_RESTRICTED_CHANNEL */
9474
9475 if (_band == NL80211_BAND_5GHZ) {
9476 param.band = WLC_BAND_5G;
9477 err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
9478 ioctl_buf, sizeof(ioctl_buf), NULL);
9479 if (err) {
9480 if (err != BCME_UNSUPPORTED) {
9481 WL_ERR(("bw_cap failed, %d\n", err));
9482 return err;
9483 } else {
9484 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
9485 if (err) {
9486 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
9487 }
9488 if (bw_cap != WLC_N_BW_20ALL)
9489 bw = WL_CHANSPEC_BW_40;
9490 }
9491 } else {
9492 if (WL_BW_CAP_80MHZ(ioctl_buf[0]))
9493 bw = WL_CHANSPEC_BW_80;
9494 else if (WL_BW_CAP_40MHZ(ioctl_buf[0]))
9495 bw = WL_CHANSPEC_BW_40;
9496 else
9497 bw = WL_CHANSPEC_BW_20;
9498
9499 }
9500
9501 } else if (_band == NL80211_BAND_2GHZ)
9502 bw = WL_CHANSPEC_BW_20;
9503 set_channel:
9504 chspec = wf_channel2chspec(_chan, bw);
9505 if (wf_chspec_valid(chspec)) {
9506 fw_chspec = wl_chspec_host_to_driver(chspec);
9507 if (fw_chspec != INVCHANSPEC) {
9508 if ((err = wldev_iovar_setint(dev, "chanspec",
9509 fw_chspec)) == BCME_BADCHAN) {
9510 if (bw == WL_CHANSPEC_BW_80)
9511 goto change_bw;
9512 err = wldev_ioctl_set(dev, WLC_SET_CHANNEL,
9513 &_chan, sizeof(_chan));
9514 if (err < 0) {
9515 WL_ERR(("WLC_SET_CHANNEL error %d"
9516 "chip may not be supporting this channel\n", err));
9517 }
9518 } else if (err) {
9519 WL_ERR(("failed to set chanspec error %d\n", err));
9520 }
9521 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
9522 else {
9523 /* Disable Frameburst only for stand-alone 2GHz SoftAP */
9524 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
9525 DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
9526 (_chan <= CH_MAX_2G_CHANNEL) &&
9527 !wl_get_drv_status(cfg, CONNECTED,
9528 bcmcfg_to_prmry_ndev(cfg))) {
9529 WL_DBG(("Disabling frameburst on "
9530 "stand-alone 2GHz SoftAP\n"));
9531 wl_cfg80211_set_frameburst(cfg, FALSE);
9532 }
9533 }
9534 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
9535 } else {
9536 WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
9537 err = BCME_ERROR;
9538 }
9539 } else {
9540 change_bw:
9541 if (bw == WL_CHANSPEC_BW_80)
9542 bw = WL_CHANSPEC_BW_40;
9543 else if (bw == WL_CHANSPEC_BW_40)
9544 bw = WL_CHANSPEC_BW_20;
9545 else
9546 bw = 0;
9547 if (bw)
9548 goto set_channel;
9549 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
9550 err = BCME_ERROR;
9551 }
9552 #ifdef CUSTOM_SET_CPUCORE
9553 if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
9554 WL_DBG(("SoftAP mode do not need to set cpucore\n"));
9555 } else if (chspec & WL_CHANSPEC_BW_80) {
9556 /* SoftAp only mode do not need to set cpucore */
9557 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
9558 dev != bcmcfg_to_prmry_ndev(cfg)) {
9559 /* Soft AP on virtual Iface (AP+STA case) */
9560 dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
9561 dhd_set_cpucore(dhd, TRUE);
9562 } else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
9563 /* If P2P IF is vht80 */
9564 dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
9565 dhd_set_cpucore(dhd, TRUE);
9566 }
9567 }
9568 #endif /* CUSTOM_SET_CPUCORE */
9569 if (!err && (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
9570 /* Update AP/GO operating channel */
9571 cfg->ap_oper_channel = ieee80211_frequency_to_channel(chan->center_freq);
9572 }
9573 if (err) {
9574 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
9575 FW_LOGSET_MASK_ALL);
9576 }
9577 return err;
9578 }
9579
9580 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9581 struct net_device *
9582 wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
9583 {
9584 struct net_info *_net_info, *next;
9585 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
9586 #pragma GCC diagnostic push
9587 #pragma GCC diagnostic ignored "-Wcast-qual"
9588 #endif // endif
9589 list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
9590 if (_net_info->ndev &&
9591 test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
9592 return _net_info->ndev;
9593 }
9594 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
9595 #pragma GCC diagnostic pop
9596 #endif // endif
9597 return NULL;
9598 }
9599 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9600
9601 static s32
9602 wl_validate_opensecurity(struct net_device *dev, s32 bssidx, bool privacy)
9603 {
9604 s32 err = BCME_OK;
9605 u32 wpa_val;
9606 s32 wsec = 0;
9607
9608 /* set auth */
9609 err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
9610 if (err < 0) {
9611 WL_ERR(("auth error %d\n", err));
9612 return BCME_ERROR;
9613 }
9614
9615 if (privacy) {
9616 /* If privacy bit is set in open mode, then WEP would be enabled */
9617 wsec = WEP_ENABLED;
9618 WL_DBG(("Setting wsec to %d for WEP \n", wsec));
9619 }
9620
9621 /* set wsec */
9622 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
9623 if (err < 0) {
9624 WL_ERR(("wsec error %d\n", err));
9625 return BCME_ERROR;
9626 }
9627
9628 /* set upper-layer auth */
9629 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC)
9630 wpa_val = WPA_AUTH_NONE;
9631 else
9632 wpa_val = WPA_AUTH_DISABLED;
9633 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_val, bssidx);
9634 if (err < 0) {
9635 WL_ERR(("wpa_auth error %d\n", err));
9636 return BCME_ERROR;
9637 }
9638
9639 return 0;
9640 }
9641
9642 static s32
9643 wl_validate_fils_ind_ie(struct net_device *dev, const bcm_tlv_t *filsindie, s32 bssidx)
9644 {
9645 s32 err = BCME_OK;
9646 struct bcm_cfg80211 *cfg = NULL;
9647
9648 if (!dev || !filsindie) {
9649 WL_ERR(("%s: dev/filsidie is null\n", __FUNCTION__));
9650 return BCME_ERROR;
9651 }
9652
9653 cfg = wl_get_cfg(dev);
9654 if (!cfg) {
9655 WL_ERR(("%s: cfg is null\n", __FUNCTION__));
9656 return BCME_ERROR;
9657 }
9658
9659 err = wldev_iovar_setbuf_bsscfg(dev, "fils_ind", (const void *)filsindie->data,
9660 filsindie->len, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
9661 bssidx, &cfg->ioctl_buf_sync);
9662 if (err < 0) {
9663 WL_ERR(("FILS Ind setting error %d\n", err));
9664 }
9665
9666 return err;
9667 }
9668
9669 static s32
9670 wl_validate_wpa2ie(struct net_device *dev, const bcm_tlv_t *wpa2ie, s32 bssidx)
9671 {
9672 s32 len = 0;
9673 s32 err = BCME_OK;
9674 u16 auth = 0; /* d11 open authentication */
9675 u32 wsec;
9676 u32 pval = 0;
9677 u32 gval = 0;
9678 u32 wpa_auth = 0;
9679 const wpa_suite_mcast_t *mcast;
9680 const wpa_suite_ucast_t *ucast;
9681 const wpa_suite_auth_key_mgmt_t *mgmt;
9682 const wpa_pmkid_list_t *pmkid;
9683 int cnt = 0;
9684 #ifdef MFP
9685 int mfp = 0;
9686 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
9687 #endif /* MFP */
9688
9689 u16 suite_count;
9690 u8 rsn_cap[2];
9691 u32 wme_bss_disable;
9692
9693 if (wpa2ie == NULL)
9694 goto exit;
9695
9696 WL_DBG(("Enter \n"));
9697 len = wpa2ie->len - WPA2_VERSION_LEN;
9698 /* check the mcast cipher */
9699 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
9700 switch (mcast->type) {
9701 case WPA_CIPHER_NONE:
9702 gval = 0;
9703 break;
9704 case WPA_CIPHER_WEP_40:
9705 case WPA_CIPHER_WEP_104:
9706 gval = WEP_ENABLED;
9707 break;
9708 case WPA_CIPHER_TKIP:
9709 gval = TKIP_ENABLED;
9710 break;
9711 case WPA_CIPHER_AES_CCM:
9712 gval = AES_ENABLED;
9713 break;
9714 #ifdef BCMWAPI_WPI
9715 case WAPI_CIPHER_SMS4:
9716 gval = SMS4_ENABLED;
9717 break;
9718 #endif // endif
9719 default:
9720 WL_ERR(("No Security Info\n"));
9721 break;
9722 }
9723 if ((len -= WPA_SUITE_LEN) <= 0)
9724 return BCME_BADLEN;
9725
9726 /* check the unicast cipher */
9727 ucast = (const wpa_suite_ucast_t *)&mcast[1];
9728 suite_count = ltoh16_ua(&ucast->count);
9729 switch (ucast->list[0].type) {
9730 case WPA_CIPHER_NONE:
9731 pval = 0;
9732 break;
9733 case WPA_CIPHER_WEP_40:
9734 case WPA_CIPHER_WEP_104:
9735 pval = WEP_ENABLED;
9736 break;
9737 case WPA_CIPHER_TKIP:
9738 pval = TKIP_ENABLED;
9739 break;
9740 case WPA_CIPHER_AES_CCM:
9741 pval = AES_ENABLED;
9742 break;
9743 #ifdef BCMWAPI_WPI
9744 case WAPI_CIPHER_SMS4:
9745 pval = SMS4_ENABLED;
9746 break;
9747 #endif // endif
9748 default:
9749 WL_ERR(("No Security Info\n"));
9750 }
9751 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
9752 return BCME_BADLEN;
9753
9754 /* FOR WPS , set SEC_OW_ENABLED */
9755 wsec = (pval | gval | SES_OW_ENABLED);
9756 /* check the AKM */
9757 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
9758 suite_count = cnt = ltoh16_ua(&mgmt->count);
9759 while (cnt--) {
9760 switch (mgmt->list[cnt].type) {
9761 case RSN_AKM_NONE:
9762 wpa_auth |= WPA_AUTH_NONE;
9763 break;
9764 case RSN_AKM_UNSPECIFIED:
9765 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
9766 break;
9767 case RSN_AKM_PSK:
9768 wpa_auth |= WPA2_AUTH_PSK;
9769 break;
9770 #ifdef MFP
9771 case RSN_AKM_MFP_PSK:
9772 wpa_auth |= WPA2_AUTH_PSK_SHA256;
9773 break;
9774 case RSN_AKM_MFP_1X:
9775 wpa_auth |= WPA2_AUTH_1X_SHA256;
9776 break;
9777 case RSN_AKM_FILS_SHA256:
9778 wpa_auth |= WPA2_AUTH_FILS_SHA256;
9779 break;
9780 case RSN_AKM_FILS_SHA384:
9781 wpa_auth |= WPA2_AUTH_FILS_SHA384;
9782 break;
9783 #endif /* MFP */
9784 default:
9785 WL_ERR(("No Key Mgmt Info\n"));
9786 }
9787 }
9788
9789 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
9790 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
9791 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
9792
9793 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
9794 wme_bss_disable = 0;
9795 } else {
9796 wme_bss_disable = 1;
9797 }
9798
9799 #ifdef MFP
9800 if (rsn_cap[0] & RSN_CAP_MFPR) {
9801 WL_DBG(("MFP Required \n"));
9802 mfp = WL_MFP_REQUIRED;
9803 /* Our firmware has requirement that WPA2_AUTH_PSK/WPA2_AUTH_UNSPECIFIED
9804 * be set, if SHA256 OUI is to be included in the rsn ie.
9805 */
9806 if (wpa_auth & WPA2_AUTH_PSK_SHA256) {
9807 wpa_auth |= WPA2_AUTH_PSK;
9808 } else if (wpa_auth & WPA2_AUTH_1X_SHA256) {
9809 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
9810 }
9811 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
9812 WL_DBG(("MFP Capable \n"));
9813 mfp = WL_MFP_CAPABLE;
9814 }
9815 #endif /* MFP */
9816
9817 /* set wme_bss_disable to sync RSN Capabilities */
9818 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
9819 if (err < 0) {
9820 WL_ERR(("wme_bss_disable error %d\n", err));
9821 return BCME_ERROR;
9822 }
9823 } else {
9824 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
9825 }
9826
9827 len -= RSN_CAP_LEN;
9828 if (len >= WPA2_PMKID_COUNT_LEN) {
9829 pmkid = (const wpa_pmkid_list_t *)
9830 ((const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
9831 cnt = ltoh16_ua(&pmkid->count);
9832 if (cnt != 0) {
9833 WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
9834 return BCME_ERROR;
9835 }
9836 /* since PMKID cnt is known to be 0 for AP, */
9837 /* so don't bother to send down this info to firmware */
9838 }
9839
9840 #ifdef MFP
9841 len -= WPA2_PMKID_COUNT_LEN;
9842 if (len >= WPA_SUITE_LEN) {
9843 cfg->bip_pos =
9844 (const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN;
9845 } else {
9846 cfg->bip_pos = NULL;
9847 }
9848 #endif // endif
9849
9850 /* set auth */
9851 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
9852 if (err < 0) {
9853 WL_ERR(("auth error %d\n", err));
9854 return BCME_ERROR;
9855 }
9856
9857 /* set wsec */
9858 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
9859 if (err < 0) {
9860 WL_ERR(("wsec error %d\n", err));
9861 return BCME_ERROR;
9862 }
9863
9864 #ifdef MFP
9865 cfg->mfp_mode = mfp;
9866 #endif /* MFP */
9867
9868 /* set upper-layer auth */
9869 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
9870 if (err < 0) {
9871 WL_ERR(("wpa_auth error %d\n", err));
9872 return BCME_ERROR;
9873 }
9874 exit:
9875 return 0;
9876 }
9877
9878 static s32
9879 wl_validate_wpaie(struct net_device *dev, const wpa_ie_fixed_t *wpaie, s32 bssidx)
9880 {
9881 const wpa_suite_mcast_t *mcast;
9882 const wpa_suite_ucast_t *ucast;
9883 const wpa_suite_auth_key_mgmt_t *mgmt;
9884 u16 auth = 0; /* d11 open authentication */
9885 u16 count;
9886 s32 err = BCME_OK;
9887 s32 len = 0;
9888 u32 i;
9889 u32 wsec;
9890 u32 pval = 0;
9891 u32 gval = 0;
9892 u32 wpa_auth = 0;
9893 u32 tmp = 0;
9894
9895 if (wpaie == NULL)
9896 goto exit;
9897 WL_DBG(("Enter \n"));
9898 len = wpaie->length; /* value length */
9899 len -= WPA_IE_TAG_FIXED_LEN;
9900 /* check for multicast cipher suite */
9901 if (len < WPA_SUITE_LEN) {
9902 WL_INFORM_MEM(("no multicast cipher suite\n"));
9903 goto exit;
9904 }
9905
9906 /* pick up multicast cipher */
9907 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
9908 len -= WPA_SUITE_LEN;
9909 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
9910 if (IS_WPA_CIPHER(mcast->type)) {
9911 tmp = 0;
9912 switch (mcast->type) {
9913 case WPA_CIPHER_NONE:
9914 tmp = 0;
9915 break;
9916 case WPA_CIPHER_WEP_40:
9917 case WPA_CIPHER_WEP_104:
9918 tmp = WEP_ENABLED;
9919 break;
9920 case WPA_CIPHER_TKIP:
9921 tmp = TKIP_ENABLED;
9922 break;
9923 case WPA_CIPHER_AES_CCM:
9924 tmp = AES_ENABLED;
9925 break;
9926 default:
9927 WL_ERR(("No Security Info\n"));
9928 }
9929 gval |= tmp;
9930 }
9931 }
9932 /* Check for unicast suite(s) */
9933 if (len < WPA_IE_SUITE_COUNT_LEN) {
9934 WL_INFORM_MEM(("no unicast suite\n"));
9935 goto exit;
9936 }
9937 /* walk thru unicast cipher list and pick up what we recognize */
9938 ucast = (const wpa_suite_ucast_t *)&mcast[1];
9939 count = ltoh16_ua(&ucast->count);
9940 len -= WPA_IE_SUITE_COUNT_LEN;
9941 for (i = 0; i < count && len >= WPA_SUITE_LEN;
9942 i++, len -= WPA_SUITE_LEN) {
9943 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
9944 if (IS_WPA_CIPHER(ucast->list[i].type)) {
9945 tmp = 0;
9946 switch (ucast->list[i].type) {
9947 case WPA_CIPHER_NONE:
9948 tmp = 0;
9949 break;
9950 case WPA_CIPHER_WEP_40:
9951 case WPA_CIPHER_WEP_104:
9952 tmp = WEP_ENABLED;
9953 break;
9954 case WPA_CIPHER_TKIP:
9955 tmp = TKIP_ENABLED;
9956 break;
9957 case WPA_CIPHER_AES_CCM:
9958 tmp = AES_ENABLED;
9959 break;
9960 default:
9961 WL_ERR(("No Security Info\n"));
9962 }
9963 pval |= tmp;
9964 }
9965 }
9966 }
9967 len -= (count - i) * WPA_SUITE_LEN;
9968 /* Check for auth key management suite(s) */
9969 if (len < WPA_IE_SUITE_COUNT_LEN) {
9970 WL_INFORM_MEM((" no auth key mgmt suite\n"));
9971 goto exit;
9972 }
9973 /* walk thru auth management suite list and pick up what we recognize */
9974 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
9975 count = ltoh16_ua(&mgmt->count);
9976 len -= WPA_IE_SUITE_COUNT_LEN;
9977 for (i = 0; i < count && len >= WPA_SUITE_LEN;
9978 i++, len -= WPA_SUITE_LEN) {
9979 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
9980 if (IS_WPA_AKM(mgmt->list[i].type)) {
9981 tmp = 0;
9982 switch (mgmt->list[i].type) {
9983 case RSN_AKM_NONE:
9984 tmp = WPA_AUTH_NONE;
9985 break;
9986 case RSN_AKM_UNSPECIFIED:
9987 tmp = WPA_AUTH_UNSPECIFIED;
9988 break;
9989 case RSN_AKM_PSK:
9990 tmp = WPA_AUTH_PSK;
9991 break;
9992 default:
9993 WL_ERR(("No Key Mgmt Info\n"));
9994 }
9995 wpa_auth |= tmp;
9996 }
9997 }
9998
9999 }
10000 /* FOR WPS , set SEC_OW_ENABLED */
10001 wsec = (pval | gval | SES_OW_ENABLED);
10002 /* set auth */
10003 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10004 if (err < 0) {
10005 WL_ERR(("auth error %d\n", err));
10006 return BCME_ERROR;
10007 }
10008 /* set wsec */
10009 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10010 if (err < 0) {
10011 WL_ERR(("wsec error %d\n", err));
10012 return BCME_ERROR;
10013 }
10014 /* set upper-layer auth */
10015 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10016 if (err < 0) {
10017 WL_ERR(("wpa_auth error %d\n", err));
10018 return BCME_ERROR;
10019 }
10020 exit:
10021 return 0;
10022 }
10023
10024 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10025 static u32 wl_get_cipher_type(uint8 type)
10026 {
10027 u32 ret = 0;
10028 switch (type) {
10029 case WPA_CIPHER_NONE:
10030 ret = 0;
10031 break;
10032 case WPA_CIPHER_WEP_40:
10033 case WPA_CIPHER_WEP_104:
10034 ret = WEP_ENABLED;
10035 break;
10036 case WPA_CIPHER_TKIP:
10037 ret = TKIP_ENABLED;
10038 break;
10039 case WPA_CIPHER_AES_CCM:
10040 ret = AES_ENABLED;
10041 break;
10042 #ifdef BCMWAPI_WPI
10043 case WAPI_CIPHER_SMS4:
10044 ret = SMS4_ENABLED;
10045 break;
10046 #endif // endif
10047 default:
10048 WL_ERR(("No Security Info\n"));
10049 }
10050 return ret;
10051 }
10052
10053 static u32 wl_get_suite_auth_key_mgmt_type(uint8 type, const wpa_suite_mcast_t *mcast)
10054 {
10055 u32 ret = 0;
10056 u32 is_wpa2 = 0;
10057
10058 if (!bcmp(mcast->oui, WPA2_OUI, WPA2_OUI_LEN)) {
10059 is_wpa2 = 1;
10060 }
10061
10062 WL_INFORM_MEM(("%s, type = %d\n", is_wpa2 ? "WPA2":"WPA", type));
10063 switch (type) {
10064 case RSN_AKM_NONE:
10065 /* For WPA and WPA2, AUTH_NONE is common */
10066 ret = WPA_AUTH_NONE;
10067 break;
10068 case RSN_AKM_UNSPECIFIED:
10069 if (is_wpa2) {
10070 ret = WPA2_AUTH_UNSPECIFIED;
10071 } else {
10072 ret = WPA_AUTH_UNSPECIFIED;
10073 }
10074 break;
10075 case RSN_AKM_PSK:
10076 if (is_wpa2) {
10077 ret = WPA2_AUTH_PSK;
10078 } else {
10079 ret = WPA_AUTH_PSK;
10080 }
10081 break;
10082 default:
10083 WL_ERR(("No Key Mgmt Info\n"));
10084 }
10085
10086 return ret;
10087 }
10088
10089 static s32
10090 wl_validate_wpaie_wpa2ie(struct net_device *dev, const wpa_ie_fixed_t *wpaie,
10091 const bcm_tlv_t *wpa2ie, s32 bssidx)
10092 {
10093 const wpa_suite_mcast_t *mcast;
10094 const wpa_suite_ucast_t *ucast;
10095 const wpa_suite_auth_key_mgmt_t *mgmt;
10096 u16 auth = 0; /* d11 open authentication */
10097 u16 count;
10098 s32 err = BCME_OK;
10099 u32 wme_bss_disable;
10100 u16 suite_count;
10101 u8 rsn_cap[2];
10102 s32 len = 0;
10103 u32 i;
10104 u32 wsec1, wsec2, wsec;
10105 u32 pval = 0;
10106 u32 gval = 0;
10107 u32 wpa_auth = 0;
10108 u32 wpa_auth1 = 0;
10109 u32 wpa_auth2 = 0;
10110
10111 if (wpaie == NULL || wpa2ie == NULL)
10112 goto exit;
10113
10114 WL_DBG(("Enter \n"));
10115 len = wpaie->length; /* value length */
10116 len -= WPA_IE_TAG_FIXED_LEN;
10117 /* check for multicast cipher suite */
10118 if (len < WPA_SUITE_LEN) {
10119 WL_INFORM_MEM(("no multicast cipher suite\n"));
10120 goto exit;
10121 }
10122
10123 /* pick up multicast cipher */
10124 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
10125 len -= WPA_SUITE_LEN;
10126 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
10127 if (IS_WPA_CIPHER(mcast->type)) {
10128 gval |= wl_get_cipher_type(mcast->type);
10129 }
10130 }
10131 WL_DBG(("\nwpa ie validate\n"));
10132 WL_DBG(("wpa ie mcast cipher = 0x%X\n", gval));
10133
10134 /* Check for unicast suite(s) */
10135 if (len < WPA_IE_SUITE_COUNT_LEN) {
10136 WL_INFORM_MEM(("no unicast suite\n"));
10137 goto exit;
10138 }
10139
10140 /* walk thru unicast cipher list and pick up what we recognize */
10141 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10142 count = ltoh16_ua(&ucast->count);
10143 len -= WPA_IE_SUITE_COUNT_LEN;
10144 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10145 i++, len -= WPA_SUITE_LEN) {
10146 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10147 if (IS_WPA_CIPHER(ucast->list[i].type)) {
10148 pval |= wl_get_cipher_type(ucast->list[i].type);
10149 }
10150 }
10151 }
10152 WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count, pval));
10153
10154 /* FOR WPS , set SEC_OW_ENABLED */
10155 wsec1 = (pval | gval | SES_OW_ENABLED);
10156 WL_ERR(("wpa ie wsec = 0x%X\n", wsec1));
10157
10158 len -= (count - i) * WPA_SUITE_LEN;
10159 /* Check for auth key management suite(s) */
10160 if (len < WPA_IE_SUITE_COUNT_LEN) {
10161 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10162 goto exit;
10163 }
10164 /* walk thru auth management suite list and pick up what we recognize */
10165 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
10166 count = ltoh16_ua(&mgmt->count);
10167 len -= WPA_IE_SUITE_COUNT_LEN;
10168 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10169 i++, len -= WPA_SUITE_LEN) {
10170 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10171 if (IS_WPA_AKM(mgmt->list[i].type)) {
10172 wpa_auth1 |=
10173 wl_get_suite_auth_key_mgmt_type(mgmt->list[i].type, mcast);
10174 }
10175 }
10176
10177 }
10178 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth1));
10179 WL_ERR(("\nwpa2 ie validate\n"));
10180
10181 pval = 0;
10182 gval = 0;
10183 len = wpa2ie->len;
10184 /* check the mcast cipher */
10185 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10186 gval = wl_get_cipher_type(mcast->type);
10187
10188 WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval));
10189 if ((len -= WPA_SUITE_LEN) <= 0)
10190 {
10191 WL_ERR(("P:wpa2 ie len[%d]", len));
10192 return BCME_BADLEN;
10193 }
10194
10195 /* check the unicast cipher */
10196 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10197 suite_count = ltoh16_ua(&ucast->count);
10198 WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count));
10199 pval |= wl_get_cipher_type(ucast->list[0].type);
10200
10201 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
10202 return BCME_BADLEN;
10203
10204 WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval));
10205
10206 /* FOR WPS , set SEC_OW_ENABLED */
10207 wsec2 = (pval | gval | SES_OW_ENABLED);
10208 WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2));
10209
10210 /* check the AKM */
10211 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
10212 suite_count = ltoh16_ua(&mgmt->count);
10213 wpa_auth2 = wl_get_suite_auth_key_mgmt_type(mgmt->list[0].type, mcast);
10214 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth2));
10215
10216 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
10217 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
10218 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
10219 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
10220 wme_bss_disable = 0;
10221 } else {
10222 wme_bss_disable = 1;
10223 }
10224 WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap[0], wme_bss_disable));
10225
10226 /* set wme_bss_disable to sync RSN Capabilities */
10227 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
10228 if (err < 0) {
10229 WL_ERR(("wme_bss_disable error %d\n", err));
10230 return BCME_ERROR;
10231 }
10232 } else {
10233 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
10234 }
10235
10236 wsec = (wsec1 | wsec2);
10237 wpa_auth = (wpa_auth1 | wpa_auth2);
10238 WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec, wpa_auth));
10239
10240 /* set auth */
10241 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10242 if (err < 0) {
10243 WL_ERR(("auth error %d\n", err));
10244 return BCME_ERROR;
10245 }
10246 /* set wsec */
10247 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10248 if (err < 0) {
10249 WL_ERR(("wsec error %d\n", err));
10250 return BCME_ERROR;
10251 }
10252 /* set upper-layer auth */
10253 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10254 if (err < 0) {
10255 WL_ERR(("wpa_auth error %d\n", err));
10256 return BCME_ERROR;
10257 }
10258 exit:
10259 return 0;
10260 }
10261 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10262
10263 static s32
10264 wl_cfg80211_bcn_validate_sec(
10265 struct net_device *dev,
10266 struct parsed_ies *ies,
10267 u32 dev_role,
10268 s32 bssidx,
10269 bool privacy)
10270 {
10271 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10272 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
10273
10274 if (!bss) {
10275 WL_ERR(("cfgbss is NULL \n"));
10276 return BCME_ERROR;
10277 }
10278
10279 if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
10280 /* For P2P GO, the sec type is WPA2-PSK */
10281 WL_DBG(("P2P GO: validating wpa2_ie"));
10282 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0)
10283 return BCME_ERROR;
10284
10285 } else if (dev_role == NL80211_IFTYPE_AP) {
10286
10287 WL_DBG(("SoftAP: validating security"));
10288 /* If wpa2_ie or wpa_ie is present validate it */
10289
10290 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10291 if ((ies->wpa_ie != NULL && ies->wpa2_ie != NULL)) {
10292 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie, ies->wpa2_ie, bssidx) < 0) {
10293 bss->security_mode = false;
10294 return BCME_ERROR;
10295 }
10296 }
10297 else {
10298 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10299 if ((ies->wpa2_ie || ies->wpa_ie) &&
10300 ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
10301 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
10302 bss->security_mode = false;
10303 return BCME_ERROR;
10304 }
10305
10306 if (ies->fils_ind_ie &&
10307 (wl_validate_fils_ind_ie(dev, ies->fils_ind_ie, bssidx) < 0)) {
10308 bss->security_mode = false;
10309 return BCME_ERROR;
10310 }
10311
10312 bss->security_mode = true;
10313 if (bss->rsn_ie) {
10314 MFREE(cfg->osh, bss->rsn_ie, bss->rsn_ie[1]
10315 + WPA_RSN_IE_TAG_FIXED_LEN);
10316 bss->rsn_ie = NULL;
10317 }
10318 if (bss->wpa_ie) {
10319 MFREE(cfg->osh, bss->wpa_ie, bss->wpa_ie[1]
10320 + WPA_RSN_IE_TAG_FIXED_LEN);
10321 bss->wpa_ie = NULL;
10322 }
10323 if (bss->wps_ie) {
10324 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
10325 bss->wps_ie = NULL;
10326 }
10327 if (bss->fils_ind_ie) {
10328 MFREE(cfg->osh, bss->fils_ind_ie, bss->fils_ind_ie[1]
10329 + FILS_INDICATION_IE_TAG_FIXED_LEN);
10330 bss->fils_ind_ie = NULL;
10331 }
10332 if (ies->wpa_ie != NULL) {
10333 /* WPAIE */
10334 bss->rsn_ie = NULL;
10335 bss->wpa_ie = MALLOCZ(cfg->osh,
10336 ies->wpa_ie->length
10337 + WPA_RSN_IE_TAG_FIXED_LEN);
10338 if (bss->wpa_ie) {
10339 memcpy(bss->wpa_ie, ies->wpa_ie,
10340 ies->wpa_ie->length
10341 + WPA_RSN_IE_TAG_FIXED_LEN);
10342 }
10343 } else if (ies->wpa2_ie != NULL) {
10344 /* RSNIE */
10345 bss->wpa_ie = NULL;
10346 bss->rsn_ie = MALLOCZ(cfg->osh,
10347 ies->wpa2_ie->len
10348 + WPA_RSN_IE_TAG_FIXED_LEN);
10349 if (bss->rsn_ie) {
10350 memcpy(bss->rsn_ie, ies->wpa2_ie,
10351 ies->wpa2_ie->len
10352 + WPA_RSN_IE_TAG_FIXED_LEN);
10353 }
10354 }
10355 #ifdef FILS_SUPPORT
10356 if (ies->fils_ind_ie) {
10357 bss->fils_ind_ie = MALLOCZ(cfg->osh,
10358 ies->fils_ind_ie->len
10359 + FILS_INDICATION_IE_TAG_FIXED_LEN);
10360 if (bss->fils_ind_ie) {
10361 memcpy(bss->fils_ind_ie, ies->fils_ind_ie,
10362 ies->fils_ind_ie->len
10363 + FILS_INDICATION_IE_TAG_FIXED_LEN);
10364 }
10365 }
10366 #endif // endif
10367 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10368 }
10369 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10370 if (!ies->wpa2_ie && !ies->wpa_ie) {
10371 wl_validate_opensecurity(dev, bssidx, privacy);
10372 bss->security_mode = false;
10373 }
10374
10375 if (ies->wps_ie) {
10376 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
10377 if (bss->wps_ie) {
10378 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
10379 }
10380 }
10381 }
10382
10383 return 0;
10384
10385 }
10386
10387 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
10388 static s32 wl_cfg80211_bcn_set_params(
10389 struct cfg80211_ap_settings *info,
10390 struct net_device *dev,
10391 u32 dev_role, s32 bssidx)
10392 {
10393 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10394 s32 err = BCME_OK;
10395
10396 WL_DBG(("interval (%d) \ndtim_period (%d) \n",
10397 info->beacon_interval, info->dtim_period));
10398
10399 if (info->beacon_interval) {
10400 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
10401 &info->beacon_interval, sizeof(s32))) < 0) {
10402 WL_ERR(("Beacon Interval Set Error, %d\n", err));
10403 return err;
10404 }
10405 }
10406
10407 if (info->dtim_period) {
10408 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
10409 &info->dtim_period, sizeof(s32))) < 0) {
10410 WL_ERR(("DTIM Interval Set Error, %d\n", err));
10411 return err;
10412 }
10413 }
10414
10415 if ((info->ssid) && (info->ssid_len > 0) &&
10416 (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
10417 WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
10418 if (dev_role == NL80211_IFTYPE_AP) {
10419 /* Store the hostapd SSID */
10420 memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
10421 memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
10422 cfg->hostapd_ssid.SSID_len = (uint32)info->ssid_len;
10423 } else {
10424 /* P2P GO */
10425 memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
10426 memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
10427 cfg->p2p->ssid.SSID_len = (uint32)info->ssid_len;
10428 }
10429 }
10430
10431 return err;
10432 }
10433 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
10434
10435 static s32
10436 wl_cfg80211_parse_ies(const u8 *ptr, u32 len, struct parsed_ies *ies)
10437 {
10438 s32 err = BCME_OK;
10439
10440 memset(ies, 0, sizeof(struct parsed_ies));
10441
10442 /* find the WPSIE */
10443 if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
10444 WL_DBG(("WPSIE in beacon \n"));
10445 ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
10446 } else {
10447 WL_ERR(("No WPSIE in beacon \n"));
10448 }
10449
10450 /* find the RSN_IE */
10451 if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len,
10452 DOT11_MNG_RSN_ID)) != NULL) {
10453 WL_DBG((" WPA2 IE found\n"));
10454 ies->wpa2_ie_len = ies->wpa2_ie->len;
10455 }
10456
10457 /* find the FILS_IND_IE */
10458 if ((ies->fils_ind_ie = bcm_parse_tlvs(ptr, len,
10459 DOT11_MNG_FILS_IND_ID)) != NULL) {
10460 WL_DBG((" FILS IND IE found\n"));
10461 ies->fils_ind_ie_len = ies->fils_ind_ie->len;
10462 }
10463
10464 /* find the WPA_IE */
10465 if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
10466 WL_DBG((" WPA found\n"));
10467 ies->wpa_ie_len = ies->wpa_ie->length;
10468 }
10469
10470 return err;
10471
10472 }
10473 static s32
10474 wl_cfg80211_set_ap_role(
10475 struct bcm_cfg80211 *cfg,
10476 struct net_device *dev)
10477 {
10478 s32 err = BCME_OK;
10479 s32 infra = 1;
10480 s32 ap = 1;
10481 s32 pm;
10482 s32 is_rsdb_supported = BCME_ERROR;
10483 s32 bssidx;
10484 s32 apsta = 0;
10485
10486 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
10487 if (is_rsdb_supported < 0)
10488 return (-ENODEV);
10489
10490 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
10491 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
10492 return -EINVAL;
10493 }
10494
10495 WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n", dev->name, bssidx));
10496
10497 /* AP on primary Interface */
10498 if (bssidx == 0) {
10499 if (is_rsdb_supported) {
10500 if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
10501 WL_IF_TYPE_AP, 0, NULL)) < 0) {
10502 WL_ERR(("wl add_del_bss returned error:%d\n", err));
10503 return err;
10504 }
10505 } else if (is_rsdb_supported == 0) {
10506 /* AP mode switch not supported. Try setting up AP explicitly */
10507 err = wldev_iovar_getint(dev, "apsta", (s32 *)&apsta);
10508 if (unlikely(err)) {
10509 WL_ERR(("Could not get apsta %d\n", err));
10510 }
10511 if (apsta == 0) {
10512 /* If apsta is not set, set it */
10513 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
10514 if (err < 0) {
10515 WL_ERR(("WLC_DOWN error %d\n", err));
10516 return err;
10517 }
10518 err = wldev_iovar_setint(dev, "apsta", 0);
10519 if (err < 0) {
10520 WL_ERR(("wl apsta 0 error %d\n", err));
10521 return err;
10522 }
10523 if ((err = wldev_ioctl_set(dev,
10524 WLC_SET_AP, &ap, sizeof(s32))) < 0) {
10525 WL_ERR(("setting AP mode failed %d \n", err));
10526 return err;
10527 }
10528 }
10529 }
10530
10531 pm = 0;
10532 if ((err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm))) != 0) {
10533 WL_ERR(("wl PM 0 returned error:%d\n", err));
10534 /* Ignore error, if any */
10535 err = BCME_OK;
10536 }
10537 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
10538 if (err < 0) {
10539 WL_ERR(("SET INFRA error %d\n", err));
10540 return err;
10541 }
10542 } else {
10543 if ((err = wl_cfg80211_add_del_bss(cfg, dev,
10544 bssidx, WL_IF_TYPE_AP, 0, NULL)) < 0) {
10545 WL_ERR(("wl bss ap returned error:%d\n", err));
10546 return err;
10547 }
10548 }
10549
10550 /* On success, mark AP creation in progress. */
10551 wl_set_drv_status(cfg, AP_CREATING, dev);
10552 return 0;
10553 }
10554
10555 /* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
10556 #define MAX_AP_LINK_WAIT_TIME 10000
10557 static s32
10558 wl_cfg80211_bcn_bringup_ap(
10559 struct net_device *dev,
10560 struct parsed_ies *ies,
10561 u32 dev_role, s32 bssidx)
10562 {
10563 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10564 struct wl_join_params join_params;
10565 bool is_bssup = false;
10566 s32 infra = 1;
10567 s32 join_params_size = 0;
10568 s32 ap = 1;
10569 s32 wsec;
10570 #ifdef DISABLE_11H_SOFTAP
10571 s32 spect = 0;
10572 #endif /* DISABLE_11H_SOFTAP */
10573 #ifdef SOFTAP_UAPSD_OFF
10574 uint32 wme_apsd = 0;
10575 #endif /* SOFTAP_UAPSD_OFF */
10576 s32 err = BCME_OK;
10577 s32 is_rsdb_supported = BCME_ERROR;
10578 long timeout;
10579 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
10580 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
10581 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
10582
10583 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
10584 if (is_rsdb_supported < 0)
10585 return (-ENODEV);
10586
10587 WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role, bssidx, dev->name));
10588
10589 if (wl_check_dongle_idle(bcmcfg_to_wiphy(cfg)) != TRUE) {
10590 WL_ERR(("FW is busy to add interface"));
10591 return -EINVAL;
10592 }
10593
10594 /* Common code for SoftAP and P2P GO */
10595 wl_clr_drv_status(cfg, AP_CREATED, dev);
10596
10597 /* Make sure INFRA is set for AP/GO */
10598 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
10599 if (err < 0) {
10600 WL_ERR(("SET INFRA error %d\n", err));
10601 goto exit;
10602 }
10603
10604 /* Do abort scan before creating GO */
10605 wl_cfg80211_scan_abort(cfg);
10606
10607 if (dev_role == NL80211_IFTYPE_P2P_GO) {
10608 is_bssup = wl_cfg80211_bss_isup(dev, bssidx);
10609 if (!is_bssup && (ies->wpa2_ie != NULL)) {
10610
10611 err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid,
10612 sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
10613 bssidx, &cfg->ioctl_buf_sync);
10614 if (err < 0) {
10615 WL_ERR(("GO SSID setting error %d\n", err));
10616 goto exit;
10617 }
10618
10619 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
10620 WL_ERR(("GO Bring up error %d\n", err));
10621 goto exit;
10622 }
10623 } else
10624 WL_DBG(("Bss is already up\n"));
10625 } else if (dev_role == NL80211_IFTYPE_AP) {
10626
10627 if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
10628 /* Make sure fw is in proper state */
10629 err = wl_cfg80211_set_ap_role(cfg, dev);
10630 if (unlikely(err)) {
10631 WL_ERR(("set ap role failed!\n"));
10632 goto exit;
10633 }
10634 }
10635
10636 /* Device role SoftAP */
10637 WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
10638 /* Clear the status bit after use */
10639 wl_clr_drv_status(cfg, AP_CREATING, dev);
10640
10641 #ifdef DISABLE_11H_SOFTAP
10642 if (is_rsdb_supported == 0) {
10643 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
10644 if (err < 0) {
10645 WL_ERR(("WLC_DOWN error %d\n", err));
10646 goto exit;
10647 }
10648 }
10649 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT,
10650 &spect, sizeof(s32));
10651 if (err < 0) {
10652 WL_ERR(("SET SPECT_MANAGMENT error %d\n", err));
10653 goto exit;
10654 }
10655 #endif /* DISABLE_11H_SOFTAP */
10656
10657 #ifdef SOFTAP_UAPSD_OFF
10658 err = wldev_iovar_setbuf_bsscfg(dev, "wme_apsd", &wme_apsd, sizeof(wme_apsd),
10659 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
10660 if (err < 0) {
10661 WL_ERR(("failed to disable uapsd, error=%d\n", err));
10662 }
10663 #endif /* SOFTAP_UAPSD_OFF */
10664
10665 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
10666 if (unlikely(err)) {
10667 WL_ERR(("WLC_UP error (%d)\n", err));
10668 goto exit;
10669 }
10670
10671 #ifdef MFP
10672 if (cfg->bip_pos) {
10673 err = wldev_iovar_setbuf_bsscfg(dev, "bip",
10674 (const void *)(cfg->bip_pos), WPA_SUITE_LEN, cfg->ioctl_buf,
10675 WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
10676 if (err < 0) {
10677 WL_ERR(("bip set error %d\n", err));
10678 #if defined(CUSTOMER_HW4)
10679 if (wl_legacy_chip_check(cfg))
10680 {
10681 /* Ignore bip error: Some older firmwares doesn't
10682 * support bip iovar/ return BCME_NOTUP while trying
10683 * to set bip from AP bring up context. These firmares
10684 * include bip in RSNIE by default. So its okay to ignore
10685 * the error.
10686 */
10687 err = BCME_OK;
10688 } else
10689 #endif // endif
10690 {
10691 goto exit;
10692 }
10693 }
10694 }
10695 #endif /* MFP */
10696
10697 err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec);
10698 if (unlikely(err)) {
10699 WL_ERR(("Could not get wsec %d\n", err));
10700 goto exit;
10701 }
10702 if ((wsec == WEP_ENABLED) && cfg->wep_key.len) {
10703 WL_DBG(("Applying buffered WEP KEY \n"));
10704 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &cfg->wep_key,
10705 sizeof(struct wl_wsec_key), cfg->ioctl_buf,
10706 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
10707 /* clear the key after use */
10708 memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
10709 if (unlikely(err)) {
10710 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
10711 goto exit;
10712 }
10713 }
10714
10715 #ifdef MFP
10716 if (cfg->mfp_mode) {
10717 /* This needs to go after wsec otherwise the wsec command will
10718 * overwrite the values set by MFP
10719 */
10720 err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx);
10721 if (err < 0) {
10722 WL_ERR(("MFP Setting failed. ret = %d \n", err));
10723 /* If fw doesn't support mfp, Ignore the error */
10724 if (err != BCME_UNSUPPORTED) {
10725 goto exit;
10726 }
10727 }
10728 }
10729 #endif /* MFP */
10730
10731 memset(&join_params, 0, sizeof(join_params));
10732 /* join parameters starts with ssid */
10733 join_params_size = sizeof(join_params.ssid);
10734 join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
10735 (uint32)DOT11_MAX_SSID_LEN);
10736 memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
10737 join_params.ssid.SSID_len);
10738 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
10739
10740 /* create softap */
10741 if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
10742 join_params_size)) != 0) {
10743 WL_ERR(("SoftAP/GO set ssid failed! \n"));
10744 goto exit;
10745 } else {
10746 WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
10747 }
10748
10749 if (bssidx != 0) {
10750 /* AP on Virtual Interface */
10751 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
10752 WL_ERR(("AP Bring up error %d\n", err));
10753 goto exit;
10754 }
10755 }
10756
10757 } else {
10758 WL_ERR(("Wrong interface type %d\n", dev_role));
10759 goto exit;
10760 }
10761
10762 /* Wait for Linkup event to mark successful AP/GO bring up */
10763 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
10764 wl_get_drv_status(cfg, AP_CREATED, dev), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
10765 if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) {
10766 WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
10767 if (timeout == -ERESTARTSYS) {
10768 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
10769 err = -ERESTARTSYS;
10770 goto exit;
10771 }
10772 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
10773 if (dhdp->memdump_enabled) {
10774 dhdp->memdump_type = DUMP_TYPE_AP_LINKUP_FAILURE;
10775 dhd_bus_mem_dump(dhdp);
10776 }
10777 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
10778 err = -ENODEV;
10779 goto exit;
10780 }
10781 SUPP_LOG(("AP/GO Link up\n"));
10782
10783 exit:
10784 if (cfg->wep_key.len) {
10785 memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
10786 }
10787
10788 #ifdef MFP
10789 if (cfg->mfp_mode) {
10790 cfg->mfp_mode = 0;
10791 }
10792
10793 if (cfg->bip_pos) {
10794 cfg->bip_pos = NULL;
10795 }
10796 #endif /* MFP */
10797
10798 if (err) {
10799 SUPP_LOG(("AP/GO bring up fail. err:%d\n", err));
10800 }
10801 return err;
10802 }
10803
10804 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
10805 s32
10806 wl_cfg80211_parse_ap_ies(
10807 struct net_device *dev,
10808 struct cfg80211_beacon_data *info,
10809 struct parsed_ies *ies)
10810 {
10811 struct parsed_ies prb_ies;
10812 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10813 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10814 const u8 *vndr = NULL;
10815 u32 vndr_ie_len = 0;
10816 s32 err = BCME_OK;
10817
10818 /* Parse Beacon IEs */
10819 if (wl_cfg80211_parse_ies((const u8 *)info->tail,
10820 info->tail_len, ies) < 0) {
10821 WL_ERR(("Beacon get IEs failed \n"));
10822 err = -EINVAL;
10823 goto fail;
10824 }
10825
10826 vndr = (const u8 *)info->proberesp_ies;
10827 vndr_ie_len = (uint32)info->proberesp_ies_len;
10828
10829 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
10830 /* SoftAP mode */
10831 const struct ieee80211_mgmt *mgmt;
10832 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
10833 if (mgmt != NULL) {
10834 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
10835 vndr_ie_len = (uint32)(info->probe_resp_len -
10836 offsetof(const struct ieee80211_mgmt, u.probe_resp.variable));
10837 }
10838 }
10839 /* Parse Probe Response IEs */
10840 if (wl_cfg80211_parse_ies((const u8 *)vndr, vndr_ie_len, &prb_ies) < 0) {
10841 WL_ERR(("PROBE RESP get IEs failed \n"));
10842 err = -EINVAL;
10843 }
10844 fail:
10845
10846 return err;
10847 }
10848
10849 s32
10850 wl_cfg80211_set_ies(
10851 struct net_device *dev,
10852 struct cfg80211_beacon_data *info,
10853 s32 bssidx)
10854 {
10855 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10856 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10857 const u8 *vndr = NULL;
10858 u32 vndr_ie_len = 0;
10859 s32 err = BCME_OK;
10860
10861 /* Set Beacon IEs to FW */
10862 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
10863 VNDR_IE_BEACON_FLAG, (const u8 *)info->tail,
10864 info->tail_len)) < 0) {
10865 WL_ERR(("Set Beacon IE Failed \n"));
10866 } else {
10867 WL_DBG(("Applied Vndr IEs for Beacon \n"));
10868 }
10869
10870 vndr = (const u8 *)info->proberesp_ies;
10871 vndr_ie_len = (uint32)info->proberesp_ies_len;
10872
10873 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
10874 /* SoftAP mode */
10875 const struct ieee80211_mgmt *mgmt;
10876 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
10877 if (mgmt != NULL) {
10878 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
10879 vndr_ie_len = (uint32)(info->probe_resp_len -
10880 offsetof(struct ieee80211_mgmt, u.probe_resp.variable));
10881 }
10882 }
10883
10884 /* Set Probe Response IEs to FW */
10885 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
10886 VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
10887 WL_ERR(("Set Probe Resp IE Failed \n"));
10888 } else {
10889 WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
10890 }
10891
10892 return err;
10893 }
10894 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
10895
10896 static s32 wl_cfg80211_hostapd_sec(
10897 struct net_device *dev,
10898 struct parsed_ies *ies,
10899 s32 bssidx)
10900 {
10901 bool update_bss = 0;
10902 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10903 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
10904
10905 if (!bss) {
10906 WL_ERR(("cfgbss is NULL \n"));
10907 return -EINVAL;
10908 }
10909
10910 if (ies->wps_ie) {
10911 if (bss->wps_ie &&
10912 memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
10913 WL_DBG((" WPS IE is changed\n"));
10914 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
10915 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
10916 if (bss->wps_ie) {
10917 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
10918 }
10919 } else if (bss->wps_ie == NULL) {
10920 WL_DBG((" WPS IE is added\n"));
10921 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
10922 if (bss->wps_ie) {
10923 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
10924 }
10925 }
10926
10927 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10928 if (ies->wpa_ie != NULL && ies->wpa2_ie != NULL) {
10929 WL_ERR(("update bss - wpa_ie and wpa2_ie is not null\n"));
10930 if (!bss->security_mode) {
10931 /* change from open mode to security mode */
10932 update_bss = true;
10933 bss->wpa_ie = MALLOCZ(cfg->osh,
10934 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
10935 if (bss->wpa_ie) {
10936 memcpy(bss->wpa_ie, ies->wpa_ie,
10937 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
10938 }
10939 bss->rsn_ie = MALLOCZ(cfg->osh,
10940 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
10941 if (bss->rsn_ie) {
10942 memcpy(bss->rsn_ie, ies->wpa2_ie,
10943 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
10944 }
10945 } else {
10946 /* change from (WPA or WPA2 or WPA/WPA2) to WPA/WPA2 mixed mode */
10947 if (bss->wpa_ie) {
10948 if (memcmp(bss->wpa_ie,
10949 ies->wpa_ie, ies->wpa_ie->length +
10950 WPA_RSN_IE_TAG_FIXED_LEN)) {
10951 MFREE(cfg->osh, bss->wpa_ie,
10952 bss->wpa_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
10953 update_bss = true;
10954 bss->wpa_ie = MALLOCZ(cfg->osh,
10955 ies->wpa_ie->length
10956 + WPA_RSN_IE_TAG_FIXED_LEN);
10957 if (bss->wpa_ie) {
10958 memcpy(bss->wpa_ie, ies->wpa_ie,
10959 ies->wpa_ie->length
10960 + WPA_RSN_IE_TAG_FIXED_LEN);
10961 }
10962 }
10963 }
10964 else {
10965 update_bss = true;
10966 bss->wpa_ie = MALLOCZ(cfg->osh,
10967 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
10968 if (bss->wpa_ie) {
10969 memcpy(bss->wpa_ie, ies->wpa_ie,
10970 ies->wpa_ie->length
10971 + WPA_RSN_IE_TAG_FIXED_LEN);
10972 }
10973 }
10974 if (bss->rsn_ie) {
10975 if (memcmp(bss->rsn_ie,
10976 ies->wpa2_ie,
10977 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
10978 update_bss = true;
10979 MFREE(cfg->osh, bss->rsn_ie,
10980 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
10981 bss->rsn_ie = MALLOCZ(cfg->osh,
10982 ies->wpa2_ie->len
10983 + WPA_RSN_IE_TAG_FIXED_LEN);
10984 if (bss->rsn_ie) {
10985 memcpy(bss->rsn_ie, ies->wpa2_ie,
10986 ies->wpa2_ie->len
10987 + WPA_RSN_IE_TAG_FIXED_LEN);
10988 }
10989 }
10990 }
10991 else {
10992 update_bss = true;
10993 bss->rsn_ie = MALLOCZ(cfg->osh,
10994 ies->wpa2_ie->len
10995 + WPA_RSN_IE_TAG_FIXED_LEN);
10996 if (bss->rsn_ie) {
10997 memcpy(bss->rsn_ie, ies->wpa2_ie,
10998 ies->wpa2_ie->len
10999 + WPA_RSN_IE_TAG_FIXED_LEN);
11000 }
11001 }
11002 }
11003 WL_ERR(("update_bss=%d\n", update_bss));
11004 if (update_bss) {
11005 bss->security_mode = true;
11006 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11007 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie,
11008 ies->wpa2_ie, bssidx) < 0) {
11009 return BCME_ERROR;
11010 }
11011 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11012 }
11013
11014 }
11015 else
11016 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11017 if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
11018 if (!bss->security_mode) {
11019 /* change from open mode to security mode */
11020 update_bss = true;
11021 if (ies->wpa_ie != NULL) {
11022 bss->wpa_ie = MALLOCZ(cfg->osh,
11023 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11024 if (bss->wpa_ie) {
11025 memcpy(bss->wpa_ie,
11026 ies->wpa_ie,
11027 ies->wpa_ie->length
11028 + WPA_RSN_IE_TAG_FIXED_LEN);
11029 }
11030 } else {
11031 bss->rsn_ie = MALLOCZ(cfg->osh,
11032 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11033 if (bss->rsn_ie) {
11034 memcpy(bss->rsn_ie,
11035 ies->wpa2_ie,
11036 ies->wpa2_ie->len
11037 + WPA_RSN_IE_TAG_FIXED_LEN);
11038 }
11039 }
11040 } else if (bss->wpa_ie) {
11041 /* change from WPA2 mode to WPA mode */
11042 if (ies->wpa_ie != NULL) {
11043 update_bss = true;
11044 MFREE(cfg->osh, bss->rsn_ie,
11045 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11046 bss->rsn_ie = NULL;
11047 bss->wpa_ie = MALLOCZ(cfg->osh,
11048 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11049 if (bss->wpa_ie) {
11050 memcpy(bss->wpa_ie,
11051 ies->wpa_ie,
11052 ies->wpa_ie->length
11053 + WPA_RSN_IE_TAG_FIXED_LEN);
11054 }
11055 } else if (memcmp(bss->rsn_ie,
11056 ies->wpa2_ie, ies->wpa2_ie->len
11057 + WPA_RSN_IE_TAG_FIXED_LEN)) {
11058 update_bss = true;
11059 MFREE(cfg->osh, bss->rsn_ie,
11060 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11061 bss->rsn_ie = MALLOCZ(cfg->osh,
11062 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11063 if (bss->rsn_ie) {
11064 memcpy(bss->rsn_ie,
11065 ies->wpa2_ie,
11066 ies->wpa2_ie->len
11067 + WPA_RSN_IE_TAG_FIXED_LEN);
11068 }
11069 bss->wpa_ie = NULL;
11070 }
11071 }
11072 if (update_bss) {
11073 bss->security_mode = true;
11074 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11075 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
11076 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
11077 return BCME_ERROR;
11078 }
11079 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11080 }
11081 }
11082 } else {
11083 WL_ERR(("No WPSIE in beacon \n"));
11084 }
11085 return 0;
11086 }
11087
11088 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
11089 2, 0))
11090 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11091 static s32
11092 wl_cfg80211_del_station(
11093 struct wiphy *wiphy, struct net_device *ndev,
11094 struct station_del_parameters *params)
11095 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
11096 static s32
11097 wl_cfg80211_del_station(
11098 struct wiphy *wiphy,
11099 struct net_device *ndev,
11100 const u8* mac_addr)
11101 #else
11102 static s32
11103 wl_cfg80211_del_station(
11104 struct wiphy *wiphy,
11105 struct net_device *ndev,
11106 u8* mac_addr)
11107 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11108 {
11109 struct net_device *dev;
11110 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11111 scb_val_t scb_val;
11112 s8 eabuf[ETHER_ADDR_STR_LEN];
11113 int err;
11114 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
11115 sizeof(struct ether_addr) + sizeof(uint)] = {0};
11116 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
11117 int num_associated = 0;
11118
11119 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11120 const u8 *mac_addr = params->mac;
11121 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11122 u16 rc = params->reason_code;
11123 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11124 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11125 WL_DBG(("Entry\n"));
11126 if (mac_addr == NULL) {
11127 WL_DBG(("mac_addr is NULL ignore it\n"));
11128 return 0;
11129 }
11130
11131 dev = ndev_to_wlc_ndev(ndev, cfg);
11132
11133 if (p2p_is_on(cfg)) {
11134 /* Suspend P2P discovery search-listen to prevent it from changing the
11135 * channel.
11136 */
11137 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
11138 WL_ERR(("Can not disable discovery mode\n"));
11139 return -EFAULT;
11140 }
11141 }
11142
11143 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
11144 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
11145 assoc_maclist, sizeof(mac_buf));
11146 if (err < 0)
11147 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
11148 else
11149 num_associated = assoc_maclist->count;
11150
11151 memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
11152 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11153 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11154 if (rc == DOT11_RC_8021X_AUTH_FAIL) {
11155 WL_ERR(("deauth will be sent at F/W\n"));
11156 scb_val.val = DOT11_RC_8021X_AUTH_FAIL;
11157 } else {
11158 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11159 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11160
11161 #ifdef WL_WPS_SYNC
11162 if (wl_wps_session_update(ndev,
11163 WPS_STATE_DISCONNECT_CLIENT, mac_addr) == BCME_UNSUPPORTED) {
11164 /* Ignore disconnect command from upper layer */
11165 WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
11166 } else
11167 #endif /* WL_WPS_SYNC */
11168 {
11169
11170 /* need to guarantee EAP-Failure send out before deauth */
11171 dhd_wait_pend8021x(dev);
11172 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
11173 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
11174 sizeof(scb_val_t));
11175 if (err < 0) {
11176 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
11177 }
11178 WL_INFORM_MEM(("Disconnect STA : " MACDBG " scb_val.val %d\n",
11179 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mac_addr,
11180 eabuf)), scb_val.val));
11181 }
11182 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11183 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11184 }
11185 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11186 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11187
11188 if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
11189 wl_delay(400);
11190
11191 return 0;
11192 }
11193
11194 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
11195 static s32
11196 wl_cfg80211_change_station(
11197 struct wiphy *wiphy,
11198 struct net_device *dev,
11199 const u8 *mac,
11200 struct station_parameters *params)
11201 #else
11202 static s32
11203 wl_cfg80211_change_station(
11204 struct wiphy *wiphy,
11205 struct net_device *dev,
11206 u8 *mac,
11207 struct station_parameters *params)
11208 #endif // endif
11209 {
11210 int err;
11211 #ifdef DHD_LOSSLESS_ROAMING
11212 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11213 #endif // endif
11214
11215 WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x "
11216 "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac),
11217 params->sta_flags_mask, params->sta_flags_set, dev->name));
11218
11219 /* Processing only authorize/de-authorize flag for now */
11220 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
11221 WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
11222 return -ENOTSUPP;
11223 }
11224
11225 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
11226 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN);
11227 if (unlikely(err)) {
11228 WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
11229 } else {
11230 WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG "\n",
11231 dev->name, MAC2STRDBG(mac)));
11232 }
11233 return err;
11234 }
11235
11236 err = wldev_ioctl_set(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN);
11237 if (unlikely(err)) {
11238 WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
11239 } else {
11240 WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG "\n",
11241 dev->name, MAC2STRDBG(mac)));
11242 #ifdef WL_WPS_SYNC
11243 wl_wps_session_update(dev, WPS_STATE_AUTHORIZE, mac);
11244 #endif /* WL_WPS_SYNC */
11245 }
11246 #ifdef DHD_LOSSLESS_ROAMING
11247 wl_del_roam_timeout(cfg);
11248 #endif // endif
11249 return err;
11250 }
11251 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
11252
11253 static s32
11254 wl_cfg80211_set_scb_timings(
11255 struct bcm_cfg80211 *cfg,
11256 struct net_device *dev)
11257 {
11258 int err;
11259 u32 ps_pretend;
11260 wl_scb_probe_t scb_probe;
11261 u32 ps_pretend_retries;
11262
11263 bzero(&scb_probe, sizeof(wl_scb_probe_t));
11264 scb_probe.scb_timeout = WL_SCB_TIMEOUT;
11265 scb_probe.scb_activity_time = WL_SCB_ACTIVITY_TIME;
11266 scb_probe.scb_max_probe = WL_SCB_MAX_PROBE;
11267 err = wldev_iovar_setbuf(dev, "scb_probe", (void *)&scb_probe,
11268 sizeof(wl_scb_probe_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
11269 &cfg->ioctl_buf_sync);
11270 if (unlikely(err)) {
11271 WL_ERR(("set 'scb_probe' failed, error = %d\n", err));
11272 return err;
11273 }
11274
11275 ps_pretend_retries = WL_PSPRETEND_RETRY_LIMIT;
11276 err = wldev_iovar_setint(dev, "pspretend_retry_limit", ps_pretend_retries);
11277 if (unlikely(err)) {
11278 if (err == BCME_UNSUPPORTED) {
11279 /* Ignore error if fw doesn't support the iovar */
11280 WL_DBG(("set 'pspretend_retry_limit %d' failed, error = %d\n",
11281 ps_pretend_retries, err));
11282 } else {
11283 WL_ERR(("set 'pspretend_retry_limit %d' failed, error = %d\n",
11284 ps_pretend_retries, err));
11285 return err;
11286 }
11287 }
11288
11289 ps_pretend = MAX(WL_SCB_MAX_PROBE / 2, WL_MIN_PSPRETEND_THRESHOLD);
11290 err = wldev_iovar_setint(dev, "pspretend_threshold", ps_pretend);
11291 if (unlikely(err)) {
11292 if (err == BCME_UNSUPPORTED) {
11293 /* Ignore error if fw doesn't support the iovar */
11294 WL_DBG(("wl pspretend_threshold %d set error %d\n",
11295 ps_pretend, err));
11296 } else {
11297 WL_ERR(("wl pspretend_threshold %d set error %d\n",
11298 ps_pretend, err));
11299 return err;
11300 }
11301 }
11302
11303 return 0;
11304 }
11305
11306 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11307 static s32
11308 wl_cfg80211_start_ap(
11309 struct wiphy *wiphy,
11310 struct net_device *dev,
11311 struct cfg80211_ap_settings *info)
11312 {
11313 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11314 s32 err = BCME_OK;
11315 struct parsed_ies ies;
11316 s32 bssidx = 0;
11317 u32 dev_role = 0;
11318 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11319
11320 WL_DBG(("Enter \n"));
11321 #if defined(SUPPORT_RANDOM_MAC_SCAN)
11322 wl_cfg80211_random_mac_disable(dev);
11323 #endif /* SUPPORT_RANDOM_MAC_SCAN */
11324
11325 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11326 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11327 return BCME_ERROR;
11328 }
11329
11330 if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
11331 dev_role = NL80211_IFTYPE_P2P_GO;
11332 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
11333 dev_role = NL80211_IFTYPE_AP;
11334 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
11335 err = dhd_ndo_enable(dhd, FALSE);
11336 WL_DBG(("%s: Disabling NDO on Hostapd mode %d\n", __FUNCTION__, err));
11337 if (err) {
11338 WL_ERR(("%s: Disabling NDO Failed %d\n", __FUNCTION__, err));
11339 }
11340 #ifdef PKT_FILTER_SUPPORT
11341 /* Disable packet filter */
11342 if (dhd->early_suspended) {
11343 WL_ERR(("Disable pkt_filter\n"));
11344 dhd_enable_packet_filter(0, dhd);
11345 }
11346 #endif /* PKT_FILTER_SUPPORT */
11347 #ifdef ARP_OFFLOAD_SUPPORT
11348 /* IF SoftAP is enabled, disable arpoe */
11349 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
11350 dhd_arp_offload_set(dhd, 0);
11351 dhd_arp_offload_enable(dhd, FALSE);
11352 }
11353 #endif /* ARP_OFFLOAD_SUPPORT */
11354 } else {
11355 /* only AP or GO role need to be handled here. */
11356 err = -EINVAL;
11357 goto fail;
11358 }
11359
11360 /* disable TDLS */
11361 #ifdef WLTDLS
11362 if (bssidx == 0) {
11363 /* Disable TDLS for primary Iface. For virtual interface,
11364 * tdls disable will happen from interface create context
11365 */
11366 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_CREATE, false);
11367 }
11368 #endif /* WLTDLS */
11369
11370 if (!check_dev_role_integrity(cfg, dev_role)) {
11371 err = -EINVAL;
11372 goto fail;
11373 }
11374
11375 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
11376 if ((err = wl_cfg80211_set_channel(wiphy, dev,
11377 dev->ieee80211_ptr->preset_chandef.chan,
11378 NL80211_CHAN_HT20) < 0)) {
11379 WL_ERR(("Set channel failed \n"));
11380 goto fail;
11381 }
11382 #endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
11383
11384 if ((err = wl_cfg80211_bcn_set_params(info, dev,
11385 dev_role, bssidx)) < 0) {
11386 WL_ERR(("Beacon params set failed \n"));
11387 goto fail;
11388 }
11389
11390 /* Parse IEs */
11391 if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) {
11392 WL_ERR(("Set IEs failed \n"));
11393 goto fail;
11394 }
11395
11396 if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies,
11397 dev_role, bssidx, info->privacy)) < 0)
11398 {
11399 WL_ERR(("Beacon set security failed \n"));
11400 goto fail;
11401 }
11402
11403 if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies,
11404 dev_role, bssidx)) < 0) {
11405 WL_ERR(("Beacon bring up AP/GO failed \n"));
11406 goto fail;
11407 }
11408
11409 /* Set GC/STA SCB expiry timings. */
11410 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
11411 WL_ERR(("scb setting failed \n"));
11412 goto fail;
11413 }
11414
11415 wl_set_drv_status(cfg, CONNECTED, dev);
11416 WL_DBG(("** AP/GO Created **\n"));
11417
11418 #ifdef WL_CFG80211_ACL
11419 /* Enfoce Admission Control. */
11420 if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
11421 WL_ERR(("Set ACL failed\n"));
11422 }
11423 #endif /* WL_CFG80211_ACL */
11424
11425 /* Set IEs to FW */
11426 if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
11427 WL_ERR(("Set IEs failed \n"));
11428
11429 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
11430 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
11431 bool pbc = 0;
11432 wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
11433 if (pbc) {
11434 WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
11435 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
11436 }
11437 }
11438
11439 /* Configure hidden SSID */
11440 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) {
11441 if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
11442 WL_ERR(("failed to set hidden : %d\n", err));
11443 WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
11444 }
11445
11446 #ifdef SUPPORT_AP_RADIO_PWRSAVE
11447 if (dev_role == NL80211_IFTYPE_AP) {
11448 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
11449 wl_cfg80211_init_ap_rps(cfg);
11450 } else {
11451 WL_ERR(("Set rpsnoa failed \n"));
11452 }
11453 }
11454 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
11455
11456 fail:
11457 if (err) {
11458 WL_ERR(("ADD/SET beacon failed\n"));
11459 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
11460 wl_cfg80211_stop_ap(wiphy, dev);
11461 if (dev_role == NL80211_IFTYPE_AP) {
11462 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
11463 #ifdef PKT_FILTER_SUPPORT
11464 /* Enable packet filter */
11465 if (dhd->early_suspended) {
11466 WL_ERR(("Enable pkt_filter\n"));
11467 dhd_enable_packet_filter(1, dhd);
11468 }
11469 #endif /* PKT_FILTER_SUPPORT */
11470 #ifdef ARP_OFFLOAD_SUPPORT
11471 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
11472 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
11473 dhd_arp_offload_set(dhd, dhd_arp_mode);
11474 dhd_arp_offload_enable(dhd, TRUE);
11475 }
11476 #endif /* ARP_OFFLOAD_SUPPORT */
11477 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
11478 wl_cfg80211_set_frameburst(cfg, TRUE);
11479 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
11480 }
11481 #ifdef WLTDLS
11482 if (bssidx == 0) {
11483 /* Since AP creation failed, re-enable TDLS */
11484 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
11485 }
11486 #endif /* WLTDLS */
11487
11488 }
11489
11490 return err;
11491 }
11492
11493 static s32
11494 wl_cfg80211_stop_ap(
11495 struct wiphy *wiphy,
11496 struct net_device *dev)
11497 {
11498 int err = 0;
11499 u32 dev_role = 0;
11500 int ap = 0;
11501 s32 bssidx = 0;
11502 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11503 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11504
11505 WL_DBG(("Enter \n"));
11506
11507 if (wl_cfg80211_get_bus_state(cfg)) {
11508 /* since bus is down, iovar will fail. recovery path will bringup the bus. */
11509 WL_ERR(("bus is not ready\n"));
11510 return BCME_OK;
11511 }
11512
11513 if (!dhd) {
11514 return (-ENODEV);
11515 }
11516
11517 wl_clr_drv_status(cfg, AP_CREATING, dev);
11518 wl_clr_drv_status(cfg, AP_CREATED, dev);
11519 cfg->ap_oper_channel = 0;
11520
11521 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
11522 dev_role = NL80211_IFTYPE_AP;
11523 WL_DBG(("stopping AP operation\n"));
11524 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
11525 dev_role = NL80211_IFTYPE_P2P_GO;
11526 WL_DBG(("stopping P2P GO operation\n"));
11527 } else {
11528 WL_ERR(("no AP/P2P GO interface is operational.\n"));
11529 return -EINVAL;
11530 }
11531
11532 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11533 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11534 return BCME_ERROR;
11535 }
11536
11537 if (!check_dev_role_integrity(cfg, dev_role)) {
11538 WL_ERR(("role integrity check failed \n"));
11539 err = -EINVAL;
11540 goto exit;
11541 }
11542
11543 /* Free up resources */
11544 wl_cfg80211_cleanup_if(dev);
11545
11546 /* Clear AP/GO connected status */
11547 wl_clr_drv_status(cfg, CONNECTED, dev);
11548 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
11549 WL_ERR(("bss down error %d\n", err));
11550 }
11551
11552 if (dev_role == NL80211_IFTYPE_AP) {
11553 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
11554 wl_cfg80211_set_frameburst(cfg, TRUE);
11555 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
11556 #ifdef PKT_FILTER_SUPPORT
11557 /* Enable packet filter */
11558 if (dhd->early_suspended) {
11559 WL_ERR(("Enable pkt_filter\n"));
11560 dhd_enable_packet_filter(1, dhd);
11561 }
11562 #endif /* PKT_FILTER_SUPPORT */
11563 #ifdef ARP_OFFLOAD_SUPPORT
11564 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
11565 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
11566 dhd_arp_offload_set(dhd, dhd_arp_mode);
11567 dhd_arp_offload_enable(dhd, TRUE);
11568 }
11569 #endif /* ARP_OFFLOAD_SUPPORT */
11570
11571 if (!DHD_OPMODE_STA_SOFTAP_CONCURR(dhd)) {
11572 /* For non-STA/SoftAP Concurrent mode,
11573 * we use stand alone AP. Do wl down on stop AP
11574 */
11575 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
11576 if (unlikely(err)) {
11577 WL_ERR(("WLC_UP error (%d)\n", err));
11578 err = -EINVAL;
11579 goto exit;
11580 }
11581 }
11582
11583 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
11584 #ifdef SUPPORT_AP_RADIO_PWRSAVE
11585 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
11586 wl_cfg80211_init_ap_rps(cfg);
11587 } else {
11588 WL_ERR(("Set rpsnoa failed \n"));
11589 }
11590 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
11591 } else {
11592 WL_DBG(("Stopping P2P GO \n"));
11593 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS*3);
11594 DHD_OS_WAKE_LOCK_TIMEOUT(dhd);
11595 }
11596
11597 SUPP_LOG(("AP/GO Link down\n"));
11598 exit:
11599 if (err) {
11600 /* In case of failure, flush fw logs */
11601 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
11602 SUPP_LOG(("AP/GO Link down fail. err:%d\n", err));
11603 }
11604 #ifdef WLTDLS
11605 if (bssidx == 0) {
11606 /* re-enable TDLS if the number of connected interfaces is less than 2 */
11607 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
11608 }
11609 #endif /* WLTDLS */
11610
11611 if (dev_role == NL80211_IFTYPE_AP) {
11612 /* clear the AP mode */
11613 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
11614 }
11615 return err;
11616 }
11617
11618 static s32
11619 wl_cfg80211_change_beacon(
11620 struct wiphy *wiphy,
11621 struct net_device *dev,
11622 struct cfg80211_beacon_data *info)
11623 {
11624 s32 err = BCME_OK;
11625 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11626 struct parsed_ies ies;
11627 u32 dev_role = 0;
11628 s32 bssidx = 0;
11629 bool pbc = 0;
11630
11631 WL_DBG(("Enter \n"));
11632
11633 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11634 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11635 return BCME_ERROR;
11636 }
11637
11638 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
11639 dev_role = NL80211_IFTYPE_P2P_GO;
11640 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
11641 dev_role = NL80211_IFTYPE_AP;
11642 } else {
11643 err = -EINVAL;
11644 goto fail;
11645 }
11646
11647 if (!check_dev_role_integrity(cfg, dev_role)) {
11648 err = -EINVAL;
11649 goto fail;
11650 }
11651
11652 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
11653 WL_ERR(("P2P already down status!\n"));
11654 err = BCME_ERROR;
11655 goto fail;
11656 }
11657
11658 /* Parse IEs */
11659 if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) {
11660 WL_ERR(("Parse IEs failed \n"));
11661 goto fail;
11662 }
11663
11664 /* Set IEs to FW */
11665 if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
11666 WL_ERR(("Set IEs failed \n"));
11667 goto fail;
11668 }
11669
11670 if (dev_role == NL80211_IFTYPE_AP) {
11671 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
11672 WL_ERR(("Hostapd update sec failed \n"));
11673 err = -EINVAL;
11674 goto fail;
11675 }
11676 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
11677 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
11678 wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
11679 WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
11680 if (pbc)
11681 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
11682 else
11683 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
11684 }
11685 }
11686
11687 fail:
11688 if (err) {
11689 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
11690 }
11691 return err;
11692 }
11693 #else
11694 static s32
11695 wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
11696 struct beacon_parameters *info)
11697 {
11698 s32 err = BCME_OK;
11699 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11700 s32 ie_offset = 0;
11701 s32 bssidx = 0;
11702 u32 dev_role = NL80211_IFTYPE_AP;
11703 struct parsed_ies ies;
11704 bcm_tlv_t *ssid_ie;
11705 bool pbc = 0;
11706 bool privacy;
11707 bool is_bss_up = 0;
11708 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11709
11710 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
11711 info->interval, info->dtim_period, info->head_len, info->tail_len));
11712
11713 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
11714 dev_role = NL80211_IFTYPE_AP;
11715 }
11716 #if defined(WL_ENABLE_P2P_IF)
11717 else if (dev == cfg->p2p_net) {
11718 /* Group Add request on p2p0 */
11719 dev = bcmcfg_to_prmry_ndev(cfg);
11720 dev_role = NL80211_IFTYPE_P2P_GO;
11721 }
11722 #endif /* WL_ENABLE_P2P_IF */
11723
11724 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11725 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11726 return BCME_ERROR;
11727 }
11728
11729 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
11730 dev_role = NL80211_IFTYPE_P2P_GO;
11731 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
11732 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
11733 }
11734
11735 if (!check_dev_role_integrity(cfg, dev_role)) {
11736 err = -ENODEV;
11737 goto fail;
11738 }
11739
11740 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
11741 WL_ERR(("P2P already down status!\n"));
11742 err = BCME_ERROR;
11743 goto fail;
11744 }
11745
11746 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
11747 /* find the SSID */
11748 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
11749 info->head_len - ie_offset,
11750 DOT11_MNG_SSID_ID)) != NULL) {
11751 if (dev_role == NL80211_IFTYPE_AP) {
11752 /* Store the hostapd SSID */
11753 memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
11754 cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
11755 memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
11756 cfg->hostapd_ssid.SSID_len);
11757 } else {
11758 /* P2P GO */
11759 memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
11760 cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
11761 memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
11762 cfg->p2p->ssid.SSID_len);
11763 }
11764 }
11765
11766 if (wl_cfg80211_parse_ies((u8 *)info->tail,
11767 info->tail_len, &ies) < 0) {
11768 WL_ERR(("Beacon get IEs failed \n"));
11769 err = -EINVAL;
11770 goto fail;
11771 }
11772
11773 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
11774 VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
11775 info->tail_len)) < 0) {
11776 WL_ERR(("Beacon set IEs failed \n"));
11777 goto fail;
11778 } else {
11779 WL_DBG(("Applied Vndr IEs for Beacon \n"));
11780 }
11781
11782 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
11783 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
11784 VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies,
11785 info->proberesp_ies_len)) < 0) {
11786 WL_ERR(("ProbeRsp set IEs failed \n"));
11787 goto fail;
11788 } else {
11789 WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
11790 }
11791 #endif // endif
11792
11793 is_bss_up = wl_cfg80211_bss_isup(dev, bssidx);
11794
11795 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
11796 privacy = info->privacy;
11797 #else
11798 privacy = 0;
11799 #endif // endif
11800 if (!is_bss_up &&
11801 (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx, privacy) < 0))
11802 {
11803 WL_ERR(("Beacon set security failed \n"));
11804 err = -EINVAL;
11805 goto fail;
11806 }
11807
11808 /* Set BI and DTIM period */
11809 if (info->interval) {
11810 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
11811 &info->interval, sizeof(s32))) < 0) {
11812 WL_ERR(("Beacon Interval Set Error, %d\n", err));
11813 return err;
11814 }
11815 }
11816 if (info->dtim_period) {
11817 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
11818 &info->dtim_period, sizeof(s32))) < 0) {
11819 WL_ERR(("DTIM Interval Set Error, %d\n", err));
11820 return err;
11821 }
11822 }
11823
11824 /* If bss is already up, skip bring up */
11825 if (!is_bss_up &&
11826 (err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0)
11827 {
11828 WL_ERR(("Beacon bring up AP/GO failed \n"));
11829 goto fail;
11830 }
11831
11832 /* Set GC/STA SCB expiry timings. */
11833 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
11834 WL_ERR(("scb setting failed \n"));
11835 goto fail;
11836 }
11837
11838 if (wl_get_drv_status(cfg, AP_CREATED, dev)) {
11839 /* Soft AP already running. Update changed params */
11840 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
11841 WL_ERR(("Hostapd update sec failed \n"));
11842 err = -EINVAL;
11843 goto fail;
11844 }
11845 }
11846
11847 /* Enable Probe Req filter */
11848 if (((dev_role == NL80211_IFTYPE_P2P_GO) ||
11849 (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) {
11850 wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
11851 if (pbc)
11852 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
11853 }
11854
11855 WL_DBG(("** ADD/SET beacon done **\n"));
11856 wl_set_drv_status(cfg, CONNECTED, dev);
11857
11858 fail:
11859 if (err) {
11860 WL_ERR(("ADD/SET beacon failed\n"));
11861 if (dev_role == NL80211_IFTYPE_AP) {
11862 /* clear the AP mode */
11863 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
11864 }
11865 }
11866 return err;
11867
11868 }
11869
11870 static s32
11871 wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
11872 {
11873 int err = 0;
11874 s32 bssidx = 0;
11875 int infra = 0;
11876 struct wireless_dev *wdev = dev->ieee80211_ptr;
11877 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11878 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11879
11880 WL_DBG(("Enter. \n"));
11881
11882 if (!wdev) {
11883 WL_ERR(("wdev null \n"));
11884 return -EINVAL;
11885 }
11886
11887 if ((wdev->iftype != NL80211_IFTYPE_P2P_GO) && (wdev->iftype != NL80211_IFTYPE_AP)) {
11888 WL_ERR(("Unspported iface type iftype:%d \n", wdev->iftype));
11889 }
11890
11891 wl_clr_drv_status(cfg, AP_CREATING, dev);
11892 wl_clr_drv_status(cfg, AP_CREATED, dev);
11893
11894 /* Clear AP/GO connected status */
11895 wl_clr_drv_status(cfg, CONNECTED, dev);
11896
11897 cfg->ap_oper_channel = 0;
11898
11899 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11900 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11901 return BCME_ERROR;
11902 }
11903
11904 /* Do bss down */
11905 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
11906 WL_ERR(("bss down error %d\n", err));
11907 }
11908
11909 /* fall through is intentional */
11910 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11911 if (err < 0) {
11912 WL_ERR(("SET INFRA error %d\n", err));
11913 }
11914 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
11915
11916 if (wdev->iftype == NL80211_IFTYPE_AP) {
11917 /* clear the AP mode */
11918 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
11919 }
11920
11921 return 0;
11922 }
11923 #endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11924
11925 #ifdef WL_SCHED_SCAN
11926 #define PNO_TIME 30
11927 #define PNO_REPEAT 4
11928 #define PNO_FREQ_EXPO_MAX 2
11929 static bool
11930 is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count)
11931 {
11932 int i;
11933
11934 if (!ssid || !ssid_list)
11935 return FALSE;
11936
11937 for (i = 0; i < count; i++) {
11938 if (ssid->ssid_len == ssid_list[i].ssid_len) {
11939 if (strncmp(ssid->ssid, ssid_list[i].ssid, ssid->ssid_len) == 0)
11940 return TRUE;
11941 }
11942 }
11943 return FALSE;
11944 }
11945
11946 static int
11947 wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
11948 struct net_device *dev,
11949 struct cfg80211_sched_scan_request *request)
11950 {
11951 ushort pno_time = PNO_TIME;
11952 int pno_repeat = PNO_REPEAT;
11953 int pno_freq_expo_max = PNO_FREQ_EXPO_MAX;
11954 wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
11955 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11956 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11957 struct cfg80211_ssid *ssid = NULL;
11958 struct cfg80211_ssid *hidden_ssid_list = NULL;
11959 log_conn_event_t *event_data = NULL;
11960 tlv_log *tlv_data = NULL;
11961 u32 alloc_len, tlv_len;
11962 u32 payload_len;
11963 int ssid_cnt = 0;
11964 int i;
11965 int ret = 0;
11966 unsigned long flags;
11967
11968 if (!request) {
11969 WL_ERR(("Sched scan request was NULL\n"));
11970 return -EINVAL;
11971 }
11972
11973 WL_DBG(("Enter \n"));
11974 WL_PNO((">>> SCHED SCAN START\n"));
11975 WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n",
11976 request->n_match_sets, request->n_ssids));
11977 WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
11978 request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
11979
11980 if (!request->n_ssids || !request->n_match_sets) {
11981 WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids));
11982 return -EINVAL;
11983 }
11984
11985 memset(&ssids_local, 0, sizeof(ssids_local));
11986
11987 if (request->n_ssids > 0) {
11988 hidden_ssid_list = request->ssids;
11989 }
11990
11991 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
11992 alloc_len = sizeof(log_conn_event_t) + DOT11_MAX_SSID_LEN;
11993 event_data = (log_conn_event_t *)MALLOC(cfg->osh, alloc_len);
11994 if (!event_data) {
11995 WL_ERR(("%s: failed to allocate log_conn_event_t with "
11996 "length(%d)\n", __func__, alloc_len));
11997 return -ENOMEM;
11998 }
11999 memset(event_data, 0, alloc_len);
12000 event_data->tlvs = NULL;
12001 tlv_len = sizeof(tlv_log);
12002 event_data->tlvs = (tlv_log *)MALLOC(cfg->osh, tlv_len);
12003 if (!event_data->tlvs) {
12004 WL_ERR(("%s: failed to allocate log_tlv with "
12005 "length(%d)\n", __func__, tlv_len));
12006 MFREE(cfg->osh, event_data, alloc_len);
12007 return -ENOMEM;
12008 }
12009 }
12010 for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) {
12011 ssid = &request->match_sets[i].ssid;
12012 /* No need to include null ssid */
12013 if (ssid->ssid_len) {
12014 ssids_local[ssid_cnt].SSID_len = MIN(ssid->ssid_len,
12015 (uint32)DOT11_MAX_SSID_LEN);
12016 memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid,
12017 ssids_local[ssid_cnt].SSID_len);
12018 if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) {
12019 ssids_local[ssid_cnt].hidden = TRUE;
12020 WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid));
12021 } else {
12022 ssids_local[ssid_cnt].hidden = FALSE;
12023 WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid->ssid));
12024 }
12025 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 15, 0))
12026 if (request->match_sets[i].rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) {
12027 ssids_local[ssid_cnt].rssi_thresh =
12028 (int8)request->match_sets[i].rssi_thold;
12029 }
12030 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 15, 0)) */
12031 ssid_cnt++;
12032 }
12033 }
12034
12035 if (ssid_cnt) {
12036 if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, ssid_cnt,
12037 pno_time, pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) {
12038 WL_ERR(("PNO setup failed!! ret=%d \n", ret));
12039 ret = -EINVAL;
12040 goto exit;
12041 }
12042
12043 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
12044 for (i = 0; i < ssid_cnt; i++) {
12045 payload_len = sizeof(log_conn_event_t);
12046 event_data->event = WIFI_EVENT_DRIVER_PNO_ADD;
12047 tlv_data = event_data->tlvs;
12048 /* ssid */
12049 tlv_data->tag = WIFI_TAG_SSID;
12050 tlv_data->len = ssids_local[i].SSID_len;
12051 memcpy(tlv_data->value, ssids_local[i].SSID,
12052 ssids_local[i].SSID_len);
12053 payload_len += TLV_LOG_SIZE(tlv_data);
12054
12055 dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
12056 event_data, payload_len);
12057 }
12058 }
12059
12060 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
12061 cfg->sched_scan_req = request;
12062 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
12063 } else {
12064 ret = -EINVAL;
12065 }
12066 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \
12067 defined(SUPPORT_RANDOM_MAC_SCAN)
12068 if (!ETHER_ISNULLADDR(request->mac_addr) && !ETHER_ISNULLADDR(request->mac_addr_mask)) {
12069 ret = wl_cfg80211_scan_mac_enable(dev, request->mac_addr, request->mac_addr_mask);
12070 /* Ignore if chip doesnt support the feature */
12071 if (ret < 0) {
12072 if (ret == BCME_UNSUPPORTED) {
12073 /* If feature is not supported, ignore the error (legacy chips) */
12074 ret = BCME_OK;
12075 } else {
12076 WL_ERR(("set random mac failed (%d). Ignore.\n", ret));
12077 /* Cleanup the states and stop the pno */
12078 if (dhd_dev_pno_stop_for_ssid(dev) < 0) {
12079 WL_ERR(("PNO Stop for SSID failed"));
12080 }
12081 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
12082 cfg->sched_scan_req = NULL;
12083 cfg->sched_scan_running = FALSE;
12084 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
12085 }
12086 }
12087 }
12088 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && (defined(SUPPORT_RANDOM_MAC_SCAN)) */
12089 exit:
12090 if (event_data) {
12091 MFREE(cfg->osh, event_data->tlvs, tlv_len);
12092 MFREE(cfg->osh, event_data, alloc_len);
12093 }
12094 return ret;
12095 }
12096
12097 static int
12098 wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
12099 {
12100 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12101 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12102 unsigned long flags;
12103
12104 WL_DBG(("Enter \n"));
12105 WL_PNO((">>> SCHED SCAN STOP\n"));
12106
12107 if (dhd_dev_pno_stop_for_ssid(dev) < 0) {
12108 WL_ERR(("PNO Stop for SSID failed"));
12109 } else {
12110 DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_REMOVE);
12111 }
12112
12113 if (cfg->scan_request && cfg->sched_scan_running) {
12114 WL_PNO((">>> Sched scan running. Aborting it..\n"));
12115 wl_cfg80211_cancel_scan(cfg);
12116 }
12117 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
12118 cfg->sched_scan_req = NULL;
12119 cfg->sched_scan_running = FALSE;
12120 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
12121 return 0;
12122 }
12123 #endif /* WL_SCHED_SCAN */
12124
12125 #ifdef WL_SUPPORT_ACS
12126 /*
12127 * Currently the dump_obss IOVAR is returning string as output so we need to
12128 * parse the output buffer in an unoptimized way. Going forward if we get the
12129 * IOVAR output in binary format this method can be optimized
12130 */
12131 static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
12132 {
12133 int i;
12134 char *token;
12135 char delim[] = " \n";
12136
12137 token = strsep(&buf, delim);
12138 while (token != NULL) {
12139 if (!strcmp(token, "OBSS")) {
12140 for (i = 0; i < OBSS_TOKEN_IDX; i++)
12141 token = strsep(&buf, delim);
12142 survey->obss = simple_strtoul(token, NULL, 10);
12143 }
12144
12145 if (!strcmp(token, "IBSS")) {
12146 for (i = 0; i < IBSS_TOKEN_IDX; i++)
12147 token = strsep(&buf, delim);
12148 survey->ibss = simple_strtoul(token, NULL, 10);
12149 }
12150
12151 if (!strcmp(token, "TXDur")) {
12152 for (i = 0; i < TX_TOKEN_IDX; i++)
12153 token = strsep(&buf, delim);
12154 survey->tx = simple_strtoul(token, NULL, 10);
12155 }
12156
12157 if (!strcmp(token, "Category")) {
12158 for (i = 0; i < CTG_TOKEN_IDX; i++)
12159 token = strsep(&buf, delim);
12160 survey->no_ctg = simple_strtoul(token, NULL, 10);
12161 }
12162
12163 if (!strcmp(token, "Packet")) {
12164 for (i = 0; i < PKT_TOKEN_IDX; i++)
12165 token = strsep(&buf, delim);
12166 survey->no_pckt = simple_strtoul(token, NULL, 10);
12167 }
12168
12169 if (!strcmp(token, "Opp(time):")) {
12170 for (i = 0; i < IDLE_TOKEN_IDX; i++)
12171 token = strsep(&buf, delim);
12172 survey->idle = simple_strtoul(token, NULL, 10);
12173 }
12174
12175 token = strsep(&buf, delim);
12176 }
12177
12178 return 0;
12179 }
12180
12181 static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
12182 struct wl_dump_survey *survey)
12183 {
12184 cca_stats_n_flags *results;
12185 char *buf;
12186 int retry, err;
12187 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
12188
12189 buf = (char *)MALLOCZ(cfg->osh, sizeof(char) * WLC_IOCTL_MAXLEN);
12190 if (unlikely(!buf)) {
12191 WL_ERR(("%s: buf alloc failed\n", __func__));
12192 return -ENOMEM;
12193 }
12194
12195 retry = IOCTL_RETRY_COUNT;
12196 while (retry--) {
12197 err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req),
12198 buf, WLC_IOCTL_MAXLEN, NULL);
12199 if (err >= 0) {
12200 break;
12201 }
12202 WL_DBG(("attempt = %d, err = %d, \n",
12203 (IOCTL_RETRY_COUNT - retry), err));
12204 }
12205
12206 if (retry <= 0) {
12207 WL_ERR(("failure, dump_obss IOVAR failed\n"));
12208 err = -EINVAL;
12209 goto exit;
12210 }
12211
12212 results = (cca_stats_n_flags *)(buf);
12213 wl_parse_dump_obss(results->buf, survey);
12214 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
12215
12216 return 0;
12217 exit:
12218 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
12219 return err;
12220 }
12221
12222 static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
12223 int idx, struct survey_info *info)
12224 {
12225 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12226 struct wl_dump_survey *survey;
12227 struct ieee80211_supported_band *band;
12228 struct ieee80211_channel*chan;
12229 cca_msrmnt_query req;
12230 int val, err, noise, retry;
12231
12232 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12233 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
12234 return -ENOENT;
12235 }
12236 band = wiphy->bands[NL80211_BAND_2GHZ];
12237 if (band && idx >= band->n_channels) {
12238 idx -= band->n_channels;
12239 band = NULL;
12240 }
12241
12242 if (!band || idx >= band->n_channels) {
12243 /* Move to 5G band */
12244 band = wiphy->bands[NL80211_BAND_5GHZ];
12245 if (idx >= band->n_channels) {
12246 return -ENOENT;
12247 }
12248 }
12249
12250 chan = &band->channels[idx];
12251 /* Setting current channel to the requested channel */
12252 if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan,
12253 NL80211_CHAN_HT20) < 0)) {
12254 WL_ERR(("Set channel failed \n"));
12255 }
12256
12257 if (!idx) {
12258 /* Set interface up, explicitly. */
12259 val = 1;
12260 err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
12261 if (err < 0) {
12262 WL_ERR(("set interface up failed, error = %d\n", err));
12263 }
12264 }
12265
12266 /* Get noise value */
12267 retry = IOCTL_RETRY_COUNT;
12268 while (retry--) {
12269 noise = 0;
12270 err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise,
12271 sizeof(noise));
12272 if (err >= 0) {
12273 break;
12274 }
12275 WL_DBG(("attempt = %d, err = %d, \n",
12276 (IOCTL_RETRY_COUNT - retry), err));
12277 }
12278
12279 if (retry <= 0) {
12280 WL_ERR(("Get Phy Noise failed, error = %d\n", err));
12281 noise = CHAN_NOISE_DUMMY;
12282 }
12283
12284 survey = (struct wl_dump_survey *)MALLOCZ(cfg->osh,
12285 sizeof(struct wl_dump_survey));
12286 if (unlikely(!survey)) {
12287 WL_ERR(("%s: alloc failed\n", __func__));
12288 return -ENOMEM;
12289 }
12290
12291 /* Start Measurement for obss stats on current channel */
12292 req.msrmnt_query = 0;
12293 req.time_req = ACS_MSRMNT_DELAY;
12294 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
12295 goto exit;
12296 }
12297
12298 /*
12299 * Wait for the meaurement to complete, adding a buffer value of 10 to take
12300 * into consideration any delay in IOVAR completion
12301 */
12302 msleep(ACS_MSRMNT_DELAY + 10);
12303
12304 /* Issue IOVAR to collect measurement results */
12305 req.msrmnt_query = 1;
12306 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
12307 goto exit;
12308 }
12309
12310 info->channel = chan;
12311 info->noise = noise;
12312 info->channel_time = ACS_MSRMNT_DELAY;
12313 info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
12314 info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg +
12315 survey->no_pckt;
12316 info->channel_time_tx = survey->tx;
12317 info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
12318 SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
12319 SURVEY_INFO_CHANNEL_TIME_TX;
12320 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
12321
12322 return 0;
12323 exit:
12324 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
12325 return err;
12326 }
12327 #endif /* WL_SUPPORT_ACS */
12328
12329 static struct cfg80211_ops wl_cfg80211_ops = {
12330 .add_virtual_intf = wl_cfg80211_add_virtual_iface,
12331 .del_virtual_intf = wl_cfg80211_del_virtual_iface,
12332 .change_virtual_intf = wl_cfg80211_change_virtual_iface,
12333 #if defined(WL_CFG80211_P2P_DEV_IF)
12334 .start_p2p_device = wl_cfgp2p_start_p2p_device,
12335 .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
12336 #endif /* WL_CFG80211_P2P_DEV_IF */
12337 .scan = wl_cfg80211_scan,
12338 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
12339 .abort_scan = wl_cfg80211_abort_scan,
12340 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
12341 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
12342 .join_ibss = wl_cfg80211_join_ibss,
12343 .leave_ibss = wl_cfg80211_leave_ibss,
12344 .get_station = wl_cfg80211_get_station,
12345 .set_tx_power = wl_cfg80211_set_tx_power,
12346 .get_tx_power = wl_cfg80211_get_tx_power,
12347 .add_key = wl_cfg80211_add_key,
12348 .del_key = wl_cfg80211_del_key,
12349 .get_key = wl_cfg80211_get_key,
12350 .set_default_key = wl_cfg80211_config_default_key,
12351 .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
12352 .set_power_mgmt = wl_cfg80211_set_power_mgmt,
12353 .connect = wl_cfg80211_connect,
12354 .disconnect = wl_cfg80211_disconnect,
12355 .suspend = wl_cfg80211_suspend,
12356 .resume = wl_cfg80211_resume,
12357 .set_pmksa = wl_cfg80211_set_pmksa,
12358 .del_pmksa = wl_cfg80211_del_pmksa,
12359 .flush_pmksa = wl_cfg80211_flush_pmksa,
12360 .remain_on_channel = wl_cfg80211_remain_on_channel,
12361 .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
12362 .mgmt_tx = wl_cfg80211_mgmt_tx,
12363 .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
12364 .change_bss = wl_cfg80211_change_bss,
12365 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS)
12366 .set_channel = wl_cfg80211_set_channel,
12367 #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
12368 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS)
12369 .set_beacon = wl_cfg80211_add_set_beacon,
12370 .add_beacon = wl_cfg80211_add_set_beacon,
12371 .del_beacon = wl_cfg80211_del_beacon,
12372 #else
12373 .change_beacon = wl_cfg80211_change_beacon,
12374 .start_ap = wl_cfg80211_start_ap,
12375 .stop_ap = wl_cfg80211_stop_ap,
12376 #endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
12377 #ifdef WL_SCHED_SCAN
12378 .sched_scan_start = wl_cfg80211_sched_scan_start,
12379 .sched_scan_stop = wl_cfg80211_sched_scan_stop,
12380 #endif /* WL_SCHED_SCAN */
12381 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
12382 2, 0))
12383 .del_station = wl_cfg80211_del_station,
12384 .change_station = wl_cfg80211_change_station,
12385 .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
12386 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
12387 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
12388 .tdls_mgmt = wl_cfg80211_tdls_mgmt,
12389 .tdls_oper = wl_cfg80211_tdls_oper,
12390 #endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
12391 #ifdef WL_SUPPORT_ACS
12392 .dump_survey = wl_cfg80211_dump_survey,
12393 #endif /* WL_SUPPORT_ACS */
12394 #ifdef WL_CFG80211_ACL
12395 .set_mac_acl = wl_cfg80211_set_mac_acl,
12396 #endif /* WL_CFG80211_ACL */
12397 #ifdef GTK_OFFLOAD_SUPPORT
12398 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
12399 .set_rekey_data = wl_cfg80211_set_rekey_data,
12400 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
12401 #endif /* GTK_OFFLOAD_SUPPORT */
12402 };
12403
12404 s32 wl_mode_to_nl80211_iftype(s32 mode)
12405 {
12406 s32 err = 0;
12407
12408 switch (mode) {
12409 case WL_MODE_BSS:
12410 return NL80211_IFTYPE_STATION;
12411 case WL_MODE_IBSS:
12412 return NL80211_IFTYPE_ADHOC;
12413 case WL_MODE_AP:
12414 return NL80211_IFTYPE_AP;
12415 default:
12416 return NL80211_IFTYPE_UNSPECIFIED;
12417 }
12418
12419 return err;
12420 }
12421
12422 #ifdef CONFIG_PM
12423 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
12424 static const struct wiphy_wowlan_support brcm_wowlan_support = {
12425 .flags = WIPHY_WOWLAN_ANY,
12426 .n_patterns = WL_WOWLAN_MAX_PATTERNS,
12427 .pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
12428 .pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
12429 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
12430 .max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
12431 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
12432 };
12433 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
12434 #endif /* CONFIG_PM */
12435
12436 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context)
12437 {
12438 s32 err = 0;
12439 #ifdef CONFIG_PM
12440 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
12441 struct cfg80211_wowlan *brcm_wowlan_config = NULL;
12442 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
12443 #endif /* CONFIG_PM */
12444
12445 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
12446 dhd_pub_t *dhd = (dhd_pub_t *)context;
12447 BCM_REFERENCE(dhd);
12448
12449 if (!dhd) {
12450 WL_ERR(("DHD is NULL!!"));
12451 err = -ENODEV;
12452 return err;
12453 }
12454 #endif // endif
12455
12456 wdev->wiphy =
12457 wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
12458 if (unlikely(!wdev->wiphy)) {
12459 WL_ERR(("Couldn not allocate wiphy device\n"));
12460 err = -ENOMEM;
12461 return err;
12462 }
12463 set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
12464 wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
12465 /* Report how many SSIDs Driver can support per Scan request */
12466 wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
12467 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
12468 #ifdef WL_SCHED_SCAN
12469 wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
12470 wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
12471 wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
12472 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
12473 #endif /* WL_SCHED_SCAN */
12474 wdev->wiphy->interface_modes =
12475 BIT(NL80211_IFTYPE_STATION)
12476 | BIT(NL80211_IFTYPE_ADHOC)
12477 #if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
12478 | BIT(NL80211_IFTYPE_MONITOR)
12479 #endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
12480 #if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
12481 | BIT(NL80211_IFTYPE_P2P_CLIENT)
12482 | BIT(NL80211_IFTYPE_P2P_GO)
12483 #endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
12484 #if defined(WL_CFG80211_P2P_DEV_IF)
12485 | BIT(NL80211_IFTYPE_P2P_DEVICE)
12486 #endif /* WL_CFG80211_P2P_DEV_IF */
12487 | BIT(NL80211_IFTYPE_AP);
12488
12489 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
12490 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
12491 WL_DBG(("Setting interface combinations for common mode\n"));
12492 wdev->wiphy->iface_combinations = common_iface_combinations;
12493 wdev->wiphy->n_iface_combinations =
12494 ARRAY_SIZE(common_iface_combinations);
12495 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
12496
12497 wdev->wiphy->bands[NL80211_BAND_2GHZ] = &__wl_band_2ghz;
12498
12499 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
12500 wdev->wiphy->cipher_suites = __wl_cipher_suites;
12501 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
12502 wdev->wiphy->max_remain_on_channel_duration = 5000;
12503 wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
12504 #ifndef WL_POWERSAVE_DISABLED
12505 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
12506 #else
12507 wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
12508 #endif /* !WL_POWERSAVE_DISABLED */
12509 wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
12510 WIPHY_FLAG_4ADDR_AP |
12511 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS)
12512 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
12513 #endif // endif
12514 WIPHY_FLAG_4ADDR_STATION;
12515 #if ((defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && ((LINUX_VERSION_CODE >= \
12516 KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)))
12517 /*
12518 * If FW ROAM flag is advertised, upper layer wouldn't provide
12519 * the bssid & freq in the connect command. This will result a
12520 * delay in initial connection time due to firmware doing a full
12521 * channel scan to figure out the channel & bssid. However kernel
12522 * ver >= 3.15, provides bssid_hint & freq_hint and hence kernel
12523 * ver >= 3.15 won't have any issue. So if this flags need to be
12524 * advertised for kernel < 3.15, suggest to use RCC along with it
12525 * to avoid the initial connection delay.
12526 */
12527 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
12528 #endif /* (ROAM_ENABLE || BCMFW_ROAM_ENABLE) && (LINUX_VERSION 3.2.0 || WL_COMPAT_WIRELESS) */
12529 #ifdef UNSET_FW_ROAM_WIPHY_FLAG
12530 wdev->wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_FW_ROAM;
12531 #endif /* UNSET_FW_ROAM_WIPHY_FLAG */
12532 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
12533 wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
12534 WIPHY_FLAG_OFFCHAN_TX;
12535 #endif // endif
12536 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
12537 4, 0))
12538 /* From 3.4 kernel ownards AP_SME flag can be advertised
12539 * to remove the patch from supplicant
12540 */
12541 wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
12542
12543 #ifdef WL_CFG80211_ACL
12544 /* Configure ACL capabilities. */
12545 wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
12546 #endif // endif
12547
12548 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
12549 /* Supplicant distinguish between the SoftAP mode and other
12550 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
12551 * response frame from Supplicant MR1 and Kernel 3.4.0 or
12552 * later version. To add Vendor specific IE into the
12553 * probe response frame in case of SoftAP mode,
12554 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
12555 */
12556 if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
12557 wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
12558 wdev->wiphy->probe_resp_offload = 0;
12559 }
12560 #endif // endif
12561 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
12562
12563 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
12564 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
12565 #endif // endif
12566
12567 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
12568 /*
12569 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
12570 * disconnection of connected network before suspend. So a dummy wowlan
12571 * filter is configured for kernels linux-3.8 and above.
12572 */
12573
12574 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
12575 wdev->wiphy->wowlan = &brcm_wowlan_support;
12576 /* If this is not provided cfg stack will get disconnect
12577 * during suspend.
12578 */
12579 brcm_wowlan_config = MALLOC(dhd->osh, sizeof(struct cfg80211_wowlan));
12580 if (brcm_wowlan_config) {
12581 brcm_wowlan_config->disconnect = true;
12582 brcm_wowlan_config->gtk_rekey_failure = true;
12583 brcm_wowlan_config->eap_identity_req = true;
12584 brcm_wowlan_config->four_way_handshake = true;
12585 brcm_wowlan_config->patterns = NULL;
12586 brcm_wowlan_config->n_patterns = 0;
12587 brcm_wowlan_config->tcp = NULL;
12588 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12589 brcm_wowlan_config->nd_config = NULL;
12590 #endif // endif
12591 } else {
12592 WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
12593 " So wiphy->wowlan_config is set to NULL\n"));
12594 }
12595 wdev->wiphy->wowlan_config = brcm_wowlan_config;
12596 #else
12597 wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
12598 wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
12599 wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
12600 wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
12601 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
12602 wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
12603 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
12604 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
12605 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
12606
12607 WL_DBG(("Registering custom regulatory)\n"));
12608 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
12609 wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
12610 #else
12611 wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
12612 #endif // endif
12613 wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
12614
12615 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
12616 WL_INFORM_MEM(("Registering Vendor80211\n"));
12617 err = wl_cfgvendor_attach(wdev->wiphy, dhd);
12618 if (unlikely(err < 0)) {
12619 WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
12620 }
12621 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
12622
12623 /* Now we can register wiphy with cfg80211 module */
12624 err = wiphy_register(wdev->wiphy);
12625 if (unlikely(err < 0)) {
12626 WL_ERR(("Couldn not register wiphy device (%d)\n", err));
12627 wiphy_free(wdev->wiphy);
12628 }
12629
12630 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
12631 KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
12632 wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
12633 #endif // endif
12634
12635 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) && defined(SUPPORT_RANDOM_MAC_SCAN)
12636 wdev->wiphy->features |= (NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
12637 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR);
12638 wdev->wiphy->max_sched_scan_plans = 1; /* multiple plans not supported */
12639 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) */
12640
12641 return err;
12642 }
12643
12644 static void wl_free_wdev(struct bcm_cfg80211 *cfg)
12645 {
12646 struct wireless_dev *wdev = cfg->wdev;
12647 struct wiphy *wiphy = NULL;
12648 if (!wdev) {
12649 WL_ERR(("wdev is invalid\n"));
12650 return;
12651 }
12652 if (wdev->wiphy) {
12653 wiphy = wdev->wiphy;
12654
12655 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
12656 wl_cfgvendor_detach(wdev->wiphy);
12657 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
12658 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
12659 /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
12660 WL_DBG(("wl_free_wdev Clearing wowlan Config \n"));
12661 if (wdev->wiphy->wowlan_config) {
12662 MFREE(cfg->osh, wdev->wiphy->wowlan_config,
12663 sizeof(struct cfg80211_wowlan));
12664 wdev->wiphy->wowlan_config = NULL;
12665 }
12666 wdev->wiphy->wowlan = NULL;
12667 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
12668 wiphy_unregister(wdev->wiphy);
12669 wdev->wiphy->dev.parent = NULL;
12670 wdev->wiphy = NULL;
12671 }
12672
12673 wl_delete_all_netinfo(cfg);
12674 if (wiphy) {
12675 MFREE(cfg->osh, wdev, sizeof(*wdev));
12676 wiphy_free(wiphy);
12677 }
12678
12679 /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
12680 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
12681 */
12682 }
12683
12684 static s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
12685 {
12686 struct wl_scan_results *bss_list;
12687 wl_bss_info_t *bi = NULL; /* must be initialized */
12688 s32 err = 0;
12689 s32 i;
12690
12691 bss_list = cfg->bss_list;
12692 WL_MEM(("scanned AP count (%d)\n", bss_list->count));
12693 #ifdef ESCAN_CHANNEL_CACHE
12694 reset_roam_cache(cfg);
12695 #endif /* ESCAN_CHANNEL_CACHE */
12696 preempt_disable();
12697 bi = next_bss(bss_list, bi);
12698 for_each_bss(bss_list, bi, i) {
12699 #ifdef ESCAN_CHANNEL_CACHE
12700 add_roam_cache(cfg, bi);
12701 #endif /* ESCAN_CHANNEL_CACHE */
12702 err = wl_inform_single_bss(cfg, bi, false);
12703 if (unlikely(err)) {
12704 WL_ERR(("bss inform failed\n"));
12705 }
12706 }
12707 preempt_enable();
12708 WL_MEM(("cfg80211 scan cache updated\n"));
12709 #ifdef ROAM_CHANNEL_CACHE
12710 /* print_roam_cache(); */
12711 update_roam_cache(cfg, ioctl_version);
12712 #endif /* ROAM_CHANNEL_CACHE */
12713 return err;
12714 }
12715
12716 static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool roam)
12717 {
12718 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
12719 struct ieee80211_mgmt *mgmt;
12720 struct ieee80211_channel *channel;
12721 struct ieee80211_supported_band *band;
12722 struct wl_cfg80211_bss_info *notif_bss_info;
12723 struct wl_scan_req *sr = wl_to_sr(cfg);
12724 struct beacon_proberesp *beacon_proberesp;
12725 struct cfg80211_bss *cbss = NULL;
12726 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12727 log_conn_event_t *event_data = NULL;
12728 tlv_log *tlv_data = NULL;
12729 u32 alloc_len, tlv_len;
12730 u32 payload_len;
12731 s32 mgmt_type;
12732 s32 signal;
12733 u32 freq;
12734 s32 err = 0;
12735 gfp_t aflags;
12736 u8 tmp_buf[IEEE80211_MAX_SSID_LEN + 1];
12737
12738 if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
12739 WL_DBG(("Beacon is larger than buffer. Discarding\n"));
12740 return err;
12741 }
12742
12743 if (bi->SSID_len > IEEE80211_MAX_SSID_LEN) {
12744 WL_ERR(("wrong SSID len:%d\n", bi->SSID_len));
12745 return -EINVAL;
12746 }
12747
12748 aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
12749 notif_bss_info = (struct wl_cfg80211_bss_info *)MALLOCZ(cfg->osh,
12750 sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
12751 if (unlikely(!notif_bss_info)) {
12752 WL_ERR(("notif_bss_info alloc failed\n"));
12753 return -ENOMEM;
12754 }
12755 mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
12756 notif_bss_info->channel =
12757 wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
12758
12759 if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
12760 band = wiphy->bands[NL80211_BAND_2GHZ];
12761 else
12762 band = wiphy->bands[NL80211_BAND_5GHZ];
12763 if (!band) {
12764 WL_ERR(("No valid band"));
12765 MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
12766 + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
12767 return -EINVAL;
12768 }
12769 notif_bss_info->rssi = wl_rssi_offset(dtoh16(bi->RSSI));
12770 memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
12771 mgmt_type = cfg->active_scan ?
12772 IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
12773 if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
12774 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type);
12775 }
12776 beacon_proberesp = cfg->active_scan ?
12777 (struct beacon_proberesp *)&mgmt->u.probe_resp :
12778 (struct beacon_proberesp *)&mgmt->u.beacon;
12779 beacon_proberesp->timestamp = 0;
12780 beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
12781 beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
12782 wl_rst_ie(cfg);
12783 wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, roam);
12784 wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
12785 wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX -
12786 offsetof(struct wl_cfg80211_bss_info, frame_buf));
12787 notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
12788 u.beacon.variable) + wl_get_ielen(cfg);
12789 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
12790 freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
12791 (void)band->band;
12792 #else
12793 freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
12794 #endif // endif
12795 if (freq == 0) {
12796 WL_ERR(("Invalid channel, fail to chcnage channel to freq\n"));
12797 MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
12798 + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
12799 return -EINVAL;
12800 }
12801 channel = ieee80211_get_channel(wiphy, freq);
12802 if (unlikely(!channel)) {
12803 WL_ERR(("ieee80211_get_channel error\n"));
12804 MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
12805 + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
12806 return -EINVAL;
12807 }
12808 memcpy(tmp_buf, bi->SSID, bi->SSID_len);
12809 tmp_buf[bi->SSID_len] = '\0';
12810 WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
12811 "mgmt_type %d frame_len %d\n", tmp_buf,
12812 notif_bss_info->rssi, notif_bss_info->channel,
12813 mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type,
12814 notif_bss_info->frame_len));
12815
12816 signal = notif_bss_info->rssi * 100;
12817 if (!mgmt->u.probe_resp.timestamp) {
12818 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
12819 struct timespec ts;
12820 get_monotonic_boottime(&ts);
12821 mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000)
12822 + ts.tv_nsec / 1000;
12823 #else
12824 struct timeval tv;
12825 do_gettimeofday(&tv);
12826 mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000)
12827 + tv.tv_usec;
12828 #endif // endif
12829 }
12830
12831 cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
12832 le16_to_cpu(notif_bss_info->frame_len), signal, aflags);
12833 if (unlikely(!cbss)) {
12834 WL_ERR(("cfg80211_inform_bss_frame error bssid " MACDBG " channel %d \n",
12835 MAC2STRDBG((u8*)(&bi->BSSID)), notif_bss_info->channel));
12836 err = -EINVAL;
12837 goto out_err;
12838 }
12839
12840 CFG80211_PUT_BSS(wiphy, cbss);
12841
12842 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID) &&
12843 (cfg->sched_scan_req && !cfg->scan_request)) {
12844 alloc_len = sizeof(log_conn_event_t) + IEEE80211_MAX_SSID_LEN + sizeof(uint16) +
12845 sizeof(int16);
12846 event_data = (log_conn_event_t *)MALLOCZ(cfg->osh, alloc_len);
12847 if (!event_data) {
12848 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
12849 "length(%d)\n", __func__, alloc_len));
12850 goto out_err;
12851 }
12852 tlv_len = 3 * sizeof(tlv_log);
12853 event_data->tlvs = (tlv_log *)MALLOCZ(cfg->osh, tlv_len);
12854 if (!event_data->tlvs) {
12855 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
12856 "length(%d)\n", __func__, tlv_len));
12857 goto free_evt_data;
12858 }
12859
12860 payload_len = sizeof(log_conn_event_t);
12861 event_data->event = WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND;
12862 tlv_data = event_data->tlvs;
12863
12864 /* ssid */
12865 tlv_data->tag = WIFI_TAG_SSID;
12866 tlv_data->len = bi->SSID_len;
12867 memcpy(tlv_data->value, bi->SSID, bi->SSID_len);
12868 payload_len += TLV_LOG_SIZE(tlv_data);
12869 tlv_data = TLV_LOG_NEXT(tlv_data);
12870
12871 /* channel */
12872 tlv_data->tag = WIFI_TAG_CHANNEL;
12873 tlv_data->len = sizeof(uint16);
12874 memcpy(tlv_data->value, &notif_bss_info->channel, sizeof(uint16));
12875 payload_len += TLV_LOG_SIZE(tlv_data);
12876 tlv_data = TLV_LOG_NEXT(tlv_data);
12877
12878 /* rssi */
12879 tlv_data->tag = WIFI_TAG_RSSI;
12880 tlv_data->len = sizeof(int16);
12881 memcpy(tlv_data->value, &notif_bss_info->rssi, sizeof(int16));
12882 payload_len += TLV_LOG_SIZE(tlv_data);
12883 tlv_data = TLV_LOG_NEXT(tlv_data);
12884
12885 dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
12886 event_data, payload_len);
12887 MFREE(dhdp->osh, event_data->tlvs, tlv_len);
12888 free_evt_data:
12889 MFREE(dhdp->osh, event_data, alloc_len);
12890 }
12891
12892 out_err:
12893 MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
12894 + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
12895 return err;
12896 }
12897
12898 static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev)
12899 {
12900 u32 event = ntoh32(e->event_type);
12901 u32 status = ntoh32(e->status);
12902 u16 flags = ntoh16(e->flags);
12903 #if defined(CUSTOM_SET_OCLOFF) || defined(CUSTOM_SET_ANTNPM)
12904 dhd_pub_t *dhd;
12905 dhd = (dhd_pub_t *)(cfg->pub);
12906 #endif /* CUSTOM_SET_OCLOFF || CUSTOM_SET_ANTNPM */
12907
12908 WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
12909 if (event == WLC_E_SET_SSID) {
12910 if (status == WLC_E_STATUS_SUCCESS) {
12911 #ifdef CUSTOM_SET_OCLOFF
12912 if (dhd->ocl_off) {
12913 int err = 0;
12914 int ocl_enable = 0;
12915 err = wldev_iovar_setint(ndev, "ocl_enable", ocl_enable);
12916 if (err != 0) {
12917 WL_ERR(("[WIFI_SEC] %s: Set ocl_enable %d failed %d\n",
12918 __FUNCTION__, ocl_enable, err));
12919 } else {
12920 WL_ERR(("[WIFI_SEC] %s: Set ocl_enable %d succeeded %d\n",
12921 __FUNCTION__, ocl_enable, err));
12922 }
12923 }
12924 #endif /* CUSTOM_SET_OCLOFF */
12925 #ifdef CUSTOM_SET_ANTNPM
12926 if (dhd->mimo_ant_set) {
12927 int err = 0;
12928
12929 WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhd->mimo_ant_set));
12930 err = wldev_iovar_setint(ndev, "txchain", dhd->mimo_ant_set);
12931 if (err != 0) {
12932 WL_ERR(("[WIFI_SEC] Fail set txchain\n"));
12933 }
12934 err = wldev_iovar_setint(ndev, "rxchain", dhd->mimo_ant_set);
12935 if (err != 0) {
12936 WL_ERR(("[WIFI_SEC] Fail set rxchain\n"));
12937 }
12938 }
12939 #endif /* CUSTOM_SET_ANTNPM */
12940 if (!wl_is_ibssmode(cfg, ndev))
12941 return true;
12942 }
12943 } else if (event == WLC_E_LINK) {
12944 if (flags & WLC_EVENT_MSG_LINK)
12945 return true;
12946 }
12947
12948 WL_DBG(("wl_is_linkup false\n"));
12949 return false;
12950 }
12951
12952 #ifdef WL_LASTEVT
12953 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, void *data)
12954 {
12955 u32 event = ntoh32(e->event_type);
12956 u16 flags = ntoh16(e->flags);
12957 wl_last_event_t *last_event = (wl_last_event_t *)data;
12958 u32 len = ntoh32(e->datalen);
12959
12960 if (event == WLC_E_DEAUTH_IND ||
12961 event == WLC_E_DISASSOC_IND ||
12962 event == WLC_E_DISASSOC ||
12963 event == WLC_E_DEAUTH) {
12964 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
12965 return true;
12966 } else if (event == WLC_E_LINK) {
12967 if (!(flags & WLC_EVENT_MSG_LINK)) {
12968 if (last_event && len > 0) {
12969 u32 current_time = last_event->current_time;
12970 u32 timestamp = last_event->timestamp;
12971 u32 event_type = last_event->event.event_type;
12972 u32 status = last_event->event.status;
12973 u32 reason = last_event->event.reason;
12974
12975 WL_ERR(("Last roam event before disconnection : current_time %d,"
12976 " time %d, type %d, status %d, reason %d\n",
12977 current_time, timestamp, event_type, status, reason));
12978 }
12979 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
12980 return true;
12981 }
12982 }
12983
12984 return false;
12985 }
12986 #else
12987 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
12988 {
12989 u32 event = ntoh32(e->event_type);
12990 u16 flags = ntoh16(e->flags);
12991
12992 if (event == WLC_E_DEAUTH_IND ||
12993 event == WLC_E_DISASSOC_IND ||
12994 event == WLC_E_DISASSOC ||
12995 event == WLC_E_DEAUTH) {
12996 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
12997 return true;
12998 } else if (event == WLC_E_LINK) {
12999 if (!(flags & WLC_EVENT_MSG_LINK)) {
13000 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
13001 return true;
13002 }
13003 }
13004
13005 return false;
13006 }
13007 #endif /* WL_LASTEVT */
13008
13009 static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13010 {
13011 u32 event = ntoh32(e->event_type);
13012 u32 status = ntoh32(e->status);
13013
13014 if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS)
13015 return true;
13016 if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
13017 return true;
13018
13019 return false;
13020 }
13021
13022 /* The mainline kernel >= 3.2.0 has support for indicating new/del station
13023 * to AP/P2P GO via events. If this change is backported to kernel for which
13024 * this driver is being built, then define WL_CFG80211_STA_EVENT. You
13025 * should use this new/del sta event mechanism for BRCM supplicant >= 22.
13026 */
13027 static s32
13028 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13029 const wl_event_msg_t *e, void *data)
13030 {
13031 s32 err = 0;
13032 u32 event = ntoh32(e->event_type);
13033 u32 reason = ntoh32(e->reason);
13034 u32 len = ntoh32(e->datalen);
13035 u32 status = ntoh32(e->status);
13036
13037 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
13038 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
13039 bool isfree = false;
13040 u8 *mgmt_frame;
13041 u8 bsscfgidx = e->bsscfgidx;
13042 s32 freq;
13043 s32 channel;
13044 u8 *body = NULL;
13045 u16 fc = 0;
13046 u32 body_len = 0;
13047
13048 struct ieee80211_supported_band *band;
13049 struct ether_addr da;
13050 struct ether_addr bssid;
13051 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13052 channel_info_t ci;
13053 u8 ioctl_buf[WLC_IOCTL_SMLEN];
13054 #else
13055 struct station_info sinfo;
13056 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
13057 #ifdef BIGDATA_SOFTAP
13058 dhd_pub_t *dhdp;
13059 #endif /* BIGDATA_SOFTAP */
13060
13061 WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n",
13062 ndev->name, event, ntoh32(e->status), reason));
13063 /* if link down, bsscfg is disabled. */
13064 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
13065 wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
13066 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
13067 WL_INFORM_MEM(("AP mode link down !! \n"));
13068 complete(&cfg->iface_disable);
13069 return 0;
13070 }
13071
13072 if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
13073 (reason == WLC_E_REASON_INITIAL_ASSOC) &&
13074 (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
13075 if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
13076 /* AP/GO brought up successfull in firmware */
13077 WL_INFORM_MEM(("AP/GO Link up\n"));
13078 wl_set_drv_status(cfg, AP_CREATED, ndev);
13079 wake_up_interruptible(&cfg->netif_change_event);
13080 #ifdef BIGDATA_SOFTAP
13081 wl_ap_stainfo_init(cfg);
13082 #endif /* BIGDATA_SOFTAP */
13083 #ifdef WL_BCNRECV
13084 /* check fakeapscan is in progress, if progress then abort */
13085 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
13086 #endif /* WL_BCNRECV */
13087 return 0;
13088 }
13089 }
13090
13091 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
13092 WL_DBG(("event %s(%d) status %d reason %d\n",
13093 bcmevent_get_name(event), event, ntoh32(e->status), reason));
13094 }
13095
13096 #ifdef BIGDATA_SOFTAP
13097 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) {
13098 WL_ERR(("AP link down - skip get sta data\n"));
13099 } else {
13100 dhdp = (dhd_pub_t *)(cfg->pub);
13101 if (dhdp && dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
13102 dhd_schedule_gather_ap_stadata(cfg, ndev, e);
13103 }
13104 }
13105 #endif /* BIGDATA_SOFTAP */
13106
13107 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
13108 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
13109 WL_DBG(("Enter \n"));
13110 if (!len && (event == WLC_E_DEAUTH)) {
13111 len = 2; /* reason code field */
13112 data = &reason;
13113 }
13114 if (len) {
13115 body = (u8 *)MALLOCZ(cfg->osh, len);
13116 if (body == NULL) {
13117 WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
13118 return WL_INVALID;
13119 }
13120 }
13121 memset(&bssid, 0, ETHER_ADDR_LEN);
13122 WL_DBG(("Enter event %d ndev %p\n", event, ndev));
13123 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
13124 MFREE(cfg->osh, body, len);
13125 return WL_INVALID;
13126 }
13127 if (len)
13128 memcpy(body, data, len);
13129
13130 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
13131 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, NULL);
13132 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
13133 memset(&bssid, 0, sizeof(bssid));
13134 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
13135 switch (event) {
13136 case WLC_E_ASSOC_IND:
13137 fc = FC_ASSOC_REQ;
13138 break;
13139 case WLC_E_REASSOC_IND:
13140 fc = FC_REASSOC_REQ;
13141 break;
13142 case WLC_E_DISASSOC_IND:
13143 fc = FC_DISASSOC;
13144 break;
13145 case WLC_E_DEAUTH_IND:
13146 fc = FC_DISASSOC;
13147 break;
13148 case WLC_E_DEAUTH:
13149 fc = FC_DISASSOC;
13150 break;
13151 default:
13152 fc = 0;
13153 goto exit;
13154 }
13155 memset(&ci, 0, sizeof(ci));
13156 if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
13157 MFREE(cfg->osh, body, len);
13158 return err;
13159 }
13160
13161 channel = dtoh32(ci.hw_channel);
13162 if (channel <= CH_MAX_2G_CHANNEL)
13163 band = wiphy->bands[NL80211_BAND_2GHZ];
13164 else
13165 band = wiphy->bands[NL80211_BAND_5GHZ];
13166 if (!band) {
13167 WL_ERR(("No valid band"));
13168 if (body) {
13169 MFREE(cfg->osh, body, len);
13170 }
13171 return -EINVAL;
13172 }
13173 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
13174 freq = ieee80211_channel_to_frequency(channel);
13175 (void)band->band;
13176 #else
13177 freq = ieee80211_channel_to_frequency(channel, band->band);
13178 #endif // endif
13179 body_len = len;
13180 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
13181 &mgmt_frame, &len, body);
13182 if (err < 0)
13183 goto exit;
13184 isfree = true;
13185
13186 if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
13187 (event == WLC_E_DISASSOC_IND) ||
13188 ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
13189 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
13190 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
13191 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
13192 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
13193 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
13194 defined(WL_COMPAT_WIRELESS)
13195 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
13196 #else
13197 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
13198 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
13199 }
13200
13201 exit:
13202 if (isfree) {
13203 MFREE(cfg->osh, mgmt_frame, len);
13204 }
13205 if (body) {
13206 MFREE(cfg->osh, body, body_len);
13207 }
13208 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
13209 sinfo.filled = 0;
13210 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
13211 reason == DOT11_SC_SUCCESS) {
13212 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
13213 * STATION_INFO_ASSOC_REQ_IES flag
13214 */
13215 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
13216 sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
13217 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
13218 if (!data) {
13219 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
13220 return -EINVAL;
13221 }
13222 sinfo.assoc_req_ies = data;
13223 sinfo.assoc_req_ies_len = len;
13224 WL_INFORM_MEM(("[%s] new sta event for "MACDBG "\n",
13225 ndev->name, MAC2STRDBG(e->addr.octet)));
13226 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
13227 #ifdef WL_WPS_SYNC
13228 wl_wps_session_update(ndev, WPS_STATE_LINKUP, e->addr.octet);
13229 #endif /* WL_WPS_SYNC */
13230 } else if ((event == WLC_E_DEAUTH_IND) ||
13231 ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
13232 (event == WLC_E_DISASSOC_IND)) {
13233 WL_INFORM_MEM(("[%s] del sta event for "MACDBG "\n",
13234 ndev->name, MAC2STRDBG(e->addr.octet)));
13235 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
13236 #ifdef WL_WPS_SYNC
13237 wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet);
13238 #endif /* WL_WPS_SYNC */
13239 }
13240 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
13241 return err;
13242 }
13243
13244 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
13245 enum {
13246 BIGDATA_ASSOC_REJECT_NO_ACK = 1,
13247 BIGDATA_ASSOC_REJECT_FAIL = 2,
13248 BIGDATA_ASSOC_REJECT_UNSOLICITED = 3,
13249 BIGDATA_ASSOC_REJECT_TIMEOUT = 4,
13250 BIGDATA_ASSOC_REJECT_ABORT = 5,
13251 BIGDATA_ASSOC_REJECT_NO_NETWWORKS = 6,
13252 BIGDATA_ASSOC_REJECT_MAX = 50
13253 };
13254
13255 int wl_get_connect_failed_status(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13256 {
13257 u32 status = ntoh32(e->status);
13258
13259 cfg->assoc_reject_status = 0;
13260
13261 if (status != WLC_E_STATUS_SUCCESS) {
13262 WL_ERR(("auth assoc status event=%d e->status %d e->reason %d \n",
13263 ntoh32(cfg->event_auth_assoc.event_type),
13264 (int)ntoh32(cfg->event_auth_assoc.status),
13265 (int)ntoh32(cfg->event_auth_assoc.reason)));
13266
13267 switch ((int)ntoh32(cfg->event_auth_assoc.status)) {
13268 case WLC_E_STATUS_NO_ACK:
13269 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_NO_ACK;
13270 break;
13271 case WLC_E_STATUS_FAIL:
13272 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_FAIL;
13273 break;
13274 case WLC_E_STATUS_UNSOLICITED:
13275 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_UNSOLICITED;
13276 break;
13277 case WLC_E_STATUS_TIMEOUT:
13278 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_TIMEOUT;
13279 break;
13280 case WLC_E_STATUS_ABORT:
13281 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_ABORT;
13282 break;
13283 case WLC_E_STATUS_SUCCESS:
13284 if (status == WLC_E_STATUS_NO_NETWORKS) {
13285 cfg->assoc_reject_status =
13286 BIGDATA_ASSOC_REJECT_NO_NETWWORKS;
13287 break;
13288 }
13289 default:
13290 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_MAX;
13291 break;
13292 }
13293 if (cfg->assoc_reject_status) {
13294 if (ntoh32(cfg->event_auth_assoc.event_type) == WLC_E_ASSOC) {
13295 cfg->assoc_reject_status += BIGDATA_ASSOC_REJECT_MAX;
13296 }
13297 }
13298 }
13299
13300 WL_ERR(("assoc_reject_status %d \n", cfg->assoc_reject_status));
13301
13302 return 0;
13303 }
13304
13305 s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len)
13306 {
13307 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13308 int bytes_written = 0;
13309
13310 if (cfg == NULL) {
13311 return -1;
13312 }
13313 bytes_written = snprintf(cmd, total_len, "assoc_reject.status %d",
13314 cfg->assoc_reject_status);
13315 WL_ERR(("cmd: %s \n", cmd));
13316 return bytes_written;
13317 }
13318 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
13319
13320 static s32
13321 wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13322 const wl_event_msg_t *e)
13323 {
13324 u32 reason = ntoh32(e->reason);
13325 u32 event = ntoh32(e->event_type);
13326 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13327 WL_DBG(("event type : %d, reason : %d\n", event, reason));
13328
13329 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
13330 memcpy(&cfg->event_auth_assoc, e, sizeof(wl_event_msg_t));
13331 WL_ERR(("event=%d status %d reason %d \n",
13332 ntoh32(cfg->event_auth_assoc.event_type),
13333 ntoh32(cfg->event_auth_assoc.status),
13334 ntoh32(cfg->event_auth_assoc.reason)));
13335 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
13336 if (sec) {
13337 switch (event) {
13338 case WLC_E_ASSOC:
13339 case WLC_E_AUTH:
13340 sec->auth_assoc_res_status = reason;
13341 default:
13342 break;
13343 }
13344 } else
13345 WL_ERR(("sec is NULL\n"));
13346 return 0;
13347 }
13348
13349 static s32
13350 wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13351 const wl_event_msg_t *e, void *data)
13352 {
13353 s32 err = 0;
13354 u32 event = ntoh32(e->event_type);
13355 u16 flags = ntoh16(e->flags);
13356 u32 status = ntoh32(e->status);
13357 bool active;
13358 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
13359 struct ieee80211_channel *channel = NULL;
13360 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13361 u32 chanspec, chan;
13362 u32 freq, band;
13363 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13364
13365 if (event == WLC_E_JOIN) {
13366 WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev->name));
13367 }
13368 if (event == WLC_E_START) {
13369 WL_INFORM_MEM(("[%s] started IBSS network\n", ndev->name));
13370 }
13371 if (event == WLC_E_JOIN || event == WLC_E_START ||
13372 (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
13373 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
13374 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
13375 if (unlikely(err)) {
13376 WL_ERR(("Could not get chanspec %d\n", err));
13377 return err;
13378 }
13379 chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
13380 band = (chan <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
13381 freq = ieee80211_channel_to_frequency(chan, band);
13382 channel = ieee80211_get_channel(wiphy, freq);
13383 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13384 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
13385 /* ROAM or Redundant */
13386 u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13387 if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
13388 WL_DBG(("IBSS connected event from same BSSID("
13389 MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
13390 return err;
13391 }
13392 WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
13393 ndev->name, MAC2STRDBG(cur_bssid),
13394 MAC2STRDBG((const u8 *)&e->addr)));
13395 wl_get_assoc_ies(cfg, ndev);
13396 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
13397 wl_update_bss_info(cfg, ndev, false);
13398 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
13399 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
13400 #else
13401 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
13402 #endif // endif
13403 }
13404 else {
13405 /* New connection */
13406 WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG "\n",
13407 ndev->name, MAC2STRDBG((const u8 *)&e->addr)));
13408 wl_link_up(cfg);
13409 wl_get_assoc_ies(cfg, ndev);
13410 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
13411 wl_update_bss_info(cfg, ndev, false);
13412 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
13413 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
13414 #else
13415 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
13416 #endif // endif
13417 wl_set_drv_status(cfg, CONNECTED, ndev);
13418 active = true;
13419 wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
13420 }
13421 } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
13422 event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
13423 wl_clr_drv_status(cfg, CONNECTED, ndev);
13424 wl_link_down(cfg);
13425 wl_init_prof(cfg, ndev);
13426 }
13427 else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
13428 WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
13429 }
13430 else {
13431 WL_DBG(("no action (IBSS mode)\n"));
13432 }
13433 return err;
13434 }
13435
13436 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
13437 #define WiFiALL_OUI "\x50\x6F\x9A" /* Wi-FiAll OUI */
13438 #define WiFiALL_OUI_LEN 3
13439 #define WiFiALL_OUI_TYPE 16
13440
13441 /* 11kv feature flag for big data */
13442 #define WL_BIGDATA_11KV_QBSSLOAD 0x00000001
13443 #define WL_BIGDATA_11KV_PROXYARP 0x00000002
13444 #define WL_BIGDATA_11KV_TFS 0x00000004
13445 #define WL_BIGDATA_11KV_SLEEP 0x00000008
13446 #define WL_BIGDATA_11KV_TIMBC 0x00000010
13447 #define WL_BIGDATA_11KV_BSSTRANS 0x00000020
13448 #define WL_BIGDATA_11KV_DMS 0x00000040
13449 #define WL_BIGDATA_11KV_LINK_MEA 0x00000080
13450 #define WL_BIGDATA_11KV_NBRREP 0x00000100
13451 #define WL_BIGDATA_11KV_BCNPASSIVE 0x00000200
13452 #define WL_BIGDATA_11KV_BCNACTIVE 0x00000400
13453 #define WL_BIGDATA_11KV_BCNTABLE 0x00000800
13454 #define WL_BIGDATA_11KV_BSSAAD 0x00001000
13455 #define WL_BIGDATA_11KV_MAX 0x00002000
13456
13457 #define WL_BIGDATA_SUPPORT_11K 0x00000001
13458 #define WL_BIGDATA_SUPPORT_11V 0x00000002
13459
13460 typedef struct {
13461 uint8 bitmap;
13462 uint8 octet_len;
13463 uint32 flag;
13464 } bigdata_11kv_t;
13465
13466 bigdata_11kv_t bigdata_11k_info[] = {
13467 {DOT11_RRM_CAP_LINK, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_LINK_MEA},
13468 {DOT11_RRM_CAP_NEIGHBOR_REPORT, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_NBRREP},
13469 {DOT11_RRM_CAP_BCN_PASSIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNPASSIVE},
13470 {DOT11_RRM_CAP_BCN_ACTIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNACTIVE},
13471 {DOT11_RRM_CAP_BCN_TABLE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNTABLE},
13472 {DOT11_RRM_CAP_BSSAAD, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BSSAAD},
13473 };
13474
13475 bigdata_11kv_t bigdata_11v_info[] = {
13476 {DOT11_EXT_CAP_PROXY_ARP, DOT11_EXTCAP_LEN_PROXY_ARP, WL_BIGDATA_11KV_PROXYARP},
13477 {DOT11_EXT_CAP_TFS, DOT11_EXTCAP_LEN_TFS, WL_BIGDATA_11KV_TFS},
13478 {DOT11_EXT_CAP_WNM_SLEEP, DOT11_EXTCAP_LEN_WNM_SLEEP, WL_BIGDATA_11KV_SLEEP},
13479 {DOT11_EXT_CAP_TIMBC, DOT11_EXTCAP_LEN_TIMBC, WL_BIGDATA_11KV_TIMBC},
13480 {DOT11_EXT_CAP_BSSTRANS_MGMT, DOT11_EXTCAP_LEN_BSSTRANS, WL_BIGDATA_11KV_BSSTRANS},
13481 {DOT11_EXT_CAP_DMS, DOT11_EXTCAP_LEN_DMS, WL_BIGDATA_11KV_DMS}
13482 };
13483
13484 static void
13485 wl_get_11kv_info(u8 *ie, u32 ie_len, uint8 *support_11kv, uint32 *flag_11kv)
13486 {
13487 bcm_tlv_t *ie_11kv = NULL;
13488 uint32 flag_11k = 0, flag_11v = 0;
13489 int i;
13490
13491 /* parsing QBSS load ie */
13492 if ((bcm_parse_tlvs(ie, (u32)ie_len,
13493 DOT11_MNG_QBSS_LOAD_ID)) != NULL) {
13494 flag_11k |= WL_BIGDATA_11KV_QBSSLOAD;
13495 }
13496
13497 /* parsing RM IE for 11k */
13498 if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
13499 DOT11_MNG_RRM_CAP_ID)) != NULL) {
13500 for (i = 0; i < ARRAYSIZE(bigdata_11k_info); i++) {
13501 if ((ie_11kv->len >= bigdata_11k_info[i].octet_len) &&
13502 isset(ie_11kv->data, bigdata_11k_info[i].bitmap)) {
13503 flag_11k |= bigdata_11k_info[i].flag;
13504 }
13505 }
13506 }
13507
13508 /* parsing extended cap. IE for 11v */
13509 if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
13510 DOT11_MNG_EXT_CAP_ID)) != NULL) {
13511 for (i = 0; i < ARRAYSIZE(bigdata_11v_info); i++) {
13512 if ((ie_11kv->len >= bigdata_11v_info[i].octet_len) &&
13513 isset(ie_11kv->data, bigdata_11v_info[i].bitmap)) {
13514 flag_11v |= bigdata_11v_info[i].flag;
13515 }
13516 }
13517 }
13518
13519 if (flag_11k > 0) {
13520 *support_11kv |= WL_BIGDATA_SUPPORT_11K;
13521 }
13522
13523 if (flag_11v > 0) {
13524 *support_11kv |= WL_BIGDATA_SUPPORT_11V;
13525 }
13526
13527 *flag_11kv = flag_11k | flag_11v;
13528 }
13529
13530 int wl_get_bss_info(struct bcm_cfg80211 *cfg, struct net_device *dev, struct ether_addr const *mac)
13531 {
13532 s32 err = 0;
13533 wl_bss_info_t *bi;
13534 uint8 eabuf[ETHER_ADDR_LEN];
13535 u32 rate, channel, freq, supported_rate, nss = 0, mcs_map, mode_80211 = 0;
13536 char rate_str[4];
13537 u8 *ie = NULL;
13538 u32 ie_len;
13539 struct wiphy *wiphy;
13540 struct cfg80211_bss *bss;
13541 bcm_tlv_t *interworking_ie = NULL;
13542 bcm_tlv_t *tlv_ie = NULL;
13543 bcm_tlv_t *vht_ie = NULL;
13544 vndr_ie_t *vndrie;
13545 int16 ie_11u_rel_num = -1, ie_mu_mimo_cap = -1;
13546 u32 i, remained_len, count = 0;
13547 char roam_count_str[4], akm_str[4];
13548 s32 val = 0;
13549 uint8 support_11kv = 0;
13550 uint32 flag_11kv = 0; /* bit flags of 11kv big data */
13551
13552 /* get BSS information */
13553
13554 strncpy(cfg->bss_info, "x x x x x x x x x x x x x x x", GET_BSS_INFO_LEN);
13555
13556 *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
13557
13558 err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, cfg->extra_buf, WL_EXTRA_BUF_MAX);
13559 if (unlikely(err)) {
13560 WL_ERR(("Could not get bss info %d\n", err));
13561 cfg->roam_count = 0;
13562 return -1;
13563 }
13564
13565 if (!mac) {
13566 WL_ERR(("mac is null \n"));
13567 cfg->roam_count = 0;
13568 return -1;
13569 }
13570
13571 memcpy(eabuf, mac, ETHER_ADDR_LEN);
13572
13573 bi = (wl_bss_info_t *)(cfg->extra_buf + 4);
13574 channel = wf_chspec_ctlchan(bi->chanspec);
13575
13576 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
13577 freq = ieee80211_channel_to_frequency(channel);
13578 #else
13579 if (channel > 14) {
13580 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
13581 } else {
13582 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
13583 }
13584 #endif // endif
13585 rate = 0;
13586 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
13587 if (err) {
13588 WL_ERR(("Could not get rate (%d)\n", err));
13589 snprintf(rate_str, sizeof(rate_str), "x"); // Unknown
13590
13591 } else {
13592 rate = dtoh32(rate);
13593 snprintf(rate_str, sizeof(rate_str), "%d", (rate/2));
13594 }
13595
13596 //supported maximum rate
13597 supported_rate = (bi->rateset.rates[bi->rateset.count - 1] & 0x7f) / 2;
13598
13599 if (supported_rate < 12) {
13600 mode_80211 = 0; //11b maximum rate is 11Mbps. 11b mode
13601 } else {
13602 //It's not HT Capable case.
13603 if (channel > 14) {
13604 mode_80211 = 3; // 11a mode
13605 } else {
13606 mode_80211 = 1; // 11g mode
13607 }
13608 }
13609
13610 if (bi->n_cap) {
13611 /* check Rx MCS Map for HT */
13612 nss = 0;
13613 mode_80211 = 2;
13614 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
13615 int8 bitmap = 0xFF;
13616 if (i == MAX_STREAMS_SUPPORTED-1) {
13617 bitmap = 0x7F;
13618 }
13619 if (bi->basic_mcs[i] & bitmap) {
13620 nss++;
13621 }
13622 }
13623 }
13624
13625 if (bi->vht_cap) {
13626 nss = 0;
13627 mode_80211 = 4;
13628 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
13629 mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
13630 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
13631 nss++;
13632 }
13633 }
13634 }
13635
13636 if (nss) {
13637 nss = nss - 1;
13638 }
13639
13640 wiphy = bcmcfg_to_wiphy(cfg);
13641 bss = CFG80211_GET_BSS(wiphy, NULL, eabuf, bi->SSID, bi->SSID_len);
13642 if (!bss) {
13643 WL_ERR(("Could not find the AP\n"));
13644 } else {
13645 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
13646 #pragma GCC diagnostic push
13647 #pragma GCC diagnostic ignored "-Wcast-qual"
13648 #endif // endif
13649 #if defined(WL_CFG80211_P2P_DEV_IF)
13650 ie = (u8 *)bss->ies->data;
13651 ie_len = bss->ies->len;
13652 #else
13653 ie = bss->information_elements;
13654 ie_len = bss->len_information_elements;
13655 #endif /* WL_CFG80211_P2P_DEV_IF */
13656 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
13657 #pragma GCC diagnostic pop
13658 #endif // endif
13659 }
13660
13661 if (ie) {
13662 ie_mu_mimo_cap = 0;
13663 ie_11u_rel_num = 0;
13664
13665 if (bi->vht_cap) {
13666 if ((vht_ie = bcm_parse_tlvs(ie, (u32)ie_len,
13667 DOT11_MNG_VHT_CAP_ID)) != NULL) {
13668 if (vht_ie->len >= VHT_CAP_IE_LEN) {
13669 ie_mu_mimo_cap = (vht_ie->data[2] & 0x08) >> 3;
13670 }
13671 }
13672 }
13673
13674 if ((interworking_ie = bcm_parse_tlvs(ie, (u32)ie_len,
13675 DOT11_MNG_INTERWORKING_ID)) != NULL) {
13676 if ((tlv_ie = bcm_parse_tlvs(ie, (u32)ie_len, DOT11_MNG_VS_ID)) != NULL) {
13677 remained_len = ie_len;
13678
13679 while (tlv_ie) {
13680 if (count > MAX_VNDR_IE_NUMBER)
13681 break;
13682
13683 if (tlv_ie->id == DOT11_MNG_VS_ID) {
13684 vndrie = (vndr_ie_t *) tlv_ie;
13685
13686 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
13687 WL_ERR(("%s: invalid vndr ie."
13688 "length is too small %d\n",
13689 __FUNCTION__, vndrie->len));
13690 break;
13691 }
13692
13693 if (!bcmp(vndrie->oui,
13694 (u8*)WiFiALL_OUI, WiFiALL_OUI_LEN) &&
13695 (vndrie->data[0] == WiFiALL_OUI_TYPE))
13696 {
13697 WL_ERR(("Found Wi-FiAll OUI oui.\n"));
13698 ie_11u_rel_num = vndrie->data[1];
13699 ie_11u_rel_num = (ie_11u_rel_num & 0xf0)>>4;
13700 ie_11u_rel_num += 1;
13701
13702 break;
13703 }
13704 }
13705 count++;
13706 tlv_ie = bcm_next_tlv(tlv_ie, &remained_len);
13707 }
13708 }
13709 }
13710
13711 /* get 11kv information from ie of current bss */
13712 wl_get_11kv_info(ie, ie_len, &support_11kv, &flag_11kv);
13713 }
13714
13715 for (i = 0; i < bi->SSID_len; i++) {
13716 if (bi->SSID[i] == ' ') {
13717 bi->SSID[i] = '_';
13718 }
13719 }
13720
13721 //0 : None, 1 : OKC, 2 : FT, 3 : CCKM
13722 err = wldev_iovar_getint(dev, "wpa_auth", &val);
13723 if (unlikely(err)) {
13724 WL_ERR(("could not get wpa_auth (%d)\n", err));
13725 snprintf(akm_str, sizeof(akm_str), "x"); // Unknown
13726 } else {
13727 WL_ERR(("wpa_auth val %d \n", val));
13728 #if defined(BCMCCX) || defined(BCMEXTCCX)
13729 if (val & (WPA_AUTH_CCKM | WPA2_AUTH_CCKM)) {
13730 snprintf(akm_str, sizeof(akm_str), "3");
13731 } else
13732 #endif /* BCMCCX || BCMEXTCCX */
13733 if (val & WPA2_AUTH_FT) {
13734 snprintf(akm_str, sizeof(akm_str), "2");
13735 } else if (val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) {
13736 snprintf(akm_str, sizeof(akm_str), "1");
13737 } else {
13738 snprintf(akm_str, sizeof(akm_str), "0");
13739 }
13740 }
13741
13742 if (cfg->roam_offload) {
13743 snprintf(roam_count_str, sizeof(roam_count_str), "x"); // Unknown
13744 } else {
13745 snprintf(roam_count_str, sizeof(roam_count_str), "%d", cfg->roam_count);
13746 }
13747 cfg->roam_count = 0;
13748
13749 WL_ERR(("BSSID:" MACDBG " SSID %s \n", MAC2STRDBG(eabuf), "*****"));
13750 WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d,"
13751 "MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n"
13752 "akm:%s, roam:%s, 11kv:%d/%d \n",
13753 freq, wf_chspec_to_bw_str(bi->chanspec),
13754 dtoh32(bi->RSSI), (rate / 2), mode_80211, nss,
13755 ie_mu_mimo_cap, ie_11u_rel_num, bi->SNR, bi->phy_noise,
13756 akm_str, roam_count_str, support_11kv, flag_11kv));
13757
13758 if (ie) {
13759 snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
13760 MACOUI" %d %s %d %s %d %d %d %d %d %d %s %s %d %d",
13761 MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
13762 dtoh32(bi->RSSI), rate_str, mode_80211, nss, ie_mu_mimo_cap,
13763 ie_11u_rel_num, bi->SNR, bi->phy_noise, akm_str, roam_count_str,
13764 support_11kv, flag_11kv);
13765 } else {
13766 //ie_mu_mimo_cap and ie_11u_rel_num is unknow.
13767 snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
13768 MACOUI" %d %s %d %s %d %d x x %d %d %s %s x x",
13769 MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
13770 dtoh32(bi->RSSI), rate_str, mode_80211, nss, bi->SNR,
13771 bi->phy_noise, akm_str, roam_count_str);
13772 }
13773
13774 CFG80211_PUT_BSS(wiphy, bss);
13775
13776 return 0;
13777 }
13778
13779 s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len)
13780 {
13781 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13782
13783 if (cfg == NULL) {
13784 return -1;
13785 }
13786
13787 if (total_len < GET_BSS_INFO_LEN) {
13788 WL_ERR(("%s: Buffer insuffient %d\n", __FUNCTION__, total_len));
13789 return -1;
13790 }
13791
13792 memset(cmd, 0, total_len);
13793 memcpy(cmd, cfg->bss_info, GET_BSS_INFO_LEN);
13794
13795 WL_ERR_KERN(("cmd: %s \n", cmd));
13796
13797 return GET_BSS_INFO_LEN;
13798 }
13799 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
13800
13801 void wl_cfg80211_disassoc(struct net_device *ndev)
13802 {
13803 scb_val_t scbval;
13804 s32 err;
13805
13806 memset(&scbval, 0x0, sizeof(scb_val_t));
13807 scbval.val = htod32(WLAN_REASON_DEAUTH_LEAVING);
13808 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
13809 if (err < 0) {
13810 WL_ERR(("WLC_DISASSOC error %d\n", err));
13811 }
13812 }
13813
13814 void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason)
13815 {
13816 struct net_device *dev;
13817 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13818 scb_val_t scb_val;
13819 int err;
13820 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
13821 sizeof(struct ether_addr) + sizeof(uint)] = {0};
13822 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
13823 int num_associated = 0;
13824
13825 dev = ndev_to_wlc_ndev(ndev, cfg);
13826
13827 if (p2p_is_on(cfg)) {
13828 /* Suspend P2P discovery search-listen to prevent it from changing the
13829 * channel.
13830 */
13831 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
13832 WL_ERR(("Can not disable discovery mode\n"));
13833 return;
13834 }
13835 }
13836
13837 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
13838 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
13839 assoc_maclist, sizeof(mac_buf));
13840 if (err < 0)
13841 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
13842 else
13843 num_associated = assoc_maclist->count;
13844
13845 memset(scb_val.ea.octet, 0xff, ETHER_ADDR_LEN);
13846 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
13847 scb_val.val = htod32(reason);
13848 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
13849 sizeof(scb_val_t));
13850 if (err < 0) {
13851 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
13852 }
13853
13854 if (num_associated > 0)
13855 wl_delay(400);
13856
13857 return;
13858 }
13859 static s32
13860 wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13861 const wl_event_msg_t *e, void *data)
13862 {
13863 bool act;
13864 struct net_device *ndev = NULL;
13865 s32 err = 0;
13866 u32 event = ntoh32(e->event_type);
13867 struct wiphy *wiphy = NULL;
13868 struct cfg80211_bss *bss = NULL;
13869 struct wlc_ssid *ssid = NULL;
13870 u8 *bssid = 0;
13871 dhd_pub_t *dhdp;
13872 u32 mode;
13873 int vndr_oui_num = 0;
13874 char vndr_oui[MAX_VNDR_OUI_STR_LEN] = {0, };
13875 bool loc_gen = false;
13876 #ifdef DHD_LOSSLESS_ROAMING
13877 struct wl_security *sec;
13878 #endif /* DHD_LOSSLESS_ROAMING */
13879
13880 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13881 #ifdef DHD_LOSSLESS_ROAMING
13882 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13883 #endif /* DHD_LOSSLESS_ROAMING */
13884 dhdp = (dhd_pub_t *)(cfg->pub);
13885 BCM_REFERENCE(dhdp);
13886
13887 mode = wl_get_mode_by_netdev(cfg, ndev);
13888 /* Push link events to upper layer log */
13889 SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n",
13890 ndev->name, mode, ntoh32(e->event_type),
13891 ntoh32(e->status), ntoh32(e->reason)));
13892 if (mode == WL_MODE_AP) {
13893 err = wl_notify_connect_status_ap(cfg, ndev, e, data);
13894 } else if (mode == WL_MODE_IBSS) {
13895 err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
13896 } else if (mode == WL_MODE_BSS) {
13897 WL_INFORM_MEM(("[%s] Mode BSS. event:%d status:%d reason:%d\n",
13898 ndev->name, ntoh32(e->event_type),
13899 ntoh32(e->status), ntoh32(e->reason)));
13900
13901 if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
13902 /* Join attempt via non-cfg80211 interface.
13903 * Don't send resultant events to cfg80211
13904 * layer
13905 */
13906 WL_INFORM_MEM(("Event received in non-cfg80211"
13907 " connect state. Ignore\n"));
13908 return BCME_OK;
13909 }
13910
13911 if (event == WLC_E_ASSOC || event == WLC_E_AUTH) {
13912 wl_get_auth_assoc_status(cfg, ndev, e);
13913 return 0;
13914 }
13915 DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
13916 if (wl_is_linkup(cfg, e, ndev)) {
13917 wl_link_up(cfg);
13918 act = true;
13919 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
13920 WL_INFORM_MEM(("[%s] link up for bssid " MACDBG "\n",
13921 ndev->name, MAC2STRDBG((const u8*)(&e->addr))));
13922
13923 if ((event == WLC_E_LINK) &&
13924 (ntoh16(e->flags) & WLC_EVENT_MSG_LINK) &&
13925 !wl_get_drv_status(cfg, CONNECTED, ndev) &&
13926 !wl_get_drv_status(cfg, CONNECTING, ndev)) {
13927 WL_INFORM_MEM(("link up in non-connected/"
13928 "non-connecting state\n"));
13929 wl_cfg80211_disassoc(ndev);
13930 return BCME_OK;
13931 }
13932
13933 #ifdef WL_WPS_SYNC
13934 /* Avoid invocation for Roam cases */
13935 if ((event == WLC_E_LINK) &&
13936 !wl_get_drv_status(cfg, CONNECTED, ndev)) {
13937 wl_wps_session_update(ndev,
13938 WPS_STATE_LINKUP, e->addr.octet);
13939 }
13940 #endif /* WL_WPS_SYNC */
13941
13942 if (((event == WLC_E_ROAM) || (event == WLC_E_BSSID)) &&
13943 !wl_get_drv_status(cfg, CONNECTED, ndev)) {
13944 /* Roam event in disconnected state. DHD-FW state
13945 * mismatch. Issue disassoc to clear fw state
13946 */
13947 WL_INFORM_MEM(("Roam even in disconnected state."
13948 " clear fw state\n"));
13949 wl_cfg80211_disassoc(ndev);
13950 return BCME_OK;
13951 }
13952 #ifdef DHD_EVENT_LOG_FILTER
13953 if (event == WLC_E_LINK && ndev == bcmcfg_to_prmry_ndev(cfg)) {
13954 int roam = FALSE;
13955 uint8 eth_addr[ETHER_ADDR_LEN];
13956 if (TRUE &&
13957 #ifdef DHD_LOSSLESS_ROAMING
13958 !cfg->roam_offload &&
13959 #endif /* DHD_LOSSLESS_ROAMING */
13960 wl_get_drv_status(cfg, CONNECTED, ndev)) {
13961 roam = TRUE;
13962 }
13963 memcpy(eth_addr, &(e->addr), ETHER_ADDR_LEN);
13964 dhd_event_log_filter_notify_connect_done(dhdp,
13965 eth_addr, roam);
13966 }
13967 #endif /* DHD_EVENT_LOG_FILTER */
13968 if (event == WLC_E_LINK &&
13969 #ifdef DHD_LOSSLESS_ROAMING
13970 !cfg->roam_offload &&
13971 !IS_AKM_SUITE_FT(sec) &&
13972 #endif /* DHD_LOSSLESS_ROAMING */
13973 wl_get_drv_status(cfg, CONNECTED, ndev)) {
13974 wl_bss_roaming_done(cfg, ndev, e, data);
13975 } else {
13976 /* Initial Association */
13977 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
13978 wl_bss_connect_done(cfg, ndev, e, data, true);
13979 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
13980 vndr_oui_num = wl_vndr_ies_get_vendor_oui(cfg,
13981 ndev, vndr_oui, ARRAY_SIZE(vndr_oui));
13982 if (vndr_oui_num > 0) {
13983 WL_INFORM_MEM(("[%s] vendor oui: %s\n",
13984 ndev->name, vndr_oui));
13985 }
13986 }
13987 WL_DBG(("joined in BSS network \"%s\"\n",
13988 ((struct wlc_ssid *)
13989 wl_read_prof(cfg, ndev,
13990 WL_PROF_SSID))->SSID));
13991 }
13992 #ifdef WBTEXT
13993 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
13994 dhdp->wbtext_support && event == WLC_E_SET_SSID) {
13995 /* set wnm_keepalives_max_idle after association */
13996 wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
13997 /* send nbr request or BTM query to update RCC */
13998 wl_cfg80211_wbtext_update_rcc(cfg, ndev);
13999 }
14000 #endif /* WBTEXT */
14001 }
14002 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
14003 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14004 } else if (WL_IS_LINKDOWN(cfg, e, data) ||
14005 ((event == WLC_E_SET_SSID) &&
14006 (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) &&
14007 (wl_get_drv_status(cfg, CONNECTED, ndev)))) {
14008
14009 WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n",
14010 wl_get_drv_status(cfg, CONNECTING, ndev),
14011 wl_get_drv_status(cfg, CONNECTED, ndev),
14012 wl_get_drv_status(cfg, DISCONNECTING, ndev),
14013 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
14014
14015 #ifdef WL_WPS_SYNC
14016 {
14017 u8 wps_state;
14018 if ((event == WLC_E_SET_SSID) &&
14019 (ntoh32(e->status) != WLC_E_STATUS_SUCCESS)) {
14020 /* connect fail */
14021 wps_state = WPS_STATE_CONNECT_FAIL;
14022 } else {
14023 wps_state = WPS_STATE_LINKDOWN;
14024 }
14025 if (wl_wps_session_update(ndev,
14026 wps_state, e->addr.octet) == BCME_UNSUPPORTED) {
14027 /* Unexpected event. Ignore it. */
14028 return 0;
14029 }
14030 }
14031 #endif /* WL_WPS_SYNC */
14032
14033 if (wl_get_drv_status(cfg, DISCONNECTING, ndev) &&
14034 (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) ||
14035 wl_get_drv_status(cfg, CONNECTING, ndev))) {
14036 /* wl_cfg80211_connect was called before 'DISCONNECTING' was
14037 * cleared. Deauth/Link down event is caused by WLC_DISASSOC
14038 * command issued from the wl_cfg80211_connect context. Ignore
14039 * the event to avoid pre-empting the current connection
14040 */
14041 WL_DBG(("Nested connection case. Drop event. \n"));
14042 wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
14043 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
14044 /* Not in 'CONNECTED' state, clear it */
14045 wl_clr_drv_status(cfg, CONNECTED, ndev);
14046 return 0;
14047 }
14048
14049 #ifdef DYNAMIC_MUMIMO_CONTROL
14050 wl_set_murx_reassoc_status(cfg, FALSE);
14051 wl_set_murx_block_eapol_status(cfg, FALSE);
14052 /* Reset default murx_bfe_cap value */
14053 wl_set_murx_bfe_cap(ndev, 1, FALSE);
14054 #ifdef ARGOS_CPU_SCHEDULER
14055 argos_config_mumimo_reset();
14056 #endif /* ARGOS_CPU_SCHEDULER */
14057 DHD_ENABLE_RUNTIME_PM(dhdp);
14058 #endif /* DYNAMIC_MUMIMO_CONTROL */
14059
14060 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
14061 FW_LOGSET_MASK_ALL);
14062 #ifdef DHD_LOSSLESS_ROAMING
14063 wl_del_roam_timeout(cfg);
14064 #endif // endif
14065 #ifdef P2PLISTEN_AP_SAMECHN
14066 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
14067 wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0);
14068 cfg->p2p_resp_apchn_status = false;
14069 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
14070 }
14071 #endif /* P2PLISTEN_AP_SAMECHN */
14072 wl_cfg80211_cancel_scan(cfg);
14073
14074 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
14075 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
14076 wl_get_bss_info(cfg, ndev, &e->addr);
14077 }
14078 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
14079 /* Explicitly calling unlink to remove BSS in CFG */
14080 wiphy = bcmcfg_to_wiphy(cfg);
14081 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
14082 bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14083 if (ssid && bssid) {
14084 bss = CFG80211_GET_BSS(wiphy, NULL, bssid,
14085 ssid->SSID, ssid->SSID_len);
14086 if (bss) {
14087 cfg80211_unlink_bss(wiphy, bss);
14088 CFG80211_PUT_BSS(wiphy, bss);
14089 }
14090 }
14091
14092 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
14093 scb_val_t scbval;
14094 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14095 uint32 reason = 0;
14096 bcm_tlv_t *deauth_info = NULL;
14097 wips_detect_inform_t *wips_detect_info;
14098 uint8 wips_bssid[ETHER_ADDR_LEN];
14099 u32 len = ntoh32(e->datalen) + TLV_HDR_LEN;
14100
14101 struct ether_addr bssid_dongle = {{0, 0, 0, 0, 0, 0}};
14102 struct ether_addr bssid_null = {{0, 0, 0, 0, 0, 0}};
14103
14104 if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
14105 reason = ntoh32(e->reason);
14106 if (reason > WLC_E_DEAUTH_MAX_REASON) {
14107 WL_ERR(("Event %d original reason is %d, "
14108 "changed 0xFF\n", event, reason));
14109 reason = WLC_E_DEAUTH_MAX_REASON;
14110 }
14111 if ((deauth_info = bcm_parse_tlvs(data, len,
14112 TAG_DEAUTH_TLV_WIPS)) != NULL) {
14113 wips_detect_info =
14114 (wips_detect_inform_t *)deauth_info->data;
14115 memcpy(wips_bssid, &wips_detect_info->ea,
14116 ETHER_ADDR_LEN);
14117 if (wips_detect_info->misdeauth > 1) {
14118 WL_ERR(("WIPS attack!! cnt=%d, curRSSI=%d, "
14119 "deauthRSSI=%d, time=%d, "
14120 "MAC="MACDBG"\n",
14121 wips_detect_info->misdeauth,
14122 wips_detect_info->cur_bsscfg_rssi,
14123 wips_detect_info->deauth_rssi,
14124 wips_detect_info->timestamp,
14125 MAC2STRDBG(wips_bssid)));
14126 }
14127 }
14128 }
14129 #ifdef SET_SSID_FAIL_CUSTOM_RC
14130 if (event == WLC_E_SET_SSID) {
14131 reason = SET_SSID_FAIL_CUSTOM_RC;
14132 }
14133 #endif /* SET_SSID_FAIL_CUSTOM_RC */
14134
14135 /* roam offload does not sync BSSID always, get it from dongle */
14136 if (cfg->roam_offload) {
14137 memset(&bssid_dongle, 0, sizeof(bssid_dongle));
14138 if (wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid_dongle,
14139 sizeof(bssid_dongle)) == BCME_OK) {
14140 /* if not roam case, it would return null bssid */
14141 if (memcmp(&bssid_dongle, &bssid_null,
14142 ETHER_ADDR_LEN) != 0) {
14143 curbssid = (u8 *)&bssid_dongle;
14144 }
14145 }
14146 }
14147 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
14148 bool fw_assoc_state = TRUE;
14149 dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
14150 fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
14151 if (!fw_assoc_state) {
14152 WL_ERR(("Event sends up even different BSSID"
14153 " cur: " MACDBG " event: " MACDBG"\n",
14154 MAC2STRDBG(curbssid),
14155 MAC2STRDBG((const u8*)(&e->addr))));
14156 } else {
14157 WL_ERR(("BSSID of event is not the connected BSSID"
14158 "(ignore it) cur: " MACDBG
14159 " event: " MACDBG"\n",
14160 MAC2STRDBG(curbssid),
14161 MAC2STRDBG((const u8*)(&e->addr))));
14162 return 0;
14163 }
14164 }
14165 #ifdef DBG_PKT_MON
14166 /* Stop packet monitor */
14167 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
14168 DHD_DBG_PKT_MON_STOP(dhdp);
14169 }
14170 #endif /* DBG_PKT_MON */
14171 /* clear RSSI monitor, framework will set new cfg */
14172 #ifdef RSSI_MONITOR_SUPPORT
14173 dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
14174 FALSE, 0, 0);
14175 #endif /* RSSI_MONITOR_SUPPORT */
14176 wl_clr_drv_status(cfg, CONNECTED, ndev);
14177
14178 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
14179 /* To make sure disconnect, explictly send dissassoc
14180 * for BSSID 00:00:00:00:00:00 issue
14181 */
14182 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
14183 WL_INFORM_MEM(("clear fw state\n"));
14184 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
14185 scbval.val = htod32(scbval.val);
14186 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
14187 sizeof(scb_val_t));
14188 if (err < 0) {
14189 WL_ERR(("WLC_DISASSOC error %d\n", err));
14190 err = 0;
14191 }
14192 }
14193 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
14194 loc_gen = true;
14195 }
14196 WL_INFORM_MEM(("[%s] Indicate disconnect event to upper layer. "
14197 "event: %d reason=%d from " MACDBG "\n",
14198 ndev->name, event, ntoh32(e->reason),
14199 MAC2STRDBG((const u8*)(&e->addr))));
14200
14201 /* Send up deauth and clear states */
14202 CFG80211_DISCONNECTED(ndev, reason, NULL, 0,
14203 loc_gen, GFP_KERNEL);
14204 wl_link_down(cfg);
14205 wl_init_prof(cfg, ndev);
14206 #ifdef WBTEXT
14207 /* when STA was disconnected, clear join pref and set wbtext */
14208 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
14209 dhdp->wbtext_policy
14210 == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) {
14211 char smbuf[WLC_IOCTL_SMLEN];
14212 char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03,
14213 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
14214 if ((err = wldev_iovar_setbuf(ndev, "join_pref",
14215 clear, sizeof(clear), smbuf,
14216 sizeof(smbuf), NULL))
14217 == BCME_OK) {
14218 if ((err = wldev_iovar_setint(ndev,
14219 "wnm_bsstrans_resp",
14220 dhdp->wbtext_policy))
14221 == BCME_OK) {
14222 wl_cfg80211_wbtext_set_default(ndev);
14223 } else {
14224 WL_ERR(("%s: Failed to set wbtext = %d\n",
14225 __FUNCTION__, err));
14226 }
14227 } else {
14228 WL_ERR(("%s: Failed to clear join pref = %d\n",
14229 __FUNCTION__, err));
14230 }
14231 wl_cfg80211_wbtext_clear_bssid_list(cfg);
14232 }
14233 #endif /* WBTEXT */
14234 }
14235 else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
14236 WL_INFORM_MEM(("link down, during connecting\n"));
14237 /* Issue WLC_DISASSOC to prevent FW roam attempts */
14238 err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
14239 if (err < 0) {
14240 WL_ERR(("CONNECTING state, WLC_DISASSOC error %d\n", err));
14241 err = 0;
14242 }
14243 WL_DBG(("Clear drv CONNECTING status\n"));
14244 wl_clr_drv_status(cfg, CONNECTING, ndev);
14245 #ifdef ESCAN_RESULT_PATCH
14246 if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) ||
14247 (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) ||
14248 (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0))
14249 /* In case this event comes while associating another AP */
14250 #endif /* ESCAN_RESULT_PATCH */
14251 wl_bss_connect_done(cfg, ndev, e, data, false);
14252 }
14253 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
14254
14255 /* if link down, bsscfg is diabled */
14256 if (ndev != bcmcfg_to_prmry_ndev(cfg))
14257 complete(&cfg->iface_disable);
14258 #ifdef WLTDLS
14259 /* re-enable TDLS if the number of connected interfaces
14260 * is less than 2.
14261 */
14262 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
14263 #endif /* WLTDLS */
14264 } else if (wl_is_nonetwork(cfg, e)) {
14265 WL_ERR(("connect failed event=%d e->status %d e->reason %d \n",
14266 event, (int)ntoh32(e->status), (int)ntoh32(e->reason)));
14267 #ifdef WL_WPS_SYNC
14268 if (wl_wps_session_update(ndev,
14269 WPS_STATE_CONNECT_FAIL, e->addr.octet) == BCME_UNSUPPORTED) {
14270 /* Unexpected event. Ignore it. */
14271 return 0;
14272 }
14273 #endif /* WL_WPS_SYNC */
14274 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
14275 if (event == WLC_E_SET_SSID) {
14276 wl_get_connect_failed_status(cfg, e);
14277 }
14278 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
14279 /* Dump FW preserve buffer content */
14280 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
14281
14282 /* Clean up any pending scan request */
14283 wl_cfg80211_cancel_scan(cfg);
14284
14285 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
14286 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
14287 WL_INFORM_MEM(("wl dissassoc\n"));
14288 err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
14289 if (err < 0) {
14290 WL_ERR(("WLC_DISASSOC error %d\n", err));
14291 err = 0;
14292 }
14293 } else {
14294 WL_DBG(("connect fail. clear disconnecting bit\n"));
14295 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
14296 }
14297 wl_bss_connect_done(cfg, ndev, e, data, false);
14298 wl_clr_drv_status(cfg, CONNECTING, ndev);
14299 WL_INFORM_MEM(("connect fail reported\n"));
14300 }
14301 } else {
14302 WL_DBG(("%s nothing\n", __FUNCTION__));
14303 }
14304 #ifdef DYNAMIC_MUMIMO_CONTROL
14305 if (!wl_get_murx_reassoc_status(cfg))
14306 #endif /* DYNAMIC_MUMIMO_CONTROL */
14307 {
14308 DHD_ENABLE_RUNTIME_PM(dhdp);
14309 }
14310 } else {
14311 WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev)));
14312 }
14313 return err;
14314 }
14315
14316 #ifdef WL_RELMCAST
14317 void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
14318 {
14319 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
14320 if (pid > 0)
14321 cfg->rmc_event_pid = pid;
14322 WL_DBG(("set pid for rmc event : pid=%d\n", pid));
14323 }
14324 #endif /* WL_RELMCAST */
14325
14326 #ifdef WLAIBSS
14327 void wl_cfg80211_set_txfail_pid(struct net_device *dev, int pid)
14328 {
14329 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
14330 if (pid > 0)
14331 cfg->aibss_txfail_pid = pid;
14332 WL_DBG(("set pid for aibss fail event : pid=%d\n", pid));
14333 }
14334
14335 static s32
14336 wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14337 const wl_event_msg_t *e, void *data)
14338 {
14339 u32 evt = ntoh32(e->event_type);
14340 int ret = -1;
14341 #ifdef PCIE_FULL_DONGLE
14342 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
14343 u32 reason = ntoh32(e->reason);
14344 #endif // endif
14345 if (cfg->aibss_txfail_pid != 0) {
14346 #ifdef PCIE_FULL_DONGLE
14347 if (reason == AIBSS_PEER_FREE) {
14348 uint8 ifindex;
14349 wl_event_msg_t event;
14350
14351 memset(&event, 0, sizeof(wl_event_msg_t));
14352 memcpy(&event, e, sizeof(wl_event_msg_t));
14353
14354 ifindex = (uint8)dhd_ifname2idx(dhd->info, event.ifname);
14355 WL_INFORM_MEM(("Peer freed. Flow rings delete for peer.\n"));
14356 dhd_flow_rings_delete_for_peer(dhd, ifindex,
14357 (void *)&event.addr.octet[0]);
14358 return 0;
14359 }
14360 #endif // endif
14361 ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL,
14362 cfg->aibss_txfail_seq++, &e->addr, ETHER_ADDR_LEN);
14363 }
14364
14365 WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n",
14366 evt, cfg->aibss_txfail_pid, ret, CONST_ETHERP_TO_MACF(&e->addr)));
14367 return ret;
14368 }
14369 #endif /* WLAIBSS */
14370 #ifdef WL_RELMCAST
14371 static s32
14372 wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14373 const wl_event_msg_t *e, void *data)
14374 {
14375 u32 evt = ntoh32(e->event_type);
14376 u32 reason = ntoh32(e->reason);
14377 int ret = -1;
14378
14379 switch (reason) {
14380 case WLC_E_REASON_RMC_AR_LOST:
14381 case WLC_E_REASON_RMC_AR_NO_ACK:
14382 if (cfg->rmc_event_pid != 0) {
14383 ret = wl_netlink_send_msg(cfg->rmc_event_pid,
14384 RMC_EVENT_LEADER_CHECK_FAIL,
14385 cfg->rmc_event_seq++, NULL, 0);
14386 }
14387 break;
14388 default:
14389 break;
14390 }
14391 WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
14392 return ret;
14393 }
14394 #endif /* WL_RELMCAST */
14395
14396 #ifdef GSCAN_SUPPORT
14397 static s32
14398 wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14399 const wl_event_msg_t *e, void *data)
14400 {
14401 struct net_device *ndev = NULL;
14402 u32 datalen = be32_to_cpu(e->datalen);
14403
14404 if (datalen) {
14405 wl_roam_exp_event_t *evt_data = (wl_roam_exp_event_t *)data;
14406 if (evt_data->version == ROAM_EXP_EVENT_VERSION) {
14407 wlc_ssid_t *ssid = &evt_data->cur_ssid;
14408 struct wireless_dev *wdev;
14409 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14410 if (ndev) {
14411 wdev = ndev->ieee80211_ptr;
14412 wdev->ssid_len = min(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN);
14413 memcpy(wdev->ssid, ssid->SSID, wdev->ssid_len);
14414 WL_ERR(("SSID is %s\n", ssid->SSID));
14415 wl_update_prof(cfg, ndev, NULL, ssid, WL_PROF_SSID);
14416 } else {
14417 WL_ERR(("NULL ndev!\n"));
14418 }
14419 } else {
14420 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
14421 ROAM_EXP_EVENT_VERSION));
14422 }
14423 }
14424 return BCME_OK;
14425 }
14426 #endif /* GSCAN_SUPPORT */
14427
14428 #ifdef RSSI_MONITOR_SUPPORT
14429 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14430 const wl_event_msg_t *e, void *data)
14431 {
14432
14433 #if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
14434 u32 datalen = be32_to_cpu(e->datalen);
14435 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14436 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14437
14438 if (datalen) {
14439 wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data;
14440 if (evt_data->version == RSSI_MONITOR_VERSION) {
14441 dhd_rssi_monitor_evt_t monitor_data;
14442 monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION;
14443 monitor_data.cur_rssi = evt_data->cur_rssi;
14444 memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN);
14445 wl_cfgvendor_send_async_event(wiphy, ndev,
14446 GOOGLE_RSSI_MONITOR_EVENT,
14447 &monitor_data, sizeof(monitor_data));
14448 } else {
14449 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
14450 RSSI_MONITOR_VERSION));
14451 }
14452 }
14453 #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
14454 return BCME_OK;
14455 }
14456 #endif /* RSSI_MONITOR_SUPPORT */
14457
14458 static s32
14459 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14460 const wl_event_msg_t *e, void *data)
14461 {
14462 bool act;
14463 struct net_device *ndev = NULL;
14464 s32 err = 0;
14465 u32 event = be32_to_cpu(e->event_type);
14466 u32 status = be32_to_cpu(e->status);
14467 #ifdef DHD_LOSSLESS_ROAMING
14468 struct wl_security *sec;
14469 #endif // endif
14470 #if defined(WBTEXT)
14471 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14472 #endif /* WBTEXT */
14473 WL_DBG(("Enter \n"));
14474
14475 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14476
14477 if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
14478 wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
14479 cfg->disable_roam_event = TRUE;
14480 }
14481
14482 if ((cfg->disable_roam_event) && (event == WLC_E_ROAM))
14483 return err;
14484
14485 if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
14486 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
14487 #ifdef DHD_LOSSLESS_ROAMING
14488 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14489 /* In order to reduce roaming delay, wl_bss_roaming_done is
14490 * early called with WLC_E_LINK event. It is called from
14491 * here only if WLC_E_LINK event is blocked for specific
14492 * security type.
14493 */
14494 if (IS_AKM_SUITE_FT(sec)) {
14495 wl_bss_roaming_done(cfg, ndev, e, data);
14496 }
14497 /* Roam timer is deleted mostly from wl_cfg80211_change_station
14498 * after roaming is finished successfully. We need to delete
14499 * the timer from here only for some security types that aren't
14500 * using wl_cfg80211_change_station to authorize SCB
14501 */
14502 if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
14503 wl_del_roam_timeout(cfg);
14504 }
14505 #else
14506 wl_bss_roaming_done(cfg, ndev, e, data);
14507 #endif /* DHD_LOSSLESS_ROAMING */
14508 #ifdef WBTEXT
14509 if (dhdp->wbtext_support) {
14510 /* set wnm_keepalives_max_idle after association */
14511 wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
14512 /* send nbr request or BTM query to update RCC
14513 * after roaming completed (receiving the first beacon)
14514 */
14515 wl_cfg80211_wbtext_update_rcc(cfg, ndev);
14516 }
14517 #endif /* WBTEXT */
14518 } else {
14519 wl_bss_connect_done(cfg, ndev, e, data, true);
14520 }
14521 act = true;
14522 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
14523 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14524
14525 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
14526 wl_vndr_ies_get_vendor_oui(cfg, ndev, NULL, 0);
14527 }
14528 }
14529 #ifdef DHD_LOSSLESS_ROAMING
14530 else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) {
14531 wl_del_roam_timeout(cfg);
14532 }
14533 #endif // endif
14534 return err;
14535 }
14536
14537 #ifdef CUSTOM_EVENT_PM_WAKE
14538 uint32 last_dpm_upd_time = 0; /* ms */
14539 #define DPM_UPD_LMT_TIME (CUSTOM_EVENT_PM_WAKE + 5) * 1000 * 4 /* ms */
14540 #define DPM_UPD_LMT_RSSI -85 /* dbm */
14541
14542 static s32
14543 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14544 const wl_event_msg_t *e, void *data)
14545 {
14546 s32 err = BCME_OK;
14547 struct net_device *ndev = NULL;
14548 u8 *pbuf = NULL;
14549 uint32 cur_dpm_upd_time = 0;
14550 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
14551 s32 rssi;
14552 #ifdef SUPPORT_RSSI_SUM_REPORT
14553 wl_rssi_ant_mimo_t rssi_ant_mimo;
14554 #endif /* SUPPORT_RSSI_SUM_REPORT */
14555 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14556
14557 pbuf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
14558 if (pbuf == NULL) {
14559 WL_ERR(("failed to allocate local pbuf\n"));
14560 return -ENOMEM;
14561 }
14562
14563 err = wldev_iovar_getbuf_bsscfg(ndev, "dump",
14564 "pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
14565
14566 if (err) {
14567 WL_ERR(("dump ioctl err = %d", err));
14568 } else {
14569 WL_ERR(("PM status : %s\n", pbuf));
14570 }
14571
14572 if (pbuf) {
14573 MFREE(cfg->osh, pbuf, WLC_IOCTL_MEDLEN);
14574 }
14575
14576 if (dhd->early_suspended) {
14577 /* LCD off */
14578 #ifdef SUPPORT_RSSI_SUM_REPORT
14579 /* Query RSSI sum across antennas */
14580 memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
14581 err = wl_get_rssi_per_ant(ndev, ndev->name, NULL, &rssi_ant_mimo);
14582 if (err) {
14583 WL_ERR(("Could not get rssi sum (%d)\n", err));
14584 }
14585 rssi = rssi_ant_mimo.rssi_sum;
14586 if (rssi == 0)
14587 #endif /* SUPPORT_RSSI_SUM_REPORT */
14588 {
14589 scb_val_t scb_val;
14590 memset(&scb_val, 0, sizeof(scb_val_t));
14591 scb_val.val = 0;
14592 err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
14593 if (err) {
14594 WL_ERR(("Could not get rssi (%d)\n", err));
14595 }
14596 rssi = wl_rssi_offset(dtoh32(scb_val.val));
14597 }
14598 WL_ERR(("RSSI %d dBm\n", rssi));
14599 if (rssi > DPM_UPD_LMT_RSSI) {
14600 return err;
14601 }
14602 } else {
14603 /* LCD on */
14604 return err;
14605 }
14606
14607 if (last_dpm_upd_time == 0) {
14608 last_dpm_upd_time = OSL_SYSUPTIME();
14609 } else {
14610 cur_dpm_upd_time = OSL_SYSUPTIME();
14611 if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) {
14612 scb_val_t scbval;
14613 bzero(&scbval, sizeof(scb_val_t));
14614
14615 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
14616 if (err < 0) {
14617 WL_ERR(("%s: Disassoc error %d\n", __FUNCTION__, err));
14618 return err;
14619 }
14620 WL_ERR(("%s: Force Disassoc due to updated DPM event.\n", __FUNCTION__));
14621
14622 last_dpm_upd_time = 0;
14623 } else {
14624 last_dpm_upd_time = cur_dpm_upd_time;
14625 }
14626 }
14627
14628 return err;
14629 }
14630 #endif /* CUSTOM_EVENT_PM_WAKE */
14631
14632 #ifdef QOS_MAP_SET
14633 /* get user priority table */
14634 uint8 *
14635 wl_get_up_table(dhd_pub_t * dhdp, int idx)
14636 {
14637 struct net_device *ndev;
14638 struct bcm_cfg80211 *cfg;
14639
14640 ndev = dhd_idx2net(dhdp, idx);
14641 if (ndev) {
14642 cfg = wl_get_cfg(ndev);
14643 if (cfg)
14644 return (uint8 *)(cfg->up_table);
14645 }
14646
14647 return NULL;
14648 }
14649 #endif /* QOS_MAP_SET */
14650
14651 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
14652 static s32
14653 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14654 const wl_event_msg_t *e, void *data)
14655 {
14656 struct wl_security *sec;
14657 struct net_device *ndev;
14658 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14659 u32 status = ntoh32(e->status);
14660 u32 reason = ntoh32(e->reason);
14661
14662 BCM_REFERENCE(sec);
14663
14664 if (status == WLC_E_STATUS_SUCCESS && reason != WLC_E_REASON_INITIAL_ASSOC) {
14665 WL_ERR(("Attempting roam with reason code : %d\n", reason));
14666 }
14667
14668 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14669
14670 #ifdef DBG_PKT_MON
14671 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
14672 DHD_DBG_PKT_MON_STOP(dhdp);
14673 DHD_DBG_PKT_MON_START(dhdp);
14674 }
14675 #endif /* DBG_PKT_MON */
14676 #ifdef DHD_LOSSLESS_ROAMING
14677 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14678 /* Disable Lossless Roaming for specific AKM suite
14679 * Any other AKM suite can be added below if transition time
14680 * is delayed because of Lossless Roaming
14681 * and it causes any certication failure
14682 */
14683 if (IS_AKM_SUITE_FT(sec)) {
14684 return BCME_OK;
14685 }
14686
14687 dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC;
14688 #ifdef DYNAMIC_MUMIMO_CONTROL
14689 if (!wl_get_murx_reassoc_status(cfg))
14690 #endif /* DYNAMIC_MUMIMO_CONTROL */
14691 {
14692 /* Restore flow control */
14693 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
14694 }
14695
14696 mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
14697 #endif /* DHD_LOSSLESS_ROAMING */
14698
14699 return BCME_OK;
14700 }
14701 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
14702
14703 static s32
14704 wl_notify_roam_start_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14705 const wl_event_msg_t *e, void *data)
14706 {
14707 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
14708 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14709 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14710 int event_type;
14711
14712 event_type = WIFI_EVENT_ROAM_SCAN_STARTED;
14713 wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_ROAM_EVENT_START,
14714 &event_type, sizeof(int));
14715 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || (WL_VENDOR_EXT_SUPPORT) */
14716
14717 return BCME_OK;
14718 }
14719
14720 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
14721 {
14722 wl_assoc_info_t assoc_info;
14723 struct wl_connect_info *conn_info = wl_to_conn(cfg);
14724 s32 err = 0;
14725 #ifdef QOS_MAP_SET
14726 bcm_tlv_t * qos_map_ie = NULL;
14727 #endif /* QOS_MAP_SET */
14728
14729 WL_DBG(("Enter \n"));
14730 err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
14731 WL_ASSOC_INFO_MAX, NULL);
14732 if (unlikely(err)) {
14733 WL_ERR(("could not get assoc info (%d)\n", err));
14734 return err;
14735 }
14736 memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
14737 assoc_info.req_len = htod32(assoc_info.req_len);
14738 assoc_info.resp_len = htod32(assoc_info.resp_len);
14739 assoc_info.flags = htod32(assoc_info.flags);
14740
14741 if (assoc_info.req_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_req) +
14742 ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0))) {
14743 err = BCME_BADLEN;
14744 goto exit;
14745 }
14746 if ((assoc_info.req_len > 0) &&
14747 (assoc_info.req_len < (sizeof(struct dot11_assoc_req) +
14748 ((assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) ? ETHER_ADDR_LEN : 0)))) {
14749 err = BCME_BADLEN;
14750 goto exit;
14751 }
14752 if (assoc_info.resp_len > (MAX_REQ_LINE + sizeof(struct dot11_assoc_resp))) {
14753 err = BCME_BADLEN;
14754 goto exit;
14755 }
14756 if ((assoc_info.resp_len > 0) && (assoc_info.resp_len < sizeof(struct dot11_assoc_resp))) {
14757 err = BCME_BADLEN;
14758 goto exit;
14759 }
14760
14761 if (conn_info->req_ie_len) {
14762 conn_info->req_ie_len = 0;
14763 bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
14764 }
14765 if (conn_info->resp_ie_len) {
14766 conn_info->resp_ie_len = 0;
14767 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
14768 }
14769
14770 if (assoc_info.req_len) {
14771 err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
14772 assoc_info.req_len, NULL);
14773 if (unlikely(err)) {
14774 WL_ERR(("could not get assoc req (%d)\n", err));
14775 goto exit;
14776 }
14777 if (assoc_info.req_len < sizeof(struct dot11_assoc_req)) {
14778 WL_ERR(("req_len %d lessthan %d \n", assoc_info.req_len,
14779 (int)sizeof(struct dot11_assoc_req)));
14780 return BCME_BADLEN;
14781 }
14782 conn_info->req_ie_len = (uint32)(assoc_info.req_len
14783 - sizeof(struct dot11_assoc_req));
14784 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
14785 conn_info->req_ie_len -= ETHER_ADDR_LEN;
14786 }
14787 memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
14788 }
14789
14790 if (assoc_info.resp_len) {
14791 err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
14792 assoc_info.resp_len, NULL);
14793 if (unlikely(err)) {
14794 WL_ERR(("could not get assoc resp (%d)\n", err));
14795 goto exit;
14796 }
14797 if (assoc_info.resp_len < sizeof(struct dot11_assoc_resp)) {
14798 WL_ERR(("resp_len %d is lessthan %d \n", assoc_info.resp_len,
14799 (int)sizeof(struct dot11_assoc_resp)));
14800 }
14801 conn_info->resp_ie_len = assoc_info.resp_len -
14802 (uint32)sizeof(struct dot11_assoc_resp);
14803 memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
14804 #ifdef QOS_MAP_SET
14805 /* find qos map set ie */
14806 if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
14807 DOT11_MNG_QOS_MAP_ID)) != NULL) {
14808 WL_DBG((" QoS map set IE found in assoc response\n"));
14809 if (!cfg->up_table) {
14810 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
14811 }
14812 wl_set_up_table(cfg->up_table, qos_map_ie);
14813 } else {
14814 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
14815 cfg->up_table = NULL;
14816 }
14817 #endif /* QOS_MAP_SET */
14818 }
14819
14820 exit:
14821 if (err) {
14822 WL_ERR(("err:%d, assoc_info-req:%u,resp:%u conn_info-req:%u,resp:%u\n",
14823 err, assoc_info.req_len, assoc_info.resp_len,
14824 conn_info->req_ie_len, conn_info->resp_ie_len));
14825 }
14826 return err;
14827 }
14828
14829 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch, struct wl_join_params *join_params,
14830 size_t *join_params_size)
14831 {
14832 chanspec_t chanspec = 0, chspec;
14833 struct bcm_cfg80211 *cfg =
14834 (struct bcm_cfg80211 *)wiphy_priv(dev->ieee80211_ptr->wiphy);
14835
14836 if ((ch != 0) && (cfg && !cfg->rcc_enabled)) {
14837 join_params->params.chanspec_num = 1;
14838 join_params->params.chanspec_list[0] = ch;
14839
14840 if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
14841 chanspec |= WL_CHANSPEC_BAND_2G;
14842 else
14843 chanspec |= WL_CHANSPEC_BAND_5G;
14844
14845 /* Get the min_bw set for the interface */
14846 chspec = WL_CHANSPEC_BW_20;
14847 if (chspec == INVCHANSPEC) {
14848 WL_ERR(("Invalid chanspec \n"));
14849 return -EINVAL;
14850 }
14851 chanspec |= chspec;
14852 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
14853
14854 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
14855 join_params->params.chanspec_num * sizeof(chanspec_t);
14856
14857 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
14858 join_params->params.chanspec_list[0] |= chanspec;
14859 join_params->params.chanspec_list[0] =
14860 wl_chspec_host_to_driver(join_params->params.chanspec_list[0]);
14861
14862 join_params->params.chanspec_num =
14863 htod32(join_params->params.chanspec_num);
14864 }
14865 #ifdef ESCAN_CHANNEL_CACHE
14866 else {
14867 /* If channel is not present and ESCAN_CHANNEL_CACHE is enabled,
14868 * use the cached channel list
14869 */
14870 int n_channels;
14871 n_channels = get_roam_channel_list(ch, join_params->params.chanspec_list,
14872 MAX_ROAM_CHANNEL, &join_params->ssid, ioctl_version);
14873 join_params->params.chanspec_num = htod32(n_channels);
14874 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
14875 join_params->params.chanspec_num * sizeof(chanspec_t);
14876 }
14877 #endif /* ESCAN_CHANNEL_CACHE */
14878
14879 WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
14880 join_params->params.chanspec_list[0],
14881 join_params->params.chanspec_num));
14882 return 0;
14883 }
14884
14885 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam)
14886 {
14887 struct cfg80211_bss *bss;
14888 wl_bss_info_t *bi;
14889 struct wlc_ssid *ssid;
14890 const struct bcm_tlv *tim;
14891 s32 beacon_interval;
14892 s32 dtim_period;
14893 size_t ie_len;
14894 const u8 *ie;
14895 u8 *curbssid;
14896 s32 err = 0;
14897 struct wiphy *wiphy;
14898 u32 channel;
14899 char *buf;
14900 u32 freq, band;
14901
14902 wiphy = bcmcfg_to_wiphy(cfg);
14903
14904 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
14905 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14906 bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
14907 ssid->SSID, ssid->SSID_len);
14908 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
14909 if (!buf) {
14910 WL_ERR(("buffer alloc failed.\n"));
14911 return BCME_NOMEM;
14912 }
14913 mutex_lock(&cfg->usr_sync);
14914 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
14915 err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX);
14916 if (unlikely(err)) {
14917 WL_ERR(("Could not get bss info %d\n", err));
14918 goto update_bss_info_out;
14919 }
14920 bi = (wl_bss_info_t *)(buf + 4);
14921 channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
14922 wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN);
14923
14924 if (!bss) {
14925 WL_DBG(("Could not find the AP\n"));
14926 if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
14927 WL_ERR(("Bssid doesn't match\n"));
14928 err = -EIO;
14929 goto update_bss_info_out;
14930 }
14931 err = wl_inform_single_bss(cfg, bi, roam);
14932 if (unlikely(err))
14933 goto update_bss_info_out;
14934
14935 ie = ((u8 *)bi) + bi->ie_offset;
14936 ie_len = bi->ie_length;
14937 beacon_interval = cpu_to_le16(bi->beacon_period);
14938 } else {
14939 WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
14940 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
14941 freq = ieee80211_channel_to_frequency(channel);
14942 #else
14943 band = (channel <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
14944 freq = ieee80211_channel_to_frequency(channel, band);
14945 #endif // endif
14946 bss->channel = ieee80211_get_channel(wiphy, freq);
14947 #if defined(WL_CFG80211_P2P_DEV_IF)
14948 ie = (const u8 *)bss->ies->data;
14949 ie_len = bss->ies->len;
14950 #else
14951 ie = bss->information_elements;
14952 ie_len = bss->len_information_elements;
14953 #endif /* WL_CFG80211_P2P_DEV_IF */
14954 beacon_interval = bss->beacon_interval;
14955
14956 CFG80211_PUT_BSS(wiphy, bss);
14957 }
14958
14959 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
14960 if (tim) {
14961 dtim_period = tim->data[1];
14962 } else {
14963 /*
14964 * active scan was done so we could not get dtim
14965 * information out of probe response.
14966 * so we speficially query dtim information.
14967 */
14968 dtim_period = 0;
14969 err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD,
14970 &dtim_period, sizeof(dtim_period));
14971 if (unlikely(err)) {
14972 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
14973 goto update_bss_info_out;
14974 }
14975 }
14976
14977 wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
14978 wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
14979
14980 update_bss_info_out:
14981 if (unlikely(err)) {
14982 WL_ERR(("Failed with error %d\n", err));
14983 }
14984
14985 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
14986 mutex_unlock(&cfg->usr_sync);
14987 return err;
14988 }
14989
14990 static s32
14991 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14992 const wl_event_msg_t *e, void *data)
14993 {
14994 struct wl_connect_info *conn_info = wl_to_conn(cfg);
14995 s32 err = 0;
14996 u8 *curbssid;
14997 u32 *channel;
14998 scb_val_t scbval;
14999 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15000 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15001 struct ieee80211_supported_band *band;
15002 struct ieee80211_channel *notify_channel = NULL;
15003 u32 freq;
15004 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
15005 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
15006 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
15007 struct cfg80211_roam_info roam_info;
15008 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
15009 #ifdef WLFBT
15010 uint32 data_len = 0;
15011 if (data)
15012 data_len = ntoh32(e->datalen);
15013 #endif /* WLFBT */
15014
15015 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15016 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
15017
15018 if ((err = wl_get_assoc_ies(cfg, ndev)) != BCME_OK) {
15019 WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
15020 " upper layer\n"));
15021 /* To make sure disconnect, and fw sync, explictly send dissassoc
15022 * for BSSID 00:00:00:00:00:00 issue
15023 */
15024 memset(&scbval, 0, sizeof(scb_val_t));
15025 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
15026 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
15027 scbval.val = htod32(scbval.val);
15028 if (wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
15029 sizeof(scb_val_t)) < 0) {
15030 WL_ERR(("WLC_DISASSOC error\n"));
15031 }
15032 goto fail;
15033 }
15034
15035 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID);
15036 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15037 if ((err = wl_update_bss_info(cfg, ndev, true)) != BCME_OK) {
15038 WL_ERR(("failed to update bss info, err=%d\n", err));
15039 goto fail;
15040 }
15041 wl_update_pmklist(ndev, cfg->pmk_list, err);
15042
15043 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
15044 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15045 /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
15046 if (*channel <= CH_MAX_2G_CHANNEL)
15047 band = wiphy->bands[NL80211_BAND_2GHZ];
15048 else
15049 band = wiphy->bands[NL80211_BAND_5GHZ];
15050 freq = ieee80211_channel_to_frequency(*channel, band->band);
15051 notify_channel = ieee80211_get_channel(wiphy, freq);
15052 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
15053 #ifdef WLFBT
15054 /* back up the given FBT key for the further supplicant request,
15055 * currently not checking the FBT is enabled for current BSS in DHD,
15056 * because the supplicant decides to take it or not.
15057 */
15058 if (data && (data_len == FBT_KEYLEN)) {
15059 memcpy(cfg->fbt_key, data, FBT_KEYLEN);
15060 }
15061 #endif /* WLFBT */
15062 #ifdef CUSTOM_LONG_RETRY_LIMIT
15063 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
15064 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
15065 }
15066 #endif /* CUSTOM_LONG_RETRY_LIMIT */
15067 WL_ERR(("Report roam event to upper layer. " MACDBG " (ch:%d)\n",
15068 MAC2STRDBG((const u8*)(&e->addr)), *channel));
15069
15070 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
15071 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
15072 memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
15073 roam_info.channel = notify_channel;
15074 roam_info.bssid = curbssid;
15075 roam_info.req_ie = conn_info->req_ie;
15076 roam_info.req_ie_len = conn_info->req_ie_len;
15077 roam_info.resp_ie = conn_info->resp_ie;
15078 roam_info.resp_ie_len = conn_info->resp_ie_len;
15079
15080 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
15081 #else
15082 cfg80211_roamed(ndev,
15083 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15084 notify_channel,
15085 #endif // endif
15086 curbssid,
15087 conn_info->req_ie, conn_info->req_ie_len,
15088 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
15089 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
15090
15091 memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
15092 wl_set_drv_status(cfg, CONNECTED, ndev);
15093
15094 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
15095 #ifdef DYNAMIC_MUMIMO_CONTROL
15096 if (!wl_get_murx_reassoc_status(cfg))
15097 #endif /* DYNAMIC_MUMIMO_CONTROL */
15098 {
15099 cfg->roam_count++;
15100 }
15101 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
15102
15103 #ifdef DYNAMIC_MUMIMO_CONTROL
15104 if (wl_get_murx_reassoc_status(cfg)) {
15105 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15106 bool sec_wpa = sec ? (sec->wpa_versions &
15107 (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) : FALSE;
15108 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15109 if (!sec_wpa) {
15110 wl_set_murx_reassoc_status(cfg, FALSE);
15111 WL_DBG(("Security is not WPA nor WPA2\n"));
15112 } else {
15113 WL_DBG(("Security is WPA or WPA2\n"));
15114 }
15115 wl_set_murx_block_eapol_status(cfg, FALSE);
15116 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
15117 }
15118 #endif /* DYNAMIC_MUMIMO_CONTROL */
15119
15120 #ifdef WL_BAM
15121 if (wl_adps_bad_ap_check(cfg, &e->addr)) {
15122 if (wl_adps_enabled(cfg, ndev)) {
15123 wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
15124 }
15125 }
15126 #endif /* WL_BAM */
15127
15128 return err;
15129
15130 fail:
15131 #ifdef DHD_LOSSLESS_ROAMING
15132 wl_del_roam_timeout(cfg);
15133 #endif /* DHD_LOSSLESS_ROAMING */
15134 return err;
15135 }
15136
15137 static bool
15138 wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15139 struct cfg80211_bss **bss)
15140 {
15141 struct wiphy *wiphy;
15142 struct wlc_ssid *ssid;
15143 uint8 *curbssid;
15144 int count = 0;
15145 int ret = false;
15146 u8 cur_ssid[DOT11_MAX_SSID_LEN + 1];
15147
15148 wiphy = bcmcfg_to_wiphy(cfg);
15149 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
15150 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15151 if (!ssid) {
15152 WL_ERR(("No SSID found in the saved profile \n"));
15153 return false;
15154 }
15155
15156 do {
15157 *bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
15158 ssid->SSID, ssid->SSID_len);
15159 if (*bss || (count > 5)) {
15160 break;
15161 }
15162
15163 count++;
15164 msleep(100);
15165 } while (*bss == NULL);
15166
15167 WL_DBG(("cfg80211 bss_ptr:%p loop_cnt:%d\n", *bss, count));
15168 if (*bss) {
15169 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
15170 /* Update the reference count after use. In case of kernel version >= 4.7
15171 * the cfg802_put_bss is called in cfg80211_connect_bss context
15172 */
15173 CFG80211_PUT_BSS(wiphy, *bss);
15174 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
15175 ret = true;
15176 } else {
15177 memset(cur_ssid, 0, DOT11_MAX_SSID_LEN);
15178 strncpy(cur_ssid, ssid->SSID,
15179 MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN));
15180 WL_ERR(("No bss entry for ssid:%s bssid:"MACDBG"\n",
15181 cur_ssid, MAC2STRDBG(curbssid)));
15182 }
15183
15184 return ret;
15185 }
15186 static void wl_notify_scan_done(struct bcm_cfg80211 *cfg, bool aborted)
15187 {
15188 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
15189 struct cfg80211_scan_info info;
15190
15191 memset(&info, 0, sizeof(struct cfg80211_scan_info));
15192 info.aborted = aborted;
15193 cfg80211_scan_done(cfg->scan_request, &info);
15194 #else
15195 cfg80211_scan_done(cfg->scan_request, aborted);
15196 #endif // endif
15197 }
15198
15199 static s32
15200 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15201 const wl_event_msg_t *e, void *data, bool completed)
15202 {
15203 struct wl_connect_info *conn_info = wl_to_conn(cfg);
15204 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15205 s32 err = 0;
15206 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15207 u32 event_type = ntoh32(e->event_type);
15208 struct cfg80211_bss *bss = NULL;
15209 dhd_pub_t *dhdp;
15210 dhdp = (dhd_pub_t *)(cfg->pub);
15211 BCM_REFERENCE(dhdp);
15212
15213 if (!sec) {
15214 WL_ERR(("sec is NULL\n"));
15215 return -ENODEV;
15216 }
15217 WL_DBG((" enter\n"));
15218 #ifdef ESCAN_RESULT_PATCH
15219 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15220 if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) {
15221 WL_INFORM_MEM((" Connected event of connected "
15222 "device e=%d s=%d, ignore it\n",
15223 ntoh32(e->event_type), ntoh32(e->status)));
15224 return err;
15225 }
15226 }
15227 if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 &&
15228 memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) {
15229 WL_DBG(("copy bssid\n"));
15230 memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN);
15231 }
15232 #else
15233 if (cfg->scan_request) {
15234 wl_cfg80211_cancel_scan(cfg);
15235 }
15236 #endif /* ESCAN_RESULT_PATCH */
15237 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
15238 wl_cfg80211_scan_abort(cfg);
15239 if (completed) {
15240 wl_get_assoc_ies(cfg, ndev);
15241 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
15242 WL_PROF_BSSID);
15243 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15244 wl_update_bss_info(cfg, ndev, false);
15245 wl_update_pmklist(ndev, cfg->pmk_list, err);
15246 wl_set_drv_status(cfg, CONNECTED, ndev);
15247 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
15248 if (dhdp->roam_env_detection)
15249 wldev_iovar_setint(ndev, "roam_env_detection",
15250 AP_ENV_INDETERMINATE);
15251 #endif /* ROAM_AP_ENV_DETECTION */
15252 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
15253 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
15254 init_completion(&cfg->iface_disable);
15255 #else
15256 /* reinitialize completion to clear previous count */
15257 INIT_COMPLETION(cfg->iface_disable);
15258 #endif // endif
15259 }
15260 #ifdef CUSTOM_SET_CPUCORE
15261 if (wl_get_chan_isvht80(ndev, dhdp)) {
15262 if (ndev == bcmcfg_to_prmry_ndev(cfg))
15263 dhdp->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
15264 else if (is_p2p_group_iface(ndev->ieee80211_ptr))
15265 dhdp->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
15266 dhd_set_cpucore(dhdp, TRUE);
15267 }
15268 #endif /* CUSTOM_SET_CPUCORE */
15269 #ifdef CUSTOM_LONG_RETRY_LIMIT
15270 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
15271 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
15272 }
15273 #endif /* CUSTOM_LONG_RETRY_LIMIT */
15274 memset(&cfg->last_roamed_addr, 0, ETHER_ADDR_LEN);
15275 }
15276 wl_clr_drv_status(cfg, CONNECTING, ndev);
15277
15278 if (completed && (wl_cfg80211_verify_bss(cfg, ndev, &bss) != true)) {
15279 /* If bss entry is not available in the cfg80211 bss cache
15280 * the wireless stack will complain and won't populate
15281 * wdev->current_bss ptr
15282 */
15283 WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
15284 completed = false;
15285 sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
15286 }
15287
15288 CFG80211_CONNECT_RESULT(ndev,
15289 curbssid,
15290 bss,
15291 conn_info->req_ie,
15292 conn_info->req_ie_len,
15293 conn_info->resp_ie,
15294 conn_info->resp_ie_len,
15295 completed ? WLAN_STATUS_SUCCESS :
15296 (sec->auth_assoc_res_status) ?
15297 sec->auth_assoc_res_status :
15298 WLAN_STATUS_UNSPECIFIED_FAILURE,
15299 GFP_KERNEL);
15300
15301 if (completed) {
15302 WL_INFORM_MEM(("[%s] Report connect result - "
15303 "connection succeeded\n", ndev->name));
15304 #ifdef WL_BAM
15305 if (wl_adps_bad_ap_check(cfg, &e->addr)) {
15306 if (wl_adps_enabled(cfg, ndev)) {
15307 wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
15308 }
15309 }
15310 #endif /* WL_BAM */
15311 } else
15312 WL_ERR(("[%s] Report connect result - connection failed\n", ndev->name));
15313 } else {
15314 WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
15315 " connecting:%x. connected:%d\n",
15316 ndev->name, event_type, wl_get_drv_status(cfg, CONNECTING, ndev),
15317 wl_get_drv_status(cfg, CONNECTED, ndev)));
15318 }
15319 #ifdef CONFIG_TCPACK_FASTTX
15320 if (wl_get_chan_isvht80(ndev, dhdp))
15321 wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
15322 else
15323 wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
15324 #endif /* CONFIG_TCPACK_FASTTX */
15325
15326 return err;
15327 }
15328
15329 static s32
15330 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15331 const wl_event_msg_t *e, void *data)
15332 {
15333 struct net_device *ndev = NULL;
15334 u16 flags = ntoh16(e->flags);
15335 enum nl80211_key_type key_type;
15336
15337 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15338
15339 WL_INFORM_MEM(("[%s] mic fail event - " MACDBG " \n",
15340 ndev->name, MAC2STRDBG(e->addr.octet)));
15341 mutex_lock(&cfg->usr_sync);
15342 if (flags & WLC_EVENT_MSG_GROUP)
15343 key_type = NL80211_KEYTYPE_GROUP;
15344 else
15345 key_type = NL80211_KEYTYPE_PAIRWISE;
15346
15347 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
15348 cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1,
15349 NULL, GFP_KERNEL);
15350 mutex_unlock(&cfg->usr_sync);
15351
15352 return 0;
15353 }
15354
15355 #ifdef BT_WIFI_HANDOVER
15356 static s32
15357 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15358 const wl_event_msg_t *e, void *data)
15359 {
15360 struct net_device *ndev = NULL;
15361 u32 event = ntoh32(e->event_type);
15362 u32 datalen = ntoh32(e->datalen);
15363 s32 err;
15364
15365 WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen));
15366 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15367 err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0);
15368
15369 return err;
15370 }
15371 #endif /* BT_WIFI_HANDOVER */
15372
15373 #ifdef PNO_SUPPORT
15374 static s32
15375 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15376 const wl_event_msg_t *e, void *data)
15377 {
15378 struct net_device *ndev = NULL;
15379 #ifdef GSCAN_SUPPORT
15380 void *ptr;
15381 int send_evt_bytes = 0;
15382 u32 event = be32_to_cpu(e->event_type);
15383 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15384 #endif /* GSCAN_SUPPORT */
15385
15386 WL_INFORM_MEM((">>> PNO Event\n"));
15387
15388 if (!data) {
15389 WL_ERR(("Data received is NULL!\n"));
15390 return 0;
15391 }
15392
15393 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15394 #ifdef GSCAN_SUPPORT
15395 ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes);
15396 if (ptr) {
15397 wl_cfgvendor_send_async_event(wiphy, ndev,
15398 GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes);
15399 MFREE(cfg->osh, ptr, send_evt_bytes);
15400 }
15401 if (!dhd_dev_is_legacy_pno_enabled(ndev))
15402 return 0;
15403 #endif /* GSCAN_SUPPORT */
15404
15405 #ifndef WL_SCHED_SCAN
15406 mutex_lock(&cfg->usr_sync);
15407 /* TODO: Use cfg80211_sched_scan_results(wiphy); */
15408 CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
15409 mutex_unlock(&cfg->usr_sync);
15410 #else
15411 /* If cfg80211 scheduled scan is supported, report the pno results via sched
15412 * scan results
15413 */
15414 wl_notify_sched_scan_results(cfg, ndev, e, data);
15415 #endif /* WL_SCHED_SCAN */
15416 return 0;
15417 }
15418 #endif /* PNO_SUPPORT */
15419
15420 #ifdef GSCAN_SUPPORT
15421 static s32
15422 wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15423 const wl_event_msg_t *e, void *data)
15424 {
15425 s32 err = 0;
15426 u32 event = be32_to_cpu(e->event_type);
15427 void *ptr = NULL;
15428 int send_evt_bytes = 0;
15429 int event_type;
15430 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15431 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15432 u32 len = ntoh32(e->datalen);
15433 u32 buf_len = 0;
15434
15435 switch (event) {
15436 case WLC_E_PFN_BEST_BATCHING:
15437 err = dhd_dev_retrieve_batch_scan(ndev);
15438 if (err < 0) {
15439 WL_ERR(("Batch retrieval already in progress %d\n", err));
15440 } else {
15441 event_type = WIFI_SCAN_THRESHOLD_NUM_SCANS;
15442 if (data && len) {
15443 event_type = *((int *)data);
15444 }
15445 wl_cfgvendor_send_async_event(wiphy, ndev,
15446 GOOGLE_GSCAN_BATCH_SCAN_EVENT,
15447 &event_type, sizeof(int));
15448 }
15449 break;
15450 case WLC_E_PFN_SCAN_COMPLETE:
15451 event_type = WIFI_SCAN_COMPLETE;
15452 wl_cfgvendor_send_async_event(wiphy, ndev,
15453 GOOGLE_SCAN_COMPLETE_EVENT,
15454 &event_type, sizeof(int));
15455 break;
15456 case WLC_E_PFN_BSSID_NET_FOUND:
15457 ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes,
15458 HOTLIST_FOUND, &buf_len);
15459 if (ptr) {
15460 wl_cfgvendor_send_hotlist_event(wiphy, ndev,
15461 ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT);
15462 dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_FOUND);
15463 } else {
15464 err = -ENOMEM;
15465 }
15466 break;
15467 case WLC_E_PFN_BSSID_NET_LOST:
15468 /* WLC_E_PFN_BSSID_NET_LOST is conflict shared with WLC_E_PFN_SCAN_ALLGONE
15469 * We currently do not use WLC_E_PFN_SCAN_ALLGONE, so if we get it, ignore
15470 */
15471 if (len) {
15472 ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes,
15473 HOTLIST_LOST, &buf_len);
15474 if (ptr) {
15475 wl_cfgvendor_send_hotlist_event(wiphy, ndev,
15476 ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT);
15477 dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_LOST);
15478 MFREE(cfg->osh, ptr, buf_len);
15479 } else {
15480 err = -ENOMEM;
15481 }
15482 } else {
15483 err = -EINVAL;
15484 }
15485 break;
15486 case WLC_E_PFN_GSCAN_FULL_RESULT:
15487 ptr = dhd_dev_process_full_gscan_result(ndev, data, len, &send_evt_bytes);
15488 if (ptr) {
15489 wl_cfgvendor_send_async_event(wiphy, ndev,
15490 GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes);
15491 MFREE(cfg->osh, ptr, send_evt_bytes);
15492 } else {
15493 err = -ENOMEM;
15494 }
15495 break;
15496 case WLC_E_PFN_SSID_EXT:
15497 ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes);
15498 if (ptr) {
15499 wl_cfgvendor_send_async_event(wiphy, ndev,
15500 GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes);
15501 MFREE(cfg->osh, ptr, send_evt_bytes);
15502 } else {
15503 err = -ENOMEM;
15504 }
15505 break;
15506 default:
15507 WL_ERR(("Unknown event %d\n", event));
15508 break;
15509 }
15510 return err;
15511 }
15512 #endif /* GSCAN_SUPPORT */
15513
15514 static s32
15515 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15516 const wl_event_msg_t *e, void *data)
15517 {
15518 struct channel_info channel_inform;
15519 struct wl_scan_results *bss_list;
15520 struct net_device *ndev = NULL;
15521 u32 len = WL_SCAN_BUF_MAX;
15522 s32 err = 0;
15523 unsigned long flags;
15524
15525 WL_DBG(("Enter \n"));
15526 if (!wl_get_drv_status(cfg, SCANNING, ndev)) {
15527 WL_DBG(("scan is not ready \n"));
15528 return err;
15529 }
15530 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15531
15532 mutex_lock(&cfg->scan_sync);
15533 wl_clr_drv_status(cfg, SCANNING, ndev);
15534 memset(&channel_inform, 0, sizeof(channel_inform));
15535 err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &channel_inform,
15536 sizeof(channel_inform));
15537 if (unlikely(err)) {
15538 WL_ERR(("scan busy (%d)\n", err));
15539 goto scan_done_out;
15540 }
15541 channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
15542 if (unlikely(channel_inform.scan_channel)) {
15543
15544 WL_DBG(("channel_inform.scan_channel (%d)\n",
15545 channel_inform.scan_channel));
15546 }
15547 cfg->bss_list = cfg->scan_results;
15548 bss_list = cfg->bss_list;
15549 memset(bss_list, 0, len);
15550 bss_list->buflen = htod32(len);
15551 err = wldev_ioctl_get(ndev, WLC_SCAN_RESULTS, bss_list, len);
15552 if (unlikely(err) && unlikely(!cfg->scan_suppressed)) {
15553 WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
15554 err = -EINVAL;
15555 goto scan_done_out;
15556 }
15557 bss_list->buflen = dtoh32(bss_list->buflen);
15558 bss_list->version = dtoh32(bss_list->version);
15559 bss_list->count = dtoh32(bss_list->count);
15560
15561 err = wl_inform_bss(cfg);
15562
15563 scan_done_out:
15564 del_timer_sync(&cfg->scan_timeout);
15565 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
15566 if (cfg->scan_request) {
15567 wl_notify_scan_done(cfg, false);
15568 cfg->scan_request = NULL;
15569 }
15570 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
15571 WL_DBG(("cfg80211_scan_done\n"));
15572 mutex_unlock(&cfg->scan_sync);
15573 return err;
15574 }
15575
15576 static s32
15577 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
15578 const struct ether_addr *da, const struct ether_addr *sa,
15579 const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody)
15580 {
15581 struct dot11_management_header *hdr;
15582 u32 totlen = 0;
15583 s32 err = 0;
15584 u8 *offset;
15585 u32 prebody_len = *body_len;
15586 switch (fc) {
15587 case FC_ASSOC_REQ:
15588 /* capability , listen interval */
15589 totlen = DOT11_ASSOC_REQ_FIXED_LEN;
15590 *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
15591 break;
15592
15593 case FC_REASSOC_REQ:
15594 /* capability, listen inteval, ap address */
15595 totlen = DOT11_REASSOC_REQ_FIXED_LEN;
15596 *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
15597 break;
15598 }
15599 totlen += DOT11_MGMT_HDR_LEN + prebody_len;
15600 *pheader = (u8 *)MALLOCZ(cfg->osh, totlen);
15601 if (*pheader == NULL) {
15602 WL_ERR(("memory alloc failed \n"));
15603 return -ENOMEM;
15604 }
15605 hdr = (struct dot11_management_header *) (*pheader);
15606 hdr->fc = htol16(fc);
15607 hdr->durid = 0;
15608 hdr->seq = 0;
15609 offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
15610 bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
15611 bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
15612 bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
15613 if ((pbody != NULL) && prebody_len)
15614 bcopy((const char*)pbody, offset, prebody_len);
15615 *body_len = totlen;
15616 return err;
15617 }
15618
15619 #ifdef WL_CFG80211_GON_COLLISION
15620 static void
15621 wl_gon_req_collision(struct bcm_cfg80211 *cfg, wl_action_frame_t *tx_act_frm,
15622 wifi_p2p_pub_act_frame_t *rx_act_frm, struct net_device *ndev,
15623 struct ether_addr sa, struct ether_addr da)
15624 {
15625 if (cfg->afx_hdl->pending_tx_act_frm == NULL)
15626 return;
15627
15628 if (tx_act_frm &&
15629 wl_cfgp2p_is_pub_action(tx_act_frm->data, tx_act_frm->len)) {
15630 wifi_p2p_pub_act_frame_t *pact_frm;
15631
15632 pact_frm = (wifi_p2p_pub_act_frame_t *)tx_act_frm->data;
15633
15634 if (!(pact_frm->subtype == P2P_PAF_GON_REQ &&
15635 rx_act_frm->subtype == P2P_PAF_GON_REQ)) {
15636 return;
15637 }
15638 }
15639
15640 WL_ERR((" GO NEGO Request COLLISION !!! \n"));
15641
15642 /* if sa(peer) addr is less than da(my) addr,
15643 * my device will process peer's gon request and block to send my gon req.
15644 *
15645 * if not (sa addr > da addr),
15646 * my device will process gon request and drop gon req of peer.
15647 */
15648 if (memcmp(sa.octet, da.octet, ETHER_ADDR_LEN) < 0) {
15649 /* block to send tx gon request */
15650 cfg->block_gon_req_tx_count = BLOCK_GON_REQ_MAX_NUM;
15651 WL_ERR((" block to send gon req tx !!!\n"));
15652
15653 /* if we are finding a common channel for sending af,
15654 * do not scan more to block to send current gon req
15655 */
15656 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
15657 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, ndev);
15658 complete(&cfg->act_frm_scan);
15659 }
15660 } else {
15661 /* drop gon request of peer to process gon request by my device. */
15662 WL_ERR((" drop to receive gon req rx !!! \n"));
15663 cfg->block_gon_req_rx_count = BLOCK_GON_REQ_MAX_NUM;
15664 }
15665
15666 return;
15667 }
15668 #endif /* WL_CFG80211_GON_COLLISION */
15669
15670 void
15671 wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 bsscfgidx)
15672 {
15673 s32 err = 0;
15674
15675 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
15676 if (timer_pending(&cfg->p2p->listen_timer)) {
15677 del_timer_sync(&cfg->p2p->listen_timer);
15678 }
15679 if (cfg->afx_hdl != NULL) {
15680 if (cfg->afx_hdl->dev != NULL) {
15681 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
15682 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev);
15683 }
15684 cfg->afx_hdl->peer_chan = WL_INVALID;
15685 }
15686 complete(&cfg->act_frm_scan);
15687 WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
15688 } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
15689 if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
15690 wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
15691 wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
15692
15693 WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx));
15694 /* Scan engine is not used for sending action frames in the latest driver
15695 * branches. actframe_abort is used in the latest driver branches
15696 * instead of scan abort.
15697 * If actframe_abort iovar succeeds, don't execute scan abort.
15698 * If actframe_abort fails with unsupported error,
15699 * execute scan abort (for backward copmatibility).
15700 */
15701 if (cfg->af_sent_channel) {
15702 err = wldev_iovar_setint_bsscfg(ndev, "actframe_abort", 1, bsscfgidx);
15703 if (err < 0) {
15704 if (err == BCME_UNSUPPORTED) {
15705 wl_cfg80211_scan_abort(cfg);
15706 } else {
15707 WL_ERR(("actframe_abort failed. ret:%d\n", err));
15708 }
15709 }
15710 }
15711 }
15712 #ifdef WL_CFG80211_SYNC_GON
15713 else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
15714 WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
15715 /* So abort scan to cancel listen */
15716 wl_cfg80211_scan_abort(cfg);
15717 }
15718 #endif /* WL_CFG80211_SYNC_GON */
15719 }
15720
15721 #if defined(WLTDLS)
15722 bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len)
15723 {
15724 unsigned char *data;
15725
15726 if (frame == NULL) {
15727 WL_ERR(("Invalid frame \n"));
15728 return false;
15729 }
15730
15731 if (frame_len < 5) {
15732 WL_ERR(("Invalid frame length [%d] \n", frame_len));
15733 return false;
15734 }
15735
15736 data = frame;
15737
15738 if (!memcmp(data, TDLS_TUNNELED_PRB_REQ, 5) ||
15739 !memcmp(data, TDLS_TUNNELED_PRB_RESP, 5)) {
15740 WL_DBG(("TDLS Vendor Specific Received type\n"));
15741 return true;
15742 }
15743
15744 return false;
15745 }
15746 #endif /* WLTDLS */
15747
15748 #if defined(WES_SUPPORT)
15749 static int wes_mode = 0;
15750 int wl_cfg80211_set_wes_mode(int mode)
15751 {
15752 wes_mode = mode;
15753 return 0;
15754 }
15755
15756 int wl_cfg80211_get_wes_mode(void)
15757 {
15758 return wes_mode;
15759 }
15760
15761 bool wl_cfg80211_is_wes(void *frame, u32 frame_len)
15762 {
15763 unsigned char *data;
15764
15765 if (frame == NULL) {
15766 WL_ERR(("Invalid frame \n"));
15767 return false;
15768 }
15769
15770 if (frame_len < 4) {
15771 WL_ERR(("Invalid frame length [%d] \n", frame_len));
15772 return false;
15773 }
15774
15775 data = frame;
15776
15777 if (memcmp(data, "\x7f\x00\x00\xf0", 4) == 0) {
15778 WL_DBG(("Receive WES VS Action Frame \n"));
15779 return true;
15780 }
15781
15782 return false;
15783 }
15784 #endif /* WES_SUPPORT */
15785
15786 int wl_cfg80211_get_ioctl_version(void)
15787 {
15788 return ioctl_version;
15789 }
15790
15791 static s32
15792 wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15793 const wl_event_msg_t *e, void *data)
15794 {
15795 struct ieee80211_supported_band *band;
15796 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15797 struct ether_addr da;
15798 struct ether_addr bssid;
15799 bool isfree = false;
15800 s32 err = 0;
15801 s32 freq;
15802 struct net_device *ndev = NULL;
15803 wifi_p2p_pub_act_frame_t *act_frm = NULL;
15804 wifi_p2p_action_frame_t *p2p_act_frm = NULL;
15805 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
15806 wl_event_rx_frame_data_t *rxframe;
15807 u32 event;
15808 u8 *mgmt_frame;
15809 u8 bsscfgidx;
15810 u32 mgmt_frame_len;
15811 u16 channel;
15812 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
15813 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15814 #endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
15815 if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) {
15816 WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen)));
15817 return -EINVAL;
15818 }
15819 mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_t);
15820 event = ntoh32(e->event_type);
15821 bsscfgidx = e->bsscfgidx;
15822 rxframe = (wl_event_rx_frame_data_t *)data;
15823 if (!rxframe) {
15824 WL_ERR(("rxframe: NULL\n"));
15825 return -EINVAL;
15826 }
15827 channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK);
15828 memset(&bssid, 0, ETHER_ADDR_LEN);
15829 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15830 if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) &&
15831 (event == WLC_E_PROBREQ_MSG)) {
15832 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15833 4 && __GNUC_MINOR__ >= 6))
15834 _Pragma("GCC diagnostic push")
15835 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
15836 #endif // endif
15837 struct net_info *iter, *next;
15838 for_each_ndev(cfg, iter, next) {
15839 if (iter->ndev && iter->wdev &&
15840 iter->wdev->iftype == NL80211_IFTYPE_AP) {
15841 ndev = iter->ndev;
15842 cfgdev = ndev_to_cfgdev(ndev);
15843 break;
15844 }
15845 }
15846 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15847 4 && __GNUC_MINOR__ >= 6))
15848 _Pragma("GCC diagnostic pop")
15849 #endif // endif
15850 }
15851
15852 if (channel <= CH_MAX_2G_CHANNEL)
15853 band = wiphy->bands[NL80211_BAND_2GHZ];
15854 else
15855 band = wiphy->bands[NL80211_BAND_5GHZ];
15856 if (!band) {
15857 WL_ERR(("No valid band"));
15858 return -EINVAL;
15859 }
15860 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
15861 freq = ieee80211_channel_to_frequency(channel);
15862 (void)band->band;
15863 #else
15864 freq = ieee80211_channel_to_frequency(channel, band->band);
15865 #endif // endif
15866 if (event == WLC_E_ACTION_FRAME_RX) {
15867 u8 ioctl_buf[WLC_IOCTL_SMLEN];
15868
15869 if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
15870 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx,
15871 NULL)) != BCME_OK) {
15872 WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
15873 goto exit;
15874 }
15875
15876 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
15877 if (err < 0)
15878 WL_ERR(("WLC_GET_BSSID error %d\n", err));
15879 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
15880 err = wl_frame_get_mgmt(cfg, FC_ACTION, &da, &e->addr, &bssid,
15881 &mgmt_frame, &mgmt_frame_len,
15882 (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
15883 if (err < 0) {
15884 WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
15885 mgmt_frame_len, channel, freq));
15886 goto exit;
15887 }
15888 isfree = true;
15889 if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
15890 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
15891 act_frm = (wifi_p2p_pub_act_frame_t *)
15892 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
15893 } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
15894 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
15895 p2p_act_frm = (wifi_p2p_action_frame_t *)
15896 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
15897 (void) p2p_act_frm;
15898 } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
15899 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
15900
15901 sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
15902 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
15903 if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
15904 if (cfg->next_af_subtype == sd_act_frm->action) {
15905 WL_DBG(("We got a right next frame of SD!(%d)\n",
15906 sd_act_frm->action));
15907 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
15908
15909 /* Stop waiting for next AF. */
15910 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
15911 }
15912 }
15913 (void) sd_act_frm;
15914 #ifdef WLTDLS
15915 } else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
15916 (wl_cfg80211_is_tdls_tunneled_frame(
15917 &mgmt_frame[DOT11_MGMT_HDR_LEN],
15918 mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
15919 if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
15920 WL_ERR((" TDLS Action Frame Received type = %d \n",
15921 mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
15922 }
15923 #ifdef TDLS_MSG_ONLY_WFD
15924 if (!dhdp->tdls_mode) {
15925 WL_DBG((" TDLS Frame filtered \n"));
15926 goto exit;
15927 }
15928 #else
15929 if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
15930 cfg->tdls_mgmt_frame = mgmt_frame;
15931 cfg->tdls_mgmt_frame_len = mgmt_frame_len;
15932 cfg->tdls_mgmt_freq = freq;
15933 return 0;
15934 }
15935 #endif /* TDLS_MSG_ONLY_WFD */
15936 #endif /* WLTDLS */
15937 #ifdef QOS_MAP_SET
15938 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
15939 /* update QoS map set table */
15940 bcm_tlv_t * qos_map_ie = NULL;
15941 if ((qos_map_ie = bcm_parse_tlvs(&mgmt_frame[DOT11_MGMT_HDR_LEN],
15942 mgmt_frame_len - DOT11_MGMT_HDR_LEN,
15943 DOT11_MNG_QOS_MAP_ID)) != NULL) {
15944 WL_DBG((" QoS map set IE found in QoS action frame\n"));
15945 if (!cfg->up_table) {
15946 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
15947 }
15948 wl_set_up_table(cfg->up_table, qos_map_ie);
15949 } else {
15950 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
15951 cfg->up_table = NULL;
15952 }
15953 #endif /* QOS_MAP_SET */
15954 #ifdef WBTEXT
15955 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_RRM) {
15956 /* radio measurement category */
15957 switch (mgmt_frame[DOT11_MGMT_HDR_LEN+1]) {
15958 case DOT11_RM_ACTION_NR_REP:
15959 if (wl_cfg80211_recv_nbr_resp(ndev,
15960 &mgmt_frame[DOT11_MGMT_HDR_LEN],
15961 mgmt_frame_len - DOT11_MGMT_HDR_LEN)
15962 == BCME_OK) {
15963 WL_DBG(("RCC updated by nbr response\n"));
15964 }
15965 break;
15966 default:
15967 break;
15968 }
15969 #endif /* WBTEXT */
15970 } else {
15971 /*
15972 * if we got normal action frame and ndev is p2p0,
15973 * we have to change ndev from p2p0 to wlan0
15974 */
15975 #if defined(WES_SUPPORT)
15976 if (wl_cfg80211_is_wes(&mgmt_frame[DOT11_MGMT_HDR_LEN],
15977 mgmt_frame_len - DOT11_MGMT_HDR_LEN) && wes_mode == 0) {
15978 /* Ignore WES VS Action frame */
15979 goto exit;
15980 }
15981 #endif /* WES_SUPPORT */
15982
15983 if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
15984 u8 action = 0;
15985 if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
15986 mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) {
15987 WL_DBG(("Recived action is not public action frame\n"));
15988 } else if (cfg->next_af_subtype == action) {
15989 WL_DBG(("Recived action is the waiting action(%d)\n",
15990 action));
15991 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
15992
15993 /* Stop waiting for next AF. */
15994 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
15995 }
15996 }
15997 }
15998
15999 if (act_frm) {
16000 #ifdef WL_CFG80211_GON_COLLISION
16001 if (act_frm->subtype == P2P_PAF_GON_REQ) {
16002 wl_gon_req_collision(cfg,
16003 &cfg->afx_hdl->pending_tx_act_frm->action_frame,
16004 act_frm, ndev, e->addr, da);
16005
16006 if (cfg->block_gon_req_rx_count) {
16007 WL_ERR(("drop frame GON Req Rx : count (%d)\n",
16008 cfg->block_gon_req_rx_count));
16009 cfg->block_gon_req_rx_count--;
16010 goto exit;
16011 }
16012 } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
16013 /* if go formation done, clear it */
16014 cfg->block_gon_req_tx_count = 0;
16015 cfg->block_gon_req_rx_count = 0;
16016 }
16017 #endif /* WL_CFG80211_GON_COLLISION */
16018
16019 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
16020 if (cfg->next_af_subtype == act_frm->subtype) {
16021 WL_DBG(("Abort wait for next frame, Recieved frame (%d) "
16022 "Next action frame(%d)\n",
16023 act_frm->subtype, cfg->next_af_subtype));
16024 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16025
16026 if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
16027 OSL_SLEEP(20);
16028 }
16029
16030 /* Stop waiting for next AF. */
16031 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16032 } else if ((cfg->next_af_subtype == P2P_PAF_GON_RSP) &&
16033 (act_frm->subtype == P2P_PAF_GON_REQ)) {
16034 /* If current received frame is GO NEG REQ and next
16035 * expected frame is GO NEG RESP, do not send it up.
16036 */
16037 WL_ERR(("GO Neg req received while waiting for RESP."
16038 "Discard incoming frame\n"));
16039 goto exit;
16040 }
16041 }
16042 }
16043
16044 wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
16045 mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel);
16046 if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
16047 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
16048 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
16049 }
16050 } else if (event == WLC_E_PROBREQ_MSG) {
16051
16052 /* Handle probe reqs frame
16053 * WPS-AP certification 4.2.13
16054 */
16055 struct parsed_ies prbreq_ies;
16056 u32 prbreq_ie_len = 0;
16057 bool pbc = 0;
16058
16059 WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
16060 mgmt_frame = (u8 *)(data);
16061 mgmt_frame_len = ntoh32(e->datalen);
16062 if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) {
16063 WL_ERR(("wrong datalen:%d\n", mgmt_frame_len));
16064 return -EINVAL;
16065 }
16066 prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
16067
16068 /* Parse prob_req IEs */
16069 if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16070 prbreq_ie_len, &prbreq_ies) < 0) {
16071 WL_ERR(("Prob req get IEs failed\n"));
16072 return 0;
16073 }
16074 if (prbreq_ies.wps_ie != NULL) {
16075 wl_validate_wps_ie(
16076 (const char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
16077 WL_DBG((" wps_ie exist pbc = %d\n", pbc));
16078 /* if pbc method, send prob_req mgmt frame to upper layer */
16079 if (!pbc)
16080 return 0;
16081 } else
16082 return 0;
16083 } else {
16084 mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
16085
16086 /* wpa supplicant use probe request event for restarting another GON Req.
16087 * but it makes GON Req repetition.
16088 * so if src addr of prb req is same as my target device,
16089 * do not send probe request event during sending action frame.
16090 */
16091 if (event == WLC_E_P2P_PROBREQ_MSG) {
16092 WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
16093 "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
16094
16095 #ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
16096 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) &&
16097 !memcmp(cfg->afx_hdl->tx_dst_addr.octet, e->addr.octet,
16098 ETHER_ADDR_LEN)) {
16099 if (cfg->afx_hdl->pending_tx_act_frm &&
16100 wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
16101 s32 channel = CHSPEC_CHANNEL(hton16(rxframe->channel));
16102 WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
16103 channel));
16104 cfg->afx_hdl->peer_chan = channel;
16105 complete(&cfg->act_frm_scan);
16106 }
16107 }
16108 #endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
16109
16110 /* Filter any P2P probe reqs arriving during the
16111 * GO-NEG Phase
16112 */
16113 if (cfg->p2p &&
16114 #if defined(P2P_IE_MISSING_FIX)
16115 cfg->p2p_prb_noti &&
16116 #endif // endif
16117 wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
16118 WL_DBG(("Filtering P2P probe_req while "
16119 "being in GO-Neg state\n"));
16120 return 0;
16121 }
16122 }
16123 }
16124
16125 if (discover_cfgdev(cfgdev, cfg))
16126 WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
16127 else
16128 WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
16129 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
16130 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
16131 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
16132 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
16133 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
16134 defined(WL_COMPAT_WIRELESS)
16135 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
16136 #else
16137 cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
16138 #endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
16139
16140 WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
16141 mgmt_frame_len, ntoh32(e->datalen), channel, freq));
16142 exit:
16143 if (isfree) {
16144 MFREE(cfg->osh, mgmt_frame, mgmt_frame_len);
16145 }
16146 return err;
16147 }
16148
16149 #ifdef WL_SCHED_SCAN
16150 /* If target scan is not reliable, set the below define to "1" to do a
16151 * full escan
16152 */
16153 #define FULL_ESCAN_ON_PFN_NET_FOUND 0
16154 static s32
16155 wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16156 const wl_event_msg_t *e, void *data)
16157 {
16158 wl_pfn_net_info_v1_t *netinfo, *pnetinfo;
16159 wl_pfn_net_info_v2_t *netinfo_v2, *pnetinfo_v2;
16160 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
16161 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16162 int err = 0;
16163 struct cfg80211_scan_request *request = NULL;
16164 struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT];
16165 struct ieee80211_channel *channel = NULL;
16166 int channel_req = 0;
16167 int band = 0;
16168 wl_pfn_scanresults_v1_t *pfn_result_v1 = (wl_pfn_scanresults_v1_t *)data;
16169 wl_pfn_scanresults_v2_t *pfn_result_v2 = (wl_pfn_scanresults_v2_t *)data;
16170 int n_pfn_results = 0;
16171 log_conn_event_t *event_data = NULL;
16172 tlv_log *tlv_data = NULL;
16173 u32 alloc_len, tlv_len;
16174 u32 payload_len;
16175 u8 tmp_buf[DOT11_MAX_SSID_LEN + 1];
16176
16177 WL_DBG(("Enter\n"));
16178
16179 /* These static asserts guarantee v1/v2 net_info and subnet_info are compatible
16180 * in size and SSID offset, allowing v1 to be used below except for the results
16181 * fields themselves (status, count, offset to netinfo).
16182 */
16183 STATIC_ASSERT(sizeof(wl_pfn_net_info_v1_t) == sizeof(wl_pfn_net_info_v2_t));
16184 STATIC_ASSERT(sizeof(wl_pfn_lnet_info_v1_t) == sizeof(wl_pfn_lnet_info_v2_t));
16185 STATIC_ASSERT(sizeof(wl_pfn_subnet_info_v1_t) == sizeof(wl_pfn_subnet_info_v2_t));
16186 STATIC_ASSERT(OFFSETOF(wl_pfn_subnet_info_v1_t, SSID) ==
16187 OFFSETOF(wl_pfn_subnet_info_v2_t, u.SSID));
16188
16189 /* Extract the version-specific items */
16190 if (pfn_result_v1->version == PFN_SCANRESULT_VERSION_V1) {
16191 n_pfn_results = pfn_result_v1->count;
16192 pnetinfo = pfn_result_v1->netinfo;
16193 WL_INFORM_MEM(("PFN NET FOUND event. count:%d \n", n_pfn_results));
16194
16195 if (n_pfn_results > 0) {
16196 int i;
16197
16198 if (n_pfn_results > MAX_PFN_LIST_COUNT)
16199 n_pfn_results = MAX_PFN_LIST_COUNT;
16200
16201 memset(&ssid, 0x00, sizeof(ssid));
16202
16203 request = (struct cfg80211_scan_request *)MALLOCZ(cfg->osh,
16204 sizeof(*request) + sizeof(*request->channels) * n_pfn_results);
16205 channel = (struct ieee80211_channel *)MALLOCZ(cfg->osh,
16206 (sizeof(struct ieee80211_channel) * n_pfn_results));
16207 if (!request || !channel) {
16208 WL_ERR(("No memory"));
16209 err = -ENOMEM;
16210 goto out_err;
16211 }
16212
16213 request->wiphy = wiphy;
16214
16215 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
16216 alloc_len = sizeof(log_conn_event_t) + DOT11_MAX_SSID_LEN +
16217 sizeof(uint16) + sizeof(int16);
16218 event_data = (log_conn_event_t *)MALLOC(cfg->osh, alloc_len);
16219 if (!event_data) {
16220 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
16221 "length(%d)\n", __func__, alloc_len));
16222 goto out_err;
16223 }
16224 tlv_len = 3 * sizeof(tlv_log);
16225 event_data->tlvs = (tlv_log *)MALLOC(cfg->osh, tlv_len);
16226 if (!event_data->tlvs) {
16227 WL_ERR(("%s: failed to allocate the tlv_log with "
16228 "length(%d)\n", __func__, tlv_len));
16229 goto out_err;
16230 }
16231 }
16232
16233 for (i = 0; i < n_pfn_results; i++) {
16234 netinfo = &pnetinfo[i];
16235 if (!netinfo) {
16236 WL_ERR(("Invalid netinfo ptr. index:%d", i));
16237 err = -EINVAL;
16238 goto out_err;
16239 }
16240 if (netinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
16241 WL_ERR(("Wrong SSID length:%d\n",
16242 netinfo->pfnsubnet.SSID_len));
16243 err = -EINVAL;
16244 goto out_err;
16245 }
16246 memcpy(tmp_buf, netinfo->pfnsubnet.SSID,
16247 netinfo->pfnsubnet.SSID_len);
16248 tmp_buf[netinfo->pfnsubnet.SSID_len] = '\0';
16249 WL_PNO((">>> SSID:%s Channel:%d \n",
16250 tmp_buf, netinfo->pfnsubnet.channel));
16251 /* PFN result doesn't have all the info which are required by
16252 * the supplicant. (For e.g IEs) Do a target Escan so that
16253 * sched scan results are reported via wl_inform_single_bss in
16254 * the required format. Escan does require the scan request in
16255 * the form of cfg80211_scan_request. For timebeing, create
16256 * cfg80211_scan_request one out of the received PNO event.
16257 */
16258
16259 ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len;
16260 memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID,
16261 ssid[i].ssid_len);
16262 request->n_ssids++;
16263
16264 channel_req = netinfo->pfnsubnet.channel;
16265 band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
16266 : NL80211_BAND_5GHZ;
16267 channel[i].center_freq =
16268 ieee80211_channel_to_frequency(channel_req, band);
16269 channel[i].band = band;
16270 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
16271 request->channels[i] = &channel[i];
16272 request->n_channels++;
16273
16274 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
16275 payload_len = sizeof(log_conn_event_t);
16276 event_data->event = WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND;
16277 tlv_data = event_data->tlvs;
16278
16279 /* ssid */
16280 tlv_data->tag = WIFI_TAG_SSID;
16281 tlv_data->len = ssid[i].ssid_len;
16282 memcpy(tlv_data->value, ssid[i].ssid, ssid[i].ssid_len);
16283 payload_len += TLV_LOG_SIZE(tlv_data);
16284 tlv_data = TLV_LOG_NEXT(tlv_data);
16285
16286 /* channel */
16287 tlv_data->tag = WIFI_TAG_CHANNEL;
16288 tlv_data->len = sizeof(uint16);
16289 memcpy(tlv_data->value, &channel_req, sizeof(uint16));
16290 payload_len += TLV_LOG_SIZE(tlv_data);
16291 tlv_data = TLV_LOG_NEXT(tlv_data);
16292
16293 /* rssi */
16294 tlv_data->tag = WIFI_TAG_RSSI;
16295 tlv_data->len = sizeof(int16);
16296 memcpy(tlv_data->value, &netinfo->RSSI, sizeof(int16));
16297 payload_len += TLV_LOG_SIZE(tlv_data);
16298 tlv_data = TLV_LOG_NEXT(tlv_data);
16299
16300 dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
16301 &event_data->event, payload_len);
16302 }
16303 }
16304
16305 /* assign parsed ssid array */
16306 if (request->n_ssids)
16307 request->ssids = &ssid[0];
16308
16309 if (wl_get_drv_status_all(cfg, SCANNING)) {
16310 /* Abort any on-going scan */
16311 wl_cfg80211_cancel_scan(cfg);
16312 }
16313
16314 if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
16315 WL_PNO((">>> P2P discovery was ON. Disabling it\n"));
16316 err = wl_cfgp2p_discover_enable_search(cfg, false);
16317 if (unlikely(err)) {
16318 wl_clr_drv_status(cfg, SCANNING, ndev);
16319 goto out_err;
16320 }
16321 p2p_scan(cfg) = false;
16322 }
16323 wl_set_drv_status(cfg, SCANNING, ndev);
16324 #if FULL_ESCAN_ON_PFN_NET_FOUND
16325 WL_PNO((">>> Doing Full ESCAN on PNO event\n"));
16326 err = wl_do_escan(cfg, wiphy, ndev, NULL);
16327 #else
16328 WL_PNO((">>> Doing targeted ESCAN on PNO event\n"));
16329 err = wl_do_escan(cfg, wiphy, ndev, request);
16330 #endif // endif
16331 if (err) {
16332 wl_clr_drv_status(cfg, SCANNING, ndev);
16333 goto out_err;
16334 }
16335 DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED);
16336 cfg->sched_scan_running = TRUE;
16337 }
16338 else {
16339 WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
16340 }
16341
16342 } else if (pfn_result_v2->version == PFN_SCANRESULT_VERSION_V2) {
16343 n_pfn_results = pfn_result_v2->count;
16344 pnetinfo_v2 = (wl_pfn_net_info_v2_t *)pfn_result_v2->netinfo;
16345
16346 if (e->event_type == WLC_E_PFN_NET_LOST) {
16347 WL_PNO(("Do Nothing %d\n", e->event_type));
16348 return 0;
16349 }
16350
16351 WL_INFORM_MEM(("PFN NET FOUND event. count:%d \n", n_pfn_results));
16352
16353 if (n_pfn_results > 0) {
16354 int i;
16355
16356 if (n_pfn_results > MAX_PFN_LIST_COUNT)
16357 n_pfn_results = MAX_PFN_LIST_COUNT;
16358
16359 memset(&ssid, 0x00, sizeof(ssid));
16360
16361 request = (struct cfg80211_scan_request *)MALLOCZ(cfg->osh,
16362 sizeof(*request) + sizeof(*request->channels) * n_pfn_results);
16363 channel = (struct ieee80211_channel *)MALLOCZ(cfg->osh,
16364 (sizeof(struct ieee80211_channel) * n_pfn_results));
16365 if (!request || !channel) {
16366 WL_ERR(("No memory"));
16367 err = -ENOMEM;
16368 goto out_err;
16369 }
16370
16371 request->wiphy = wiphy;
16372
16373 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
16374 alloc_len = sizeof(log_conn_event_t) + DOT11_MAX_SSID_LEN +
16375 sizeof(uint16) + sizeof(int16);
16376 event_data = (log_conn_event_t *)MALLOC(cfg->osh, alloc_len);
16377 if (!event_data) {
16378 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
16379 "length(%d)\n", __func__, alloc_len));
16380 goto out_err;
16381 }
16382 tlv_len = 3 * sizeof(tlv_log);
16383 event_data->tlvs = (tlv_log *)MALLOC(cfg->osh, tlv_len);
16384 if (!event_data->tlvs) {
16385 WL_ERR(("%s: failed to allocate the tlv_log with "
16386 "length(%d)\n", __func__, tlv_len));
16387 goto out_err;
16388 }
16389 }
16390
16391 for (i = 0; i < n_pfn_results; i++) {
16392 netinfo_v2 = &pnetinfo_v2[i];
16393 if (!netinfo_v2) {
16394 WL_ERR(("Invalid netinfo ptr. index:%d", i));
16395 err = -EINVAL;
16396 goto out_err;
16397 }
16398 WL_PNO((">>> SSID:%s Channel:%d \n",
16399 netinfo_v2->pfnsubnet.u.SSID,
16400 netinfo_v2->pfnsubnet.channel));
16401 /* PFN result doesn't have all the info which are required by the
16402 * supplicant. (For e.g IEs) Do a target Escan so that sched scan
16403 * results are reported via wl_inform_single_bss in the required
16404 * format. Escan does require the scan request in the form of
16405 * cfg80211_scan_request. For timebeing, create
16406 * cfg80211_scan_request one out of the received PNO event.
16407 */
16408 ssid[i].ssid_len = MIN(DOT11_MAX_SSID_LEN,
16409 netinfo_v2->pfnsubnet.SSID_len);
16410 memcpy(ssid[i].ssid, netinfo_v2->pfnsubnet.u.SSID,
16411 ssid[i].ssid_len);
16412 request->n_ssids++;
16413
16414 channel_req = netinfo_v2->pfnsubnet.channel;
16415 band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
16416 : NL80211_BAND_5GHZ;
16417 channel[i].center_freq =
16418 ieee80211_channel_to_frequency(channel_req, band);
16419 channel[i].band = band;
16420 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
16421 request->channels[i] = &channel[i];
16422 request->n_channels++;
16423
16424 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
16425 payload_len = sizeof(log_conn_event_t);
16426 event_data->event = WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND;
16427 tlv_data = event_data->tlvs;
16428
16429 /* ssid */
16430 tlv_data->tag = WIFI_TAG_SSID;
16431 tlv_data->len = netinfo_v2->pfnsubnet.SSID_len;
16432 memcpy(tlv_data->value, ssid[i].ssid, ssid[i].ssid_len);
16433 payload_len += TLV_LOG_SIZE(tlv_data);
16434 tlv_data = TLV_LOG_NEXT(tlv_data);
16435
16436 /* channel */
16437 tlv_data->tag = WIFI_TAG_CHANNEL;
16438 tlv_data->len = sizeof(uint16);
16439 memcpy(tlv_data->value, &channel_req, sizeof(uint16));
16440 payload_len += TLV_LOG_SIZE(tlv_data);
16441 tlv_data = TLV_LOG_NEXT(tlv_data);
16442
16443 /* rssi */
16444 tlv_data->tag = WIFI_TAG_RSSI;
16445 tlv_data->len = sizeof(int16);
16446 memcpy(tlv_data->value, &netinfo_v2->RSSI, sizeof(int16));
16447 payload_len += TLV_LOG_SIZE(tlv_data);
16448 tlv_data = TLV_LOG_NEXT(tlv_data);
16449
16450 dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
16451 &event_data->event, payload_len);
16452 }
16453 }
16454
16455 /* assign parsed ssid array */
16456 if (request->n_ssids)
16457 request->ssids = &ssid[0];
16458
16459 if (wl_get_drv_status_all(cfg, SCANNING)) {
16460 /* Abort any on-going scan */
16461 wl_cfg80211_cancel_scan(cfg);
16462 }
16463
16464 if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
16465 WL_PNO((">>> P2P discovery was ON. Disabling it\n"));
16466 err = wl_cfgp2p_discover_enable_search(cfg, false);
16467 if (unlikely(err)) {
16468 wl_clr_drv_status(cfg, SCANNING, ndev);
16469 goto out_err;
16470 }
16471 p2p_scan(cfg) = false;
16472 }
16473
16474 wl_set_drv_status(cfg, SCANNING, ndev);
16475 #if FULL_ESCAN_ON_PFN_NET_FOUND
16476 WL_PNO((">>> Doing Full ESCAN on PNO event\n"));
16477 err = wl_do_escan(cfg, wiphy, ndev, NULL);
16478 #else
16479 WL_PNO((">>> Doing targeted ESCAN on PNO event\n"));
16480 err = wl_do_escan(cfg, wiphy, ndev, request);
16481 #endif // endif
16482 if (err) {
16483 wl_clr_drv_status(cfg, SCANNING, ndev);
16484 goto out_err;
16485 }
16486 DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED);
16487 cfg->sched_scan_running = TRUE;
16488 }
16489 else {
16490 WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
16491 }
16492 } else {
16493 WL_ERR(("Unsupported version %d, expected %d or %d\n", pfn_result_v1->version,
16494 PFN_SCANRESULT_VERSION_V1, PFN_SCANRESULT_VERSION_V2));
16495 return 0;
16496 }
16497 out_err:
16498 if (request) {
16499 MFREE(cfg->osh, request,
16500 sizeof(*request) + sizeof(*request->channels) * n_pfn_results);
16501 }
16502 if (channel) {
16503 MFREE(cfg->osh, channel,
16504 (sizeof(struct ieee80211_channel) * n_pfn_results));
16505 }
16506
16507 if (event_data) {
16508 if (event_data->tlvs) {
16509 MFREE(cfg->osh, event_data->tlvs, tlv_len);
16510 }
16511 MFREE(cfg->osh, event_data, alloc_len);
16512 }
16513 return err;
16514 }
16515 #endif /* WL_SCHED_SCAN */
16516
16517 static void wl_init_conf(struct wl_conf *conf)
16518 {
16519 WL_DBG(("Enter \n"));
16520 conf->frag_threshold = (u32)-1;
16521 conf->rts_threshold = (u32)-1;
16522 conf->retry_short = (u32)-1;
16523 conf->retry_long = (u32)-1;
16524 conf->tx_power = -1;
16525 }
16526
16527 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
16528 {
16529 unsigned long flags;
16530 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
16531
16532 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
16533 memset(profile, 0, sizeof(struct wl_profile));
16534 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
16535 }
16536
16537 static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
16538 {
16539 memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler));
16540
16541 cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
16542 cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
16543 cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
16544 cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
16545 cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
16546 cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
16547 cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
16548 cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
16549 cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
16550 cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
16551 cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
16552 cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
16553 cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
16554 cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
16555 cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
16556 cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
16557 cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
16558 cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
16559 cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
16560 cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
16561 #ifdef PNO_SUPPORT
16562 cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
16563 #endif /* PNO_SUPPORT */
16564 #ifdef GSCAN_SUPPORT
16565 cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
16566 cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
16567 cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
16568 cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
16569 cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
16570 cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
16571 cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
16572 cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
16573 #endif /* GSCAN_SUPPORT */
16574 #ifdef RSSI_MONITOR_SUPPORT
16575 cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
16576 #endif /* RSSI_MONITOR_SUPPORT */
16577 #ifdef WLTDLS
16578 cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
16579 #endif /* WLTDLS */
16580 cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
16581 #ifdef WLAIBSS
16582 cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail;
16583 #endif /* WLAIBSS */
16584 #ifdef WL_RELMCAST
16585 cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
16586 #endif /* WL_RELMCAST */
16587 #ifdef BT_WIFI_HANDOVER
16588 cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
16589 #endif // endif
16590 #ifdef WL_NAN
16591 cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status;
16592 cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status;
16593 #endif /* WL_NAN */
16594 cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
16595 cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
16596 #ifdef CUSTOM_EVENT_PM_WAKE
16597 cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
16598 #endif /* CUSTOM_EVENT_PM_WAKE */
16599 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
16600 cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
16601 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
16602 cfg->evt_handler[WLC_E_ROAM_START] = wl_notify_roam_start_status;
16603 #ifdef WL_BAM
16604 cfg->evt_handler[WLC_E_ADPS] = wl_adps_event_handler;
16605 #endif /* WL_BAM */
16606 #ifdef WL_BCNRECV
16607 cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
16608 #endif /* WL_BCNRECV */
16609 }
16610
16611 #if defined(STATIC_WL_PRIV_STRUCT)
16612 static int
16613 wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
16614 {
16615 #ifdef DUAL_ESCAN_RESULT_BUFFER
16616 cfg->escan_info.escan_buf[0] = DHD_OS_PREALLOC(cfg->pub,
16617 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
16618 if (cfg->escan_info.escan_buf[0] == NULL) {
16619 WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
16620 return -ENOMEM;
16621 }
16622
16623 cfg->escan_info.escan_buf[1] = DHD_OS_PREALLOC(cfg->pub,
16624 DHD_PREALLOC_WIPHY_ESCAN1, ESCAN_BUF_SIZE);
16625 if (cfg->escan_info.escan_buf[1] == NULL) {
16626 WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
16627 return -ENOMEM;
16628 }
16629
16630 bzero(cfg->escan_info.escan_buf[0], ESCAN_BUF_SIZE);
16631 bzero(cfg->escan_info.escan_buf[1], ESCAN_BUF_SIZE);
16632 cfg->escan_info.escan_type[0] = 0;
16633 cfg->escan_info.escan_type[1] = 0;
16634 #else
16635 cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
16636 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
16637 if (cfg->escan_info.escan_buf == NULL) {
16638 WL_ERR(("Failed to alloc ESCAN_BUF\n"));
16639 return -ENOMEM;
16640 }
16641 bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
16642 #endif /* DUAL_ESCAN_RESULT_BUFFER */
16643
16644 return 0;
16645 }
16646
16647 static void
16648 wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
16649 {
16650 #ifdef DUAL_ESCAN_RESULT_BUFFER
16651 if (cfg->escan_info.escan_buf[0] != NULL) {
16652 cfg->escan_info.escan_buf[0] = NULL;
16653 cfg->escan_info.escan_type[0] = 0;
16654 }
16655
16656 if (cfg->escan_info.escan_buf[1] != NULL) {
16657 cfg->escan_info.escan_buf[1] = NULL;
16658 cfg->escan_info.escan_type[1] = 0;
16659 }
16660 #else
16661 if (cfg->escan_info.escan_buf != NULL) {
16662 cfg->escan_info.escan_buf = NULL;
16663 }
16664 #endif /* DUAL_ESCAN_RESULT_BUFFER */
16665 }
16666 #endif /* STATIC_WL_PRIV_STRUCT */
16667
16668 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
16669 {
16670 WL_DBG(("Enter \n"));
16671
16672 cfg->scan_results = (struct wl_scan_results *)MALLOCZ(cfg->osh,
16673 WL_SCAN_BUF_MAX);
16674 if (unlikely(!cfg->scan_results)) {
16675 WL_ERR(("Scan results alloc failed\n"));
16676 goto init_priv_mem_out;
16677 }
16678 cfg->conf = (struct wl_conf *)MALLOCZ(cfg->osh, sizeof(*cfg->conf));
16679 if (unlikely(!cfg->conf)) {
16680 WL_ERR(("wl_conf alloc failed\n"));
16681 goto init_priv_mem_out;
16682 }
16683 cfg->scan_req_int = (void *)MALLOCZ(cfg->osh,
16684 sizeof(*cfg->scan_req_int));
16685 if (unlikely(!cfg->scan_req_int)) {
16686 WL_ERR(("Scan req alloc failed\n"));
16687 goto init_priv_mem_out;
16688 }
16689 cfg->ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
16690 if (unlikely(!cfg->ioctl_buf)) {
16691 WL_ERR(("Ioctl buf alloc failed\n"));
16692 goto init_priv_mem_out;
16693 }
16694 cfg->escan_ioctl_buf = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
16695 if (unlikely(!cfg->escan_ioctl_buf)) {
16696 WL_ERR(("Ioctl buf alloc failed\n"));
16697 goto init_priv_mem_out;
16698 }
16699 cfg->extra_buf = (void *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
16700 if (unlikely(!cfg->extra_buf)) {
16701 WL_ERR(("Extra buf alloc failed\n"));
16702 goto init_priv_mem_out;
16703 }
16704 cfg->pmk_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->pmk_list));
16705 if (unlikely(!cfg->pmk_list)) {
16706 WL_ERR(("pmk list alloc failed\n"));
16707 goto init_priv_mem_out;
16708 }
16709 #if defined(STATIC_WL_PRIV_STRUCT)
16710 cfg->conn_info = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->conn_info));
16711 if (unlikely(!cfg->conn_info)) {
16712 WL_ERR(("cfg->conn_info alloc failed\n"));
16713 goto init_priv_mem_out;
16714 }
16715 cfg->ie = (void *)MALLOC(cfg->osh, sizeof(*cfg->ie));
16716 if (unlikely(!cfg->ie)) {
16717 WL_ERR(("cfg->ie alloc failed\n"));
16718 goto init_priv_mem_out;
16719 }
16720 if (unlikely(wl_init_escan_result_buf(cfg))) {
16721 WL_ERR(("Failed to init escan resul buf\n"));
16722 goto init_priv_mem_out;
16723 }
16724 #endif /* STATIC_WL_PRIV_STRUCT */
16725 cfg->afx_hdl = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->afx_hdl));
16726 if (unlikely(!cfg->afx_hdl)) {
16727 WL_ERR(("afx hdl alloc failed\n"));
16728 goto init_priv_mem_out;
16729 } else {
16730 init_completion(&cfg->act_frm_scan);
16731 init_completion(&cfg->wait_next_af);
16732
16733 INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
16734 }
16735 #ifdef WLTDLS
16736 if (cfg->tdls_mgmt_frame) {
16737 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
16738 cfg->tdls_mgmt_frame = NULL;
16739 cfg->tdls_mgmt_frame_len = 0;
16740 }
16741 #endif /* WLTDLS */
16742 return 0;
16743
16744 init_priv_mem_out:
16745 wl_deinit_priv_mem(cfg);
16746
16747 return -ENOMEM;
16748 }
16749
16750 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
16751 {
16752 MFREE(cfg->osh, cfg->scan_results, WL_SCAN_BUF_MAX);
16753 cfg->scan_results = NULL;
16754 MFREE(cfg->osh, cfg->conf, sizeof(*cfg->conf));
16755 cfg->conf = NULL;
16756 MFREE(cfg->osh, cfg->scan_req_int, sizeof(*cfg->scan_req_int));
16757 cfg->scan_req_int = NULL;
16758 MFREE(cfg->osh, cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
16759 cfg->ioctl_buf = NULL;
16760 MFREE(cfg->osh, cfg->escan_ioctl_buf, WLC_IOCTL_MAXLEN);
16761 cfg->escan_ioctl_buf = NULL;
16762 MFREE(cfg->osh, cfg->extra_buf, WL_EXTRA_BUF_MAX);
16763 cfg->extra_buf = NULL;
16764 MFREE(cfg->osh, cfg->pmk_list, sizeof(*cfg->pmk_list));
16765 cfg->pmk_list = NULL;
16766 #if defined(STATIC_WL_PRIV_STRUCT)
16767 MFREE(cfg->osh, cfg->conn_info, sizeof(*cfg->conn_info));
16768 cfg->conn_info = NULL;
16769 MFREE(cfg->osh, cfg->ie, sizeof(*cfg->ie));
16770 cfg->ie = NULL;
16771 wl_deinit_escan_result_buf(cfg);
16772 #endif /* STATIC_WL_PRIV_STRUCT */
16773 if (cfg->afx_hdl) {
16774 cancel_work_sync(&cfg->afx_hdl->work);
16775 MFREE(cfg->osh, cfg->afx_hdl, sizeof(*cfg->afx_hdl));
16776 cfg->afx_hdl = NULL;
16777 }
16778
16779 }
16780
16781 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
16782 {
16783 int ret = 0;
16784 WL_DBG(("Enter \n"));
16785
16786 /* Allocate workqueue for event */
16787 if (!cfg->event_workq) {
16788 cfg->event_workq = alloc_workqueue("dhd_eventd",
16789 WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 1);
16790 }
16791
16792 if (!cfg->event_workq) {
16793 ret = -ENOMEM;
16794 } else {
16795 INIT_WORK(&cfg->event_work, wl_event_handler);
16796 }
16797 return ret;
16798 }
16799
16800 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
16801 {
16802 if (cfg && cfg->event_workq) {
16803 cancel_work_sync(&cfg->event_work);
16804 destroy_workqueue(cfg->event_workq);
16805 cfg->event_workq = NULL;
16806 }
16807 }
16808
16809 void wl_terminate_event_handler(struct net_device *dev)
16810 {
16811 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
16812
16813 if (cfg) {
16814 wl_destroy_event_handler(cfg);
16815 wl_flush_eq(cfg);
16816 }
16817 }
16818
16819 static void wl_scan_timeout(unsigned long data)
16820 {
16821 wl_event_msg_t msg;
16822 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
16823 struct wireless_dev *wdev = NULL;
16824 struct net_device *ndev = NULL;
16825 struct wl_scan_results *bss_list;
16826 wl_bss_info_t *bi = NULL;
16827 s32 i;
16828 u32 channel;
16829 u64 cur_time = OSL_LOCALTIME_NS();
16830 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16831 #ifdef DHD_FW_COREDUMP
16832 uint32 prev_memdump_mode = dhdp->memdump_enabled;
16833 #endif /* DHD_FW_COREDUMP */
16834 unsigned long flags;
16835
16836 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
16837 if (!(cfg->scan_request)) {
16838 WL_ERR(("timer expired but no scan request\n"));
16839 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
16840 return;
16841 } else {
16842 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
16843 if (cfg->scan_request->dev) {
16844 wdev = cfg->scan_request->dev->ieee80211_ptr;
16845 }
16846 #else
16847 wdev = cfg->scan_request->wdev;
16848 #endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
16849 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
16850
16851 if (!wdev) {
16852 WL_ERR(("No wireless_dev present\n"));
16853 return;
16854 }
16855 }
16856
16857 #if defined(DHD_KERNEL_SCHED_DEBUG) && defined(DHD_FW_COREDUMP)
16858 if (prev_memdump_mode && !dhd_query_bus_erros(dhdp) &&
16859 ((cfg->scan_deq_time < cfg->scan_enq_time) ||
16860 dhd_bus_query_dpc_sched_errors(dhdp))) {
16861 WL_ERR(("****SCAN event timeout due to scheduling problem\n"));
16862 /* change g_assert_type to trigger Kernel panic */
16863 g_assert_type = 2;
16864 /* use ASSERT() to trigger panic */
16865 ASSERT(0);
16866 }
16867 #endif /* DHD_KERNEL_SCHED_DEBUG && DHD_FW_COREDUMP */
16868
16869 WL_ERR(("***SCAN event timeout. WQ state:0x%x scan_enq_time:"SEC_USEC_FMT
16870 " evt_hdlr_entry_time:"SEC_USEC_FMT" evt_deq_time:"SEC_USEC_FMT
16871 "\nscan_deq_time:"SEC_USEC_FMT" scan_hdlr_cmplt_time:"SEC_USEC_FMT
16872 " scan_cmplt_time:"SEC_USEC_FMT" evt_hdlr_exit_time:"SEC_USEC_FMT
16873 "\ncurrent_time:"SEC_USEC_FMT"\n", work_busy(&cfg->event_work),
16874 GET_SEC_USEC(cfg->scan_enq_time), GET_SEC_USEC(cfg->wl_evt_hdlr_entry_time),
16875 GET_SEC_USEC(cfg->wl_evt_deq_time), GET_SEC_USEC(cfg->scan_deq_time),
16876 GET_SEC_USEC(cfg->scan_hdlr_cmplt_time), GET_SEC_USEC(cfg->scan_cmplt_time),
16877 GET_SEC_USEC(cfg->wl_evt_hdlr_exit_time), GET_SEC_USEC(cur_time)));
16878 if (cfg->scan_enq_time) {
16879 WL_ERR(("Elapsed time(ns): %llu\n", (cur_time - cfg->scan_enq_time)));
16880 }
16881 WL_ERR(("lock_states:[%d:%d:%d:%d:%d:%d]\n",
16882 mutex_is_locked(&cfg->if_sync),
16883 mutex_is_locked(&cfg->usr_sync),
16884 mutex_is_locked(&cfg->pm_sync),
16885 mutex_is_locked(&cfg->scan_sync),
16886 spin_is_locked(&cfg->cfgdrv_lock),
16887 spin_is_locked(&cfg->eq_lock)));
16888 dhd_bus_intr_count_dump(dhdp);
16889
16890 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) && !defined(CONFIG_MODULES)
16891 /* Print WQ states. Enable only for in-built drivers as the symbol is not exported */
16892 show_workqueue_state();
16893 #endif /* LINUX_VER >= 4.1 && !CONFIG_MODULES */
16894
16895 bss_list = wl_escan_get_buf(cfg, FALSE);
16896 if (!bss_list) {
16897 WL_ERR(("bss_list is null. Didn't receive any partial scan results\n"));
16898 } else {
16899 WL_ERR(("Dump scan buffer:\n"
16900 "scanned AP count (%d)\n", bss_list->count));
16901
16902 bi = next_bss(bss_list, bi);
16903 for_each_bss(bss_list, bi, i) {
16904 channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
16905 WL_ERR(("SSID :%s Channel :%d\n", bi->SSID, channel));
16906 }
16907 }
16908
16909 ndev = wdev_to_wlc_ndev(wdev, cfg);
16910 bzero(&msg, sizeof(wl_event_msg_t));
16911 WL_ERR(("timer expired\n"));
16912 #ifdef BCMPCIE
16913 (void)dhd_pcie_dump_int_regs(dhdp);
16914 dhd_pcie_dump_rc_conf_space_cap(dhdp);
16915 #endif /* BCMPCIE */
16916 #ifdef DHD_FW_COREDUMP
16917 if (dhdp->memdump_enabled) {
16918 dhdp->memdump_enabled = DUMP_MEMFILE;
16919 dhdp->memdump_type = DUMP_TYPE_SCAN_TIMEOUT;
16920 dhd_bus_mem_dump(dhdp);
16921 dhdp->memdump_enabled = prev_memdump_mode;
16922 }
16923 #endif /* DHD_FW_COREDUMP */
16924 msg.event_type = hton32(WLC_E_ESCAN_RESULT);
16925 msg.status = hton32(WLC_E_STATUS_TIMEOUT);
16926 msg.reason = 0xFFFFFFFF;
16927 wl_cfg80211_event(ndev, &msg, NULL);
16928 #ifdef CUSTOMER_HW4_DEBUG
16929 if (!wl_scan_timeout_dbg_enabled)
16930 wl_scan_timeout_dbg_set();
16931 #endif /* CUSTOMER_HW4_DEBUG */
16932 }
16933
16934 #ifdef DHD_LOSSLESS_ROAMING
16935 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
16936 {
16937 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16938
16939 /* restore prec_map to ALLPRIO */
16940 dhdp->dequeue_prec_map = ALLPRIO;
16941 if (timer_pending(&cfg->roam_timeout)) {
16942 del_timer_sync(&cfg->roam_timeout);
16943 }
16944
16945 }
16946
16947 static void wl_roam_timeout(unsigned long data)
16948 {
16949 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
16950 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16951
16952 WL_ERR(("roam timer expired\n"));
16953
16954 /* restore prec_map to ALLPRIO */
16955 dhdp->dequeue_prec_map = ALLPRIO;
16956 }
16957
16958 #endif /* DHD_LOSSLESS_ROAMING */
16959
16960 static s32
16961 wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
16962 unsigned long state, void *ptr)
16963 {
16964 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
16965 struct net_device *dev = ptr;
16966 #else
16967 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
16968 #endif /* LINUX_VERSION < VERSION(3, 11, 0) */
16969 struct wireless_dev *wdev = NULL;
16970 struct bcm_cfg80211 *cfg = NULL;
16971
16972 WL_DBG(("Enter state:%lu ndev%p \n", state, dev));
16973 if (!dev) {
16974 WL_ERR(("dev null\n"));
16975 return NOTIFY_DONE;
16976 }
16977
16978 wdev = ndev_to_wdev(dev);
16979 if (!wdev) {
16980 WL_ERR(("wdev null. Do nothing\n"));
16981 return NOTIFY_DONE;
16982 }
16983
16984 cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
16985 if (!cfg || (cfg != wl_cfg80211_get_bcmcfg())) {
16986 /* If cfg80211 priv is null or doesn't match return */
16987 WL_ERR(("wrong cfg ptr (%p)\n", cfg));
16988 return NOTIFY_DONE;
16989 }
16990
16991 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
16992 /* Nothing to be done for primary I/F */
16993 return NOTIFY_DONE;
16994 }
16995
16996 switch (state) {
16997 case NETDEV_DOWN:
16998 {
16999 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
17000 int max_wait_timeout = 2;
17001 int max_wait_count = 100;
17002 int refcnt = 0;
17003 unsigned long limit = jiffies + max_wait_timeout * HZ;
17004 while (work_pending(&wdev->cleanup_work)) {
17005 if (refcnt%5 == 0) {
17006 WL_ERR(("[NETDEV_DOWN] wait for "
17007 "complete of cleanup_work"
17008 " (%d th)\n", refcnt));
17009 }
17010 if (!time_before(jiffies, limit)) {
17011 WL_ERR(("[NETDEV_DOWN] cleanup_work"
17012 " of CFG80211 is not"
17013 " completed in %d sec\n",
17014 max_wait_timeout));
17015 break;
17016 }
17017 if (refcnt >= max_wait_count) {
17018 WL_ERR(("[NETDEV_DOWN] cleanup_work"
17019 " of CFG80211 is not"
17020 " completed in %d loop\n",
17021 max_wait_count));
17022 break;
17023 }
17024 set_current_state(TASK_INTERRUPTIBLE);
17025 (void)schedule_timeout(100);
17026 set_current_state(TASK_RUNNING);
17027 refcnt++;
17028 }
17029 #endif /* LINUX_VERSION < VERSION(3, 14, 0) */
17030 break;
17031 }
17032 case NETDEV_UNREGISTER:
17033 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
17034 /* after calling list_del_rcu(&wdev->list) */
17035 wl_dealloc_netinfo_by_wdev(cfg, wdev);
17036 break;
17037 case NETDEV_GOING_DOWN:
17038 /*
17039 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
17040 * In front of door, the function checks whether current scan
17041 * is working or not. If the scanning is still working,
17042 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
17043 */
17044 if (wl_get_drv_status(cfg, SCANNING, dev))
17045 wl_cfg80211_cancel_scan(cfg);
17046 break;
17047 }
17048 return NOTIFY_DONE;
17049 }
17050
17051 static struct notifier_block wl_cfg80211_netdev_notifier = {
17052 .notifier_call = wl_cfg80211_netdev_notifier_call,
17053 };
17054
17055 /*
17056 * to make sure we won't register the same notifier twice, otherwise a loop is likely to be
17057 * created in kernel notifier link list (with 'next' pointing to itself)
17058 */
17059 static bool wl_cfg80211_netdev_notifier_registered = FALSE;
17060
17061 static void wl_cfg80211_cancel_scan(struct bcm_cfg80211 *cfg)
17062 {
17063 struct wireless_dev *wdev = NULL;
17064 struct net_device *ndev = NULL;
17065
17066 mutex_lock(&cfg->scan_sync);
17067 if (!cfg->scan_request) {
17068 goto exit;
17069 }
17070
17071 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
17072 if (cfg->scan_request->dev)
17073 wdev = cfg->scan_request->dev->ieee80211_ptr;
17074 #else
17075 wdev = cfg->scan_request->wdev;
17076 #endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
17077
17078 if (!wdev) {
17079 WL_ERR(("No wireless_dev present\n"));
17080 goto exit;
17081 }
17082
17083 ndev = wdev_to_wlc_ndev(wdev, cfg);
17084 wl_notify_escan_complete(cfg, ndev, true, true);
17085 WL_INFORM_MEM(("Scan aborted! \n"));
17086 exit:
17087 mutex_unlock(&cfg->scan_sync);
17088 }
17089
17090 void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
17091 {
17092 wl_scan_params_t *params = NULL;
17093 s32 params_size = 0;
17094 s32 err = BCME_OK;
17095 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
17096 if (!in_atomic()) {
17097 /* Our scan params only need space for 1 channel and 0 ssids */
17098 params = wl_cfg80211_scan_alloc_params(cfg, -1, 0, &params_size);
17099 if (params == NULL) {
17100 WL_ERR(("scan params allocation failed \n"));
17101 err = -ENOMEM;
17102 } else {
17103 /* Do a scan abort to stop the driver's scan engine */
17104 err = wldev_ioctl_set(dev, WLC_SCAN, params, params_size);
17105 if (err < 0) {
17106 /* scan abort can fail if there is no outstanding scan */
17107 WL_DBG(("scan abort failed \n"));
17108 }
17109 MFREE(cfg->osh, params, params_size);
17110 }
17111 }
17112 #ifdef WLTDLS
17113 if (cfg->tdls_mgmt_frame) {
17114 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
17115 cfg->tdls_mgmt_frame = NULL;
17116 cfg->tdls_mgmt_frame_len = 0;
17117 }
17118 #endif /* WLTDLS */
17119 }
17120
17121 static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
17122 struct net_device *ndev,
17123 bool aborted, bool fw_abort)
17124 {
17125 s32 err = BCME_OK;
17126 unsigned long flags;
17127 struct net_device *dev;
17128 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
17129
17130 WL_DBG(("Enter \n"));
17131 BCM_REFERENCE(dhdp);
17132
17133 if (!ndev) {
17134 WL_ERR(("ndev is null\n"));
17135 err = BCME_ERROR;
17136 goto out;
17137 }
17138
17139 if (cfg->escan_info.ndev != ndev) {
17140 WL_ERR(("Outstanding scan req ndev not matching (%p:%p)\n",
17141 cfg->escan_info.ndev, ndev));
17142 err = BCME_ERROR;
17143 goto out;
17144 }
17145
17146 if (cfg->scan_request) {
17147 dev = bcmcfg_to_prmry_ndev(cfg);
17148 #if defined(WL_ENABLE_P2P_IF)
17149 if (cfg->scan_request->dev != cfg->p2p_net)
17150 dev = cfg->scan_request->dev;
17151 #elif defined(WL_CFG80211_P2P_DEV_IF)
17152 if (cfg->scan_request->wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
17153 dev = cfg->scan_request->wdev->netdev;
17154 #endif /* WL_ENABLE_P2P_IF */
17155 }
17156 else {
17157 WL_DBG(("cfg->scan_request is NULL. Internal scan scenario."
17158 "doing scan_abort for ndev %p primary %p",
17159 ndev, bcmcfg_to_prmry_ndev(cfg)));
17160 dev = ndev;
17161 }
17162 if (fw_abort && !in_atomic())
17163 wl_cfg80211_scan_abort(cfg);
17164 if (timer_pending(&cfg->scan_timeout))
17165 del_timer_sync(&cfg->scan_timeout);
17166 cfg->scan_enq_time = 0;
17167 #if defined(ESCAN_RESULT_PATCH)
17168 if (likely(cfg->scan_request)) {
17169 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
17170 if (aborted && p2p_scan(cfg) &&
17171 (cfg->scan_request->flags & NL80211_SCAN_FLAG_FLUSH)) {
17172 WL_ERR(("scan list is changed"));
17173 cfg->bss_list = wl_escan_get_buf(cfg, !aborted);
17174 } else
17175 #endif // endif
17176 cfg->bss_list = wl_escan_get_buf(cfg, aborted);
17177
17178 wl_inform_bss(cfg);
17179 }
17180 #endif /* ESCAN_RESULT_PATCH */
17181 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
17182 #ifdef WL_SCHED_SCAN
17183 if (cfg->sched_scan_req && !cfg->scan_request) {
17184 if (!aborted) {
17185 WL_INFORM_MEM(("[%s] Report sched scan done.\n", dev->name));
17186 cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy);
17187 }
17188
17189 DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE);
17190 cfg->sched_scan_running = FALSE;
17191 }
17192 #endif /* WL_SCHED_SCAN */
17193 if (likely(cfg->scan_request)) {
17194 WL_INFORM_MEM(("[%s] Report scan done.\n", dev->name));
17195 wl_notify_scan_done(cfg, aborted);
17196 cfg->scan_request = NULL;
17197 }
17198 if (p2p_is_on(cfg))
17199 wl_clr_p2p_status(cfg, SCANNING);
17200 wl_clr_drv_status(cfg, SCANNING, dev);
17201
17202 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
17203 DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)(cfg->pub));
17204 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
17205
17206 out:
17207 return err;
17208 }
17209
17210 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17211 #ifndef WL_DRV_AVOID_SCANCACHE
17212 static void
17213 wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate)
17214 {
17215 int idx;
17216 for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) {
17217 int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1;
17218 if (bss->RSSI < candidate[idx].RSSI) {
17219 if (len)
17220 memcpy(&candidate[idx + 1], &candidate[idx],
17221 sizeof(removal_element_t) * len);
17222 candidate[idx].RSSI = bss->RSSI;
17223 candidate[idx].length = bss->length;
17224 memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN);
17225 return;
17226 }
17227 }
17228 }
17229
17230 static void
17231 wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate,
17232 wl_bss_info_t *bi)
17233 {
17234 int idx1, idx2;
17235 int total_delete_len = 0;
17236 for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) {
17237 int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
17238 wl_bss_info_t *bss = NULL;
17239 if (candidate[idx1].RSSI >= bi->RSSI)
17240 continue;
17241 for (idx2 = 0; idx2 < list->count; idx2++) {
17242 bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) :
17243 list->bss_info;
17244 if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
17245 candidate[idx1].RSSI == bss->RSSI &&
17246 candidate[idx1].length == dtoh32(bss->length)) {
17247 u32 delete_len = dtoh32(bss->length);
17248 WL_DBG(("delete scan info of " MACDBG " to add new AP\n",
17249 MAC2STRDBG(bss->BSSID.octet)));
17250 if (idx2 < list->count -1) {
17251 memmove((u8 *)bss, (u8 *)bss + delete_len,
17252 list->buflen - cur_len - delete_len);
17253 }
17254 list->buflen -= delete_len;
17255 list->count--;
17256 total_delete_len += delete_len;
17257 /* if delete_len is greater than or equal to result length */
17258 if (total_delete_len >= bi->length) {
17259 return;
17260 }
17261 break;
17262 }
17263 cur_len += dtoh32(bss->length);
17264 }
17265 }
17266 }
17267 #endif /* WL_DRV_AVOID_SCANCACHE */
17268 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17269
17270 #ifdef WL_DRV_AVOID_SCANCACHE
17271 static u32 wl_p2p_find_peer_channel(struct bcm_cfg80211 *cfg, s32 status, wl_bss_info_t *bi,
17272 u32 bi_length)
17273 {
17274 u32 ret;
17275 u8 *p2p_dev_addr = NULL;
17276
17277 ret = wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL);
17278 if (!ret) {
17279 return ret;
17280 }
17281 if (status == WLC_E_STATUS_PARTIAL) {
17282 p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
17283 if (p2p_dev_addr && !memcmp(p2p_dev_addr,
17284 cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) {
17285 s32 channel = wf_chspec_ctlchan(
17286 wl_chspec_driver_to_host(bi->chanspec));
17287
17288 if ((channel > MAXCHANNEL) || (channel <= 0)) {
17289 channel = WL_INVALID;
17290 } else {
17291 WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found,"
17292 " channel : %d\n",
17293 MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet),
17294 channel));
17295 }
17296 wl_clr_p2p_status(cfg, SCANNING);
17297 cfg->afx_hdl->peer_chan = channel;
17298 complete(&cfg->act_frm_scan);
17299 }
17300 } else {
17301 WL_INFORM_MEM(("ACTION FRAME SCAN DONE\n"));
17302 wl_clr_p2p_status(cfg, SCANNING);
17303 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
17304 if (cfg->afx_hdl->peer_chan == WL_INVALID)
17305 complete(&cfg->act_frm_scan);
17306 }
17307
17308 return ret;
17309 }
17310
17311 static s32 wl_escan_without_scan_cache(struct bcm_cfg80211 *cfg, wl_escan_result_t *escan_result,
17312 struct net_device *ndev, const wl_event_msg_t *e, s32 status)
17313 {
17314 s32 err = BCME_OK;
17315 wl_bss_info_t *bi;
17316 u32 bi_length;
17317 bool aborted = false;
17318 bool fw_abort = false;
17319 bool notify_escan_complete = false;
17320
17321 if (wl_escan_check_sync_id(status, escan_result->sync_id,
17322 cfg->escan_info.cur_sync_id) < 0) {
17323 goto exit;
17324 }
17325
17326 wl_escan_print_sync_id(status, escan_result->sync_id,
17327 cfg->escan_info.cur_sync_id);
17328
17329 if (!(status == WLC_E_STATUS_TIMEOUT) || !(status == WLC_E_STATUS_PARTIAL)) {
17330 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
17331 }
17332
17333 if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
17334 notify_escan_complete = true;
17335 }
17336
17337 if (status == WLC_E_STATUS_PARTIAL) {
17338 WL_DBG(("WLC_E_STATUS_PARTIAL \n"));
17339 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND);
17340 if ((!escan_result) || (dtoh16(escan_result->bss_count) != 1)) {
17341 WL_ERR(("Invalid escan result (NULL pointer) or invalid bss_count\n"));
17342 goto exit;
17343 }
17344
17345 bi = escan_result->bss_info;
17346 bi_length = dtoh32(bi->length);
17347 if ((!bi) ||
17348 (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE))) {
17349 WL_ERR(("Invalid escan bss info (NULL pointer)"
17350 "or invalid bss_info length\n"));
17351 goto exit;
17352 }
17353
17354 if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
17355 if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
17356 WL_DBG(("Ignoring IBSS result\n"));
17357 goto exit;
17358 }
17359 }
17360
17361 if (wl_p2p_find_peer_channel(cfg, status, bi, bi_length)) {
17362 goto exit;
17363 } else {
17364 if (scan_req_match(cfg)) {
17365 /* p2p scan && allow only probe response */
17366 if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) &&
17367 (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
17368 goto exit;
17369 }
17370 #ifdef ROAM_CHANNEL_CACHE
17371 add_roam_cache(cfg, bi);
17372 #endif /* ROAM_CHANNEL_CACHE */
17373 err = wl_inform_single_bss(cfg, bi, false);
17374 #ifdef ROAM_CHANNEL_CACHE
17375 /* print_roam_cache(); */
17376 update_roam_cache(cfg, ioctl_version);
17377 #endif /* ROAM_CHANNEL_CACHE */
17378
17379 /*
17380 * !Broadcast && number of ssid = 1 && number of channels =1
17381 * means specific scan to association
17382 */
17383 if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) {
17384 WL_ERR(("P2P assoc scan fast aborted.\n"));
17385 aborted = false;
17386 fw_abort = true;
17387 }
17388 /* Directly exit from function here and
17389 * avoid sending notify completion to cfg80211
17390 */
17391 goto exit;
17392 }
17393 } else if (status == WLC_E_STATUS_SUCCESS) {
17394 if (wl_p2p_find_peer_channel(cfg, status, NULL, 0)) {
17395 goto exit;
17396 }
17397 WL_INFORM_MEM(("ESCAN COMPLETED\n"));
17398 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_COMPLETE);
17399
17400 /* Update escan complete status */
17401 aborted = false;
17402 fw_abort = false;
17403
17404 #ifdef CUSTOMER_HW4_DEBUG
17405 if (wl_scan_timeout_dbg_enabled)
17406 wl_scan_timeout_dbg_clear();
17407 #endif /* CUSTOMER_HW4_DEBUG */
17408 } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) ||
17409 #ifdef BCMCCX
17410 (status == WLC_E_STATUS_CCXFASTRM) ||
17411 #endif /* BCMCCX */
17412 (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) ||
17413 (status == WLC_E_STATUS_NEWASSOC)) {
17414 /* Handle all cases of scan abort */
17415
17416 WL_DBG(("ESCAN ABORT reason: %d\n", status));
17417 if (wl_p2p_find_peer_channel(cfg, status, NULL, 0)) {
17418 goto exit;
17419 }
17420 WL_INFORM_MEM(("ESCAN ABORTED\n"));
17421
17422 /* Update escan complete status */
17423 aborted = true;
17424 fw_abort = false;
17425
17426 } else if (status == WLC_E_STATUS_TIMEOUT) {
17427 WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request));
17428 WL_ERR(("reason[0x%x]\n", e->reason));
17429 if (e->reason == 0xFFFFFFFF) {
17430 /* Update escan complete status */
17431 aborted = true;
17432 fw_abort = true;
17433 }
17434 } else {
17435 WL_ERR(("unexpected Escan Event %d : abort\n", status));
17436
17437 if (wl_p2p_find_peer_channel(cfg, status, NULL, 0)) {
17438 goto exit;
17439 }
17440 /* Update escan complete status */
17441 aborted = true;
17442 fw_abort = false;
17443 }
17444
17445 /* Notify escan complete status */
17446 if (notify_escan_complete) {
17447 wl_notify_escan_complete(cfg, ndev, aborted, fw_abort);
17448 }
17449
17450 exit:
17451 return err;
17452
17453 }
17454 #endif /* WL_DRV_AVOID_SCANCACHE */
17455
17456 #ifdef WL_BCNRECV
17457 /* Beacon recv results handler sending to upper layer */
17458 static s32
17459 wl_bcnrecv_result_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17460 wl_bss_info_v109_2_t *bi, uint32 scan_status)
17461 {
17462 s32 err = BCME_OK;
17463 struct wiphy *wiphy = NULL;
17464 wl_bcnrecv_result_t *bcn_recv = NULL;
17465 struct timespec ts;
17466 if (!bi) {
17467 WL_ERR(("%s: bi is NULL\n", __func__));
17468 err = BCME_NORESOURCE;
17469 goto exit;
17470 }
17471 if ((bi->length - bi->ie_length) < sizeof(wl_bss_info_v109_2_t)) {
17472 WL_ERR(("bi info version doesn't support bcn_recv attributes\n"));
17473 goto exit;
17474 }
17475
17476 if (scan_status == WLC_E_STATUS_RXBCN) {
17477 wiphy = cfg->wdev->wiphy;
17478 if (!wiphy) {
17479 WL_ERR(("wiphy is NULL\n"));
17480 err = BCME_NORESOURCE;
17481 goto exit;
17482 }
17483 bcn_recv = (wl_bcnrecv_result_t *)MALLOCZ(cfg->osh, sizeof(*bcn_recv));
17484 if (unlikely(!bcn_recv)) {
17485 WL_ERR(("Failed to allocate memory\n"));
17486 return -ENOMEM;
17487 }
17488 memcpy((char *)bcn_recv->SSID, (char *)bi->SSID, DOT11_MAX_SSID_LEN);
17489 memcpy(&bcn_recv->BSSID, &bi->BSSID, ETH_ALEN);
17490 bcn_recv->channel = wf_chspec_ctlchan(
17491 wl_chspec_driver_to_host(bi->chanspec));
17492 bcn_recv->beacon_interval = bi->beacon_period;
17493
17494 /* kernal timestamp */
17495 get_monotonic_boottime(&ts);
17496 bcn_recv->system_time = ((u64)ts.tv_sec*1000000)
17497 + ts.tv_nsec / 1000;
17498 bcn_recv->timestamp[0] = bi->timestamp[0];
17499 bcn_recv->timestamp[1] = bi->timestamp[1];
17500 if (bcn_recv) {
17501 if ((err = wl_android_bcnrecv_event(cfgdev_to_wlc_ndev(cfgdev, cfg),
17502 BCNRECV_ATTR_BCNINFO, 0, 0, (uint8 *)bcn_recv, sizeof(*bcn_recv)))
17503 != BCME_OK) {
17504 WL_ERR(("failed to send bcnrecv event, error:%d\n", err));
17505 }
17506 }
17507 } else {
17508 WL_DBG(("Ignoring Escan Event:%d \n", scan_status));
17509 }
17510 exit:
17511 if (bcn_recv) {
17512 MFREE(cfg->osh, bcn_recv, sizeof(*bcn_recv));
17513 }
17514 return err;
17515 }
17516 #endif /* WL_BCNRECV */
17517
17518 static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17519 const wl_event_msg_t *e, void *data)
17520 {
17521 s32 err = BCME_OK;
17522 s32 status = ntoh32(e->status);
17523 wl_escan_result_t *escan_result;
17524 struct net_device *ndev = NULL;
17525 #ifndef WL_DRV_AVOID_SCANCACHE
17526 wl_bss_info_t *bi;
17527 u32 bi_length;
17528 const wifi_p2p_ie_t * p2p_ie;
17529 const u8 *p2p_dev_addr = NULL;
17530 wl_scan_results_t *list;
17531 wl_bss_info_t *bss = NULL;
17532 u32 i;
17533 #endif /* WL_DRV_AVOID_SCANCACHE */
17534
17535 WL_DBG((" enter event type : %d, status : %d \n",
17536 ntoh32(e->event_type), ntoh32(e->status)));
17537
17538 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17539
17540 mutex_lock(&cfg->scan_sync);
17541 /* P2P SCAN is coming from primary interface */
17542 if (wl_get_p2p_status(cfg, SCANNING)) {
17543 if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM))
17544 ndev = cfg->afx_hdl->dev;
17545 else
17546 ndev = cfg->escan_info.ndev;
17547 }
17548 escan_result = (wl_escan_result_t *)data;
17549 #ifdef WL_BCNRECV
17550 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED &&
17551 status == WLC_E_STATUS_RXBCN) {
17552 /* handle beacon recv scan results */
17553 wl_bss_info_v109_2_t *bi_info;
17554 bi_info = (wl_bss_info_v109_2_t *)escan_result->bss_info;
17555 err = wl_bcnrecv_result_handler(cfg, cfgdev, bi_info, status);
17556 goto exit;
17557 }
17558 #endif /* WL_BCNRECV */
17559 if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) {
17560 WL_ERR_RLMT(("escan is not ready. drv_scan_status 0x%x"
17561 " e_type %d e_states %d\n",
17562 wl_get_drv_status(cfg, SCANNING, ndev),
17563 ntoh32(e->event_type), ntoh32(e->status)));
17564 goto exit;
17565 }
17566
17567 #ifndef WL_DRV_AVOID_SCANCACHE
17568 if (status == WLC_E_STATUS_PARTIAL) {
17569 WL_DBG(("WLC_E_STATUS_PARTIAL \n"));
17570 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND);
17571 if (!escan_result) {
17572 WL_ERR(("Invalid escan result (NULL pointer)\n"));
17573 goto exit;
17574 }
17575 if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) ||
17576 (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) {
17577 WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen)));
17578 goto exit;
17579 }
17580 if (dtoh16(escan_result->bss_count) != 1) {
17581 WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
17582 goto exit;
17583 }
17584 bi = escan_result->bss_info;
17585 if (!bi) {
17586 WL_ERR(("Invalid escan bss info (NULL pointer)\n"));
17587 goto exit;
17588 }
17589 bi_length = dtoh32(bi->length);
17590 if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
17591 WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
17592 goto exit;
17593 }
17594 if (wl_escan_check_sync_id(status, escan_result->sync_id,
17595 cfg->escan_info.cur_sync_id) < 0)
17596 goto exit;
17597
17598 if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
17599 if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
17600 WL_DBG(("Ignoring IBSS result\n"));
17601 goto exit;
17602 }
17603 }
17604
17605 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17606 p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
17607 if (p2p_dev_addr && !memcmp(p2p_dev_addr,
17608 cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) {
17609 s32 channel = wf_chspec_ctlchan(
17610 wl_chspec_driver_to_host(bi->chanspec));
17611
17612 if ((channel > MAXCHANNEL) || (channel <= 0))
17613 channel = WL_INVALID;
17614 else
17615 WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found,"
17616 " channel : %d\n",
17617 MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet),
17618 channel));
17619
17620 wl_clr_p2p_status(cfg, SCANNING);
17621 cfg->afx_hdl->peer_chan = channel;
17622 complete(&cfg->act_frm_scan);
17623 goto exit;
17624 }
17625
17626 } else {
17627 int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
17628 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17629 removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT];
17630 int remove_lower_rssi = FALSE;
17631
17632 bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT);
17633 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17634
17635 list = wl_escan_get_buf(cfg, FALSE);
17636 if (scan_req_match(cfg)) {
17637 #ifdef WL_HOST_BAND_MGMT
17638 s32 channel_band = 0;
17639 chanspec_t chspec;
17640 #endif /* WL_HOST_BAND_MGMT */
17641 /* p2p scan && allow only probe response */
17642 if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) &&
17643 (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
17644 goto exit;
17645 if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset,
17646 bi->ie_length)) == NULL) {
17647 WL_ERR(("Couldn't find P2PIE in probe"
17648 " response/beacon\n"));
17649 goto exit;
17650 }
17651 #ifdef WL_HOST_BAND_MGMT
17652 chspec = wl_chspec_driver_to_host(bi->chanspec);
17653 channel_band = CHSPEC2WLC_BAND(chspec);
17654
17655 if ((cfg->curr_band == WLC_BAND_5G) &&
17656 (channel_band == WLC_BAND_2G)) {
17657 /* Avoid sending the GO results in band conflict */
17658 if (wl_cfgp2p_retreive_p2pattrib(p2p_ie,
17659 P2P_SEID_GROUP_ID) != NULL)
17660 goto exit;
17661 }
17662 #endif /* WL_HOST_BAND_MGMT */
17663 }
17664 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17665 if (bi_length > ESCAN_BUF_SIZE - list->buflen)
17666 remove_lower_rssi = TRUE;
17667 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17668
17669 for (i = 0; i < list->count; i++) {
17670 bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
17671 : list->bss_info;
17672 if (!bss) {
17673 WL_ERR(("bss is NULL\n"));
17674 goto exit;
17675 }
17676 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17677 WL_TRACE(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n",
17678 bss->SSID, MAC2STRDBG(bss->BSSID.octet),
17679 i, bss->RSSI, list->count));
17680
17681 if (remove_lower_rssi)
17682 wl_cfg80211_find_removal_candidate(bss, candidate);
17683 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17684
17685 if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
17686 (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec))
17687 == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) &&
17688 bi->SSID_len == bss->SSID_len &&
17689 !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
17690
17691 /* do not allow beacon data to update
17692 *the data recd from a probe response
17693 */
17694 if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) &&
17695 (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
17696 goto exit;
17697
17698 WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d"
17699 " flags 0x%x, new: RSSI %d flags 0x%x\n",
17700 bss->SSID, MAC2STRDBG(bi->BSSID.octet), i,
17701 bss->RSSI, bss->flags, bi->RSSI, bi->flags));
17702
17703 if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) ==
17704 (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) {
17705 /* preserve max RSSI if the measurements are
17706 * both on-channel or both off-channel
17707 */
17708 WL_SCAN(("%s("MACDBG"), same onchan"
17709 ", RSSI: prev %d new %d\n",
17710 bss->SSID, MAC2STRDBG(bi->BSSID.octet),
17711 bss->RSSI, bi->RSSI));
17712 bi->RSSI = MAX(bss->RSSI, bi->RSSI);
17713 } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
17714 (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) {
17715 /* preserve the on-channel rssi measurement
17716 * if the new measurement is off channel
17717 */
17718 WL_SCAN(("%s("MACDBG"), prev onchan"
17719 ", RSSI: prev %d new %d\n",
17720 bss->SSID, MAC2STRDBG(bi->BSSID.octet),
17721 bss->RSSI, bi->RSSI));
17722 bi->RSSI = bss->RSSI;
17723 bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL;
17724 }
17725 if (dtoh32(bss->length) != bi_length) {
17726 u32 prev_len = dtoh32(bss->length);
17727
17728 WL_SCAN(("bss info replacement"
17729 " is occured(bcast:%d->probresp%d)\n",
17730 bss->ie_length, bi->ie_length));
17731 WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n",
17732 bss->SSID, MAC2STRDBG(bi->BSSID.octet),
17733 prev_len, bi_length));
17734
17735 if (list->buflen - prev_len + bi_length
17736 > ESCAN_BUF_SIZE) {
17737 WL_ERR(("Buffer is too small: keep the"
17738 " previous result of this AP\n"));
17739 /* Only update RSSI */
17740 bss->RSSI = bi->RSSI;
17741 bss->flags |= (bi->flags
17742 & WL_BSS_FLAGS_RSSI_ONCHANNEL);
17743 goto exit;
17744 }
17745
17746 if (i < list->count - 1) {
17747 /* memory copy required by this case only */
17748 memmove((u8 *)bss + bi_length,
17749 (u8 *)bss + prev_len,
17750 list->buflen - cur_len - prev_len);
17751 }
17752 list->buflen -= prev_len;
17753 list->buflen += bi_length;
17754 }
17755 list->version = dtoh32(bi->version);
17756 memcpy((u8 *)bss, (u8 *)bi, bi_length);
17757 goto exit;
17758 }
17759 cur_len += dtoh32(bss->length);
17760 }
17761 if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
17762 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17763 wl_cfg80211_remove_lowRSSI_info(list, candidate, bi);
17764 if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
17765 WL_DBG(("RSSI(" MACDBG ") is too low(%d) to add Buffer\n",
17766 MAC2STRDBG(bi->BSSID.octet), bi->RSSI));
17767 goto exit;
17768 }
17769 #else
17770 WL_ERR(("Buffer is too small: ignoring\n"));
17771 goto exit;
17772 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17773 }
17774
17775 memcpy(&(((char *)list)[list->buflen]), bi, bi_length);
17776 list->version = dtoh32(bi->version);
17777 list->buflen += bi_length;
17778 list->count++;
17779
17780 /*
17781 * !Broadcast && number of ssid = 1 && number of channels =1
17782 * means specific scan to association
17783 */
17784 if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) {
17785 WL_ERR(("P2P assoc scan fast aborted.\n"));
17786 wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false, true);
17787 goto exit;
17788 }
17789 }
17790 }
17791 else if (status == WLC_E_STATUS_SUCCESS) {
17792 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
17793 wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id,
17794 escan_result->sync_id);
17795
17796 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17797 WL_DBG(("ACTION FRAME SCAN DONE\n"));
17798 wl_clr_p2p_status(cfg, SCANNING);
17799 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
17800 if (cfg->afx_hdl->peer_chan == WL_INVALID)
17801 complete(&cfg->act_frm_scan);
17802 } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
17803 WL_INFORM_MEM(("ESCAN COMPLETED\n"));
17804 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_COMPLETE);
17805 cfg->bss_list = wl_escan_get_buf(cfg, FALSE);
17806 if (!scan_req_match(cfg)) {
17807 WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n",
17808 cfg->bss_list->count));
17809 }
17810 #if defined(SUPPORT_RANDOM_MAC_SCAN) && defined(DHD_RANDOM_MAC_SCAN)
17811 wl_cfg80211_random_mac_disable(ndev);
17812 #endif /* SUPPORT_RANDOM_MAC_SCAN && DHD_RANDOM_MAC_SCAN */
17813 wl_inform_bss(cfg);
17814 wl_notify_escan_complete(cfg, ndev, false, false);
17815 }
17816 wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT);
17817 #ifdef CUSTOMER_HW4_DEBUG
17818 if (wl_scan_timeout_dbg_enabled)
17819 wl_scan_timeout_dbg_clear();
17820 #endif /* CUSTOMER_HW4_DEBUG */
17821 } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) ||
17822 #ifdef BCMCCX
17823 (status == WLC_E_STATUS_CCXFASTRM) ||
17824 #endif /* BCMCCX */
17825 (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) ||
17826 (status == WLC_E_STATUS_NEWASSOC)) {
17827 /* Dump FW preserve buffer content */
17828 if (status == WLC_E_STATUS_ABORT) {
17829 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
17830 }
17831 /* Handle all cases of scan abort */
17832 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
17833 wl_escan_print_sync_id(status, escan_result->sync_id,
17834 cfg->escan_info.cur_sync_id);
17835 WL_DBG(("ESCAN ABORT reason: %d\n", status));
17836 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17837 WL_DBG(("ACTION FRAME SCAN DONE\n"));
17838 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
17839 wl_clr_p2p_status(cfg, SCANNING);
17840 if (cfg->afx_hdl->peer_chan == WL_INVALID)
17841 complete(&cfg->act_frm_scan);
17842 } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
17843 WL_INFORM_MEM(("ESCAN ABORTED\n"));
17844
17845 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
17846 if (p2p_scan(cfg) && cfg->scan_request &&
17847 (cfg->scan_request->flags & NL80211_SCAN_FLAG_FLUSH)) {
17848 WL_ERR(("scan list is changed"));
17849 cfg->bss_list = wl_escan_get_buf(cfg, FALSE);
17850 } else
17851 #endif // endif
17852 cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
17853
17854 if (!scan_req_match(cfg)) {
17855 WL_TRACE_HW4(("SCAN ABORTED: scanned AP count=%d\n",
17856 cfg->bss_list->count));
17857 }
17858 #ifdef DUAL_ESCAN_RESULT_BUFFER
17859 if (escan_result->sync_id != cfg->escan_info.cur_sync_id) {
17860 /* If sync_id is not matching, then the abort might have
17861 * come for the old scan req or for the in-driver initiated
17862 * scan. So do abort for scan_req for which sync_id is
17863 * matching.
17864 */
17865 WL_INFORM_MEM(("sync_id mismatch (%d != %d). "
17866 "Ignore the scan abort event.\n",
17867 escan_result->sync_id, cfg->escan_info.cur_sync_id));
17868 goto exit;
17869 } else {
17870 /* sync id is matching, abort the scan */
17871 WL_INFORM_MEM(("scan aborted for sync_id: %d \n",
17872 cfg->escan_info.cur_sync_id));
17873 wl_inform_bss(cfg);
17874 wl_notify_escan_complete(cfg, ndev, true, false);
17875 }
17876 #else
17877 wl_inform_bss(cfg);
17878 wl_notify_escan_complete(cfg, ndev, true, false);
17879 #endif /* DUAL_ESCAN_RESULT_BUFFER */
17880 } else {
17881 /* If there is no pending host initiated scan, do nothing */
17882 WL_DBG(("ESCAN ABORT: No pending scans. Ignoring event.\n"));
17883 }
17884 wl_escan_increment_sync_id(cfg, SCAN_BUF_CNT);
17885 } else if (status == WLC_E_STATUS_TIMEOUT) {
17886 WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request));
17887 WL_ERR(("reason[0x%x]\n", e->reason));
17888 if (e->reason == 0xFFFFFFFF) {
17889 wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
17890 }
17891 } else {
17892 WL_ERR(("unexpected Escan Event %d : abort\n", status));
17893 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
17894 wl_escan_print_sync_id(status, escan_result->sync_id,
17895 cfg->escan_info.cur_sync_id);
17896 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17897 WL_DBG(("ACTION FRAME SCAN DONE\n"));
17898 wl_clr_p2p_status(cfg, SCANNING);
17899 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
17900 if (cfg->afx_hdl->peer_chan == WL_INVALID)
17901 complete(&cfg->act_frm_scan);
17902 } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
17903 cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
17904 if (!scan_req_match(cfg)) {
17905 WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): "
17906 "scanned AP count=%d\n",
17907 cfg->bss_list->count));
17908 }
17909 wl_inform_bss(cfg);
17910 wl_notify_escan_complete(cfg, ndev, true, false);
17911 }
17912 wl_escan_increment_sync_id(cfg, 2);
17913 }
17914 #else /* WL_DRV_AVOID_SCANCACHE */
17915 err = wl_escan_without_scan_cache(cfg, escan_result, ndev, e, status);
17916 #endif /* WL_DRV_AVOID_SCANCACHE */
17917 exit:
17918 mutex_unlock(&cfg->scan_sync);
17919 return err;
17920 }
17921
17922 static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
17923 {
17924 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
17925 bool p2p_connected = wl_cfgp2p_vif_created(cfg);
17926 struct net_info *iter, *next;
17927
17928 if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT))
17929 return;
17930
17931 WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
17932 enable, p2p_connected, connected_cnt));
17933 /* Disable FW roam when we have a concurrent P2P connection */
17934 if (enable && p2p_connected && connected_cnt > 1) {
17935
17936 /* Mark it as to be reverted */
17937 cfg->roam_flags |= WL_ROAM_REVERT_STATUS;
17938 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17939 4 && __GNUC_MINOR__ >= 6))
17940 _Pragma("GCC diagnostic push")
17941 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
17942 #endif // endif
17943 for_each_ndev(cfg, iter, next) {
17944 if (iter->ndev && iter->wdev &&
17945 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
17946 if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE)
17947 == BCME_OK) {
17948 iter->roam_off = TRUE;
17949 }
17950 else {
17951 WL_ERR(("error to enable roam_off\n"));
17952 }
17953 }
17954 }
17955 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17956 4 && __GNUC_MINOR__ >= 6))
17957 _Pragma("GCC diagnostic pop")
17958 #endif // endif
17959 }
17960 else if (!enable && (cfg->roam_flags & WL_ROAM_REVERT_STATUS)) {
17961 cfg->roam_flags &= ~WL_ROAM_REVERT_STATUS;
17962 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17963 4 && __GNUC_MINOR__ >= 6))
17964 _Pragma("GCC diagnostic push")
17965 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
17966 #endif // endif
17967 for_each_ndev(cfg, iter, next) {
17968 if (iter->ndev && iter->wdev &&
17969 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
17970 if (iter->roam_off != WL_INVALID) {
17971 if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE)
17972 == BCME_OK) {
17973 iter->roam_off = FALSE;
17974 }
17975 else {
17976 WL_ERR(("error to disable roam_off\n"));
17977 }
17978 }
17979 }
17980 }
17981 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17982 4 && __GNUC_MINOR__ >= 6))
17983 _Pragma("GCC diagnostic pop")
17984 #endif // endif
17985 }
17986
17987 return;
17988 }
17989
17990 static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
17991 {
17992 struct net_info *iter, *next;
17993 u32 ctl_chan = 0;
17994 u32 chanspec = 0;
17995 u32 pre_ctl_chan = 0;
17996 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
17997 cfg->vsdb_mode = false;
17998
17999 if (connected_cnt <= 1) {
18000 return;
18001 }
18002 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18003 4 && __GNUC_MINOR__ >= 6))
18004 _Pragma("GCC diagnostic push")
18005 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
18006 #endif // endif
18007 for_each_ndev(cfg, iter, next) {
18008 /* p2p discovery iface ndev could be null */
18009 if (iter->ndev) {
18010 chanspec = 0;
18011 ctl_chan = 0;
18012 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
18013 if (wldev_iovar_getint(iter->ndev, "chanspec",
18014 (s32 *)&chanspec) == BCME_OK) {
18015 chanspec = wl_chspec_driver_to_host(chanspec);
18016 ctl_chan = wf_chspec_ctlchan(chanspec);
18017 wl_update_prof(cfg, iter->ndev, NULL,
18018 &ctl_chan, WL_PROF_CHAN);
18019 }
18020 if (!cfg->vsdb_mode) {
18021 if (!pre_ctl_chan && ctl_chan)
18022 pre_ctl_chan = ctl_chan;
18023 else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) {
18024 cfg->vsdb_mode = true;
18025 }
18026 }
18027 }
18028 }
18029 }
18030 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18031 4 && __GNUC_MINOR__ >= 6))
18032 _Pragma("GCC diagnostic pop")
18033 #endif // endif
18034 WL_ERR(("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel"));
18035 return;
18036 }
18037
18038 int
18039 wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211 *cfg)
18040 {
18041 struct net_info *iter, *next;
18042 u32 chanspec = 0;
18043 u32 band = 0;
18044 u32 pre_band = 0;
18045 bool is_rsdb_supported = FALSE;
18046 bool rsdb_mode = FALSE;
18047
18048 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
18049
18050 if (!is_rsdb_supported) {
18051 return 0;
18052 }
18053
18054 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18055 4 && __GNUC_MINOR__ >= 6))
18056 _Pragma("GCC diagnostic push")
18057 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
18058 #endif // endif
18059 for_each_ndev(cfg, iter, next) {
18060 /* p2p discovery iface ndev could be null */
18061 if (iter->ndev) {
18062 chanspec = 0;
18063 band = 0;
18064 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
18065 if (wldev_iovar_getint(iter->ndev, "chanspec",
18066 (s32 *)&chanspec) == BCME_OK) {
18067 chanspec = wl_chspec_driver_to_host(chanspec);
18068 band = CHSPEC_BAND(chanspec);
18069 }
18070
18071 if (!pre_band && band) {
18072 pre_band = band;
18073 } else if (pre_band && (pre_band != band)) {
18074 rsdb_mode = TRUE;
18075 }
18076 }
18077 }
18078 }
18079 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18080 4 && __GNUC_MINOR__ >= 6))
18081 _Pragma("GCC diagnostic pop")
18082 #endif // endif
18083 WL_DBG(("RSDB mode is %s\n", rsdb_mode ? "enabled" : "disabled"));
18084
18085 return rsdb_mode;
18086 }
18087
18088 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
18089 enum wl_status state, bool set)
18090 {
18091 s32 pm = PM_FAST;
18092 s32 err = BCME_OK;
18093 u32 mode;
18094 u32 chan = 0;
18095 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
18096 dhd_pub_t *dhd = cfg->pub;
18097 #ifdef RTT_SUPPORT
18098 rtt_status_info_t *rtt_status;
18099 #endif /* RTT_SUPPORT */
18100 if (dhd->busstate == DHD_BUS_DOWN) {
18101 WL_ERR(("%s : busstate is DHD_BUS_DOWN!\n", __FUNCTION__));
18102 return 0;
18103 }
18104 WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
18105 state, set, _net_info->pm_restore, _net_info->ndev->name));
18106
18107 if (state != WL_STATUS_CONNECTED)
18108 return 0;
18109 mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
18110 if (set) {
18111 wl_cfg80211_concurrent_roam(cfg, 1);
18112 wl_cfg80211_determine_vsdb_mode(cfg);
18113 if (mode == WL_MODE_AP) {
18114 if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
18115 WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
18116 }
18117 pm = PM_OFF;
18118 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
18119 sizeof(pm))) != 0) {
18120 if (err == -ENODEV)
18121 WL_DBG(("%s:netdev not ready\n",
18122 _net_info->ndev->name));
18123 else
18124 WL_ERR(("%s:error (%d)\n",
18125 _net_info->ndev->name, err));
18126
18127 wl_cfg80211_update_power_mode(_net_info->ndev);
18128 }
18129 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
18130 #if defined(WLTDLS)
18131 if (wl_cfg80211_is_concurrent_mode(primary_dev)) {
18132 err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
18133 }
18134 #endif /* defined(WLTDLS) */
18135
18136 #ifdef DISABLE_FRAMEBURST_VSDB
18137 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
18138 wl_cfg80211_is_concurrent_mode(primary_dev) &&
18139 !wl_cfg80211_determine_p2p_rsdb_mode(cfg)) {
18140 wl_cfg80211_set_frameburst(cfg, FALSE);
18141 }
18142 #endif /* DISABLE_FRAMEBURST_VSDB */
18143 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18144 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
18145 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
18146 /* Enable frameburst for
18147 * STA/SoftAP concurrent mode
18148 */
18149 wl_cfg80211_set_frameburst(cfg, TRUE);
18150 }
18151 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
18152 } else { /* clear */
18153 chan = 0;
18154 /* clear chan information when the net device is disconnected */
18155 wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
18156 wl_cfg80211_determine_vsdb_mode(cfg);
18157 if (primary_dev == _net_info->ndev) {
18158 pm = PM_FAST;
18159 #ifdef RTT_SUPPORT
18160 rtt_status = GET_RTTSTATE(dhd);
18161 if (rtt_status->status != RTT_ENABLED)
18162 #endif /* RTT_SUPPORT */
18163 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
18164 sizeof(pm))) != 0) {
18165 if (err == -ENODEV)
18166 WL_DBG(("%s:netdev not ready\n",
18167 _net_info->ndev->name));
18168 else
18169 WL_ERR(("%s:error (%d)\n",
18170 _net_info->ndev->name, err));
18171
18172 wl_cfg80211_update_power_mode(_net_info->ndev);
18173 }
18174 }
18175 wl_cfg80211_concurrent_roam(cfg, 0);
18176 #if defined(WLTDLS)
18177 if (!wl_cfg80211_is_concurrent_mode(primary_dev)) {
18178 err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
18179 }
18180 #endif /* defined(WLTDLS) */
18181
18182 #if defined(DISABLE_FRAMEBURST_VSDB)
18183 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE)) {
18184 wl_cfg80211_set_frameburst(cfg, TRUE);
18185 }
18186 #endif /* DISABLE_FRAMEBURST_VSDB */
18187 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18188 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
18189 (cfg->ap_oper_channel <= CH_MAX_2G_CHANNEL)) {
18190 /* Disable frameburst for stand-alone 2GHz SoftAP */
18191 wl_cfg80211_set_frameburst(cfg, FALSE);
18192 }
18193 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
18194 }
18195 return err;
18196 }
18197 static s32 wl_init_scan(struct bcm_cfg80211 *cfg)
18198 {
18199 int err = 0;
18200
18201 cfg->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler;
18202 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
18203 wl_escan_init_sync_id(cfg);
18204
18205 /* Init scan_timeout timer */
18206 init_timer(&cfg->scan_timeout);
18207 cfg->scan_timeout.data = (unsigned long) cfg;
18208 cfg->scan_timeout.function = wl_scan_timeout;
18209
18210 return err;
18211 }
18212
18213 #ifdef DHD_LOSSLESS_ROAMING
18214 static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
18215 {
18216 int err = 0;
18217
18218 /* Init roam timer */
18219 init_timer(&cfg->roam_timeout);
18220 cfg->roam_timeout.data = (unsigned long) cfg;
18221 cfg->roam_timeout.function = wl_roam_timeout;
18222
18223 return err;
18224 }
18225 #endif /* DHD_LOSSLESS_ROAMING */
18226
18227 static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
18228 {
18229 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
18230 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
18231 s32 err = 0;
18232
18233 cfg->scan_request = NULL;
18234 cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
18235 #ifdef DISABLE_BUILTIN_ROAM
18236 cfg->roam_on = false;
18237 #else
18238 cfg->roam_on = true;
18239 #endif /* DISABLE_BUILTIN_ROAM */
18240 cfg->active_scan = true;
18241 cfg->rf_blocked = false;
18242 cfg->vsdb_mode = false;
18243 #if defined(BCMSDIO)
18244 cfg->wlfc_on = false;
18245 #endif /* defined(BCMSDIO) */
18246 cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
18247 cfg->disable_roam_event = false;
18248 /* register interested state */
18249 set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
18250 spin_lock_init(&cfg->cfgdrv_lock);
18251 mutex_init(&cfg->ioctl_buf_sync);
18252 init_waitqueue_head(&cfg->netif_change_event);
18253 init_completion(&cfg->send_af_done);
18254 init_completion(&cfg->iface_disable);
18255 wl_init_eq(cfg);
18256 err = wl_init_priv_mem(cfg);
18257 if (err)
18258 return err;
18259 if (wl_create_event_handler(cfg))
18260 return -ENOMEM;
18261 wl_init_event_handler(cfg);
18262 mutex_init(&cfg->usr_sync);
18263 mutex_init(&cfg->event_sync);
18264 mutex_init(&cfg->if_sync);
18265 mutex_init(&cfg->scan_sync);
18266 #ifdef WLTDLS
18267 mutex_init(&cfg->tdls_sync);
18268 #endif /* WLTDLS */
18269 #ifdef WL_BCNRECV
18270 mutex_init(&cfg->bcn_sync);
18271 #endif /* WL_BCNRECV */
18272 #ifdef WL_WPS_SYNC
18273 wl_init_wps_reauth_sm(cfg);
18274 #endif /* WL_WPS_SYNC */
18275 err = wl_init_scan(cfg);
18276 if (err)
18277 return err;
18278 #ifdef DHD_LOSSLESS_ROAMING
18279 err = wl_init_roam_timeout(cfg);
18280 if (err) {
18281 return err;
18282 }
18283 #endif /* DHD_LOSSLESS_ROAMING */
18284 wl_init_conf(cfg->conf);
18285 wl_init_prof(cfg, ndev);
18286 wl_link_down(cfg);
18287 DNGL_FUNC(dhd_cfg80211_init, (cfg));
18288 #ifdef WL_NAN
18289 cfg->nan_dp_state = NAN_DP_STATE_DISABLED;
18290 init_waitqueue_head(&cfg->ndp_if_change_event);
18291 #endif /* WL_NAN */
18292 return err;
18293 }
18294
18295 static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
18296 {
18297 DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
18298 wl_destroy_event_handler(cfg);
18299 wl_flush_eq(cfg);
18300 wl_link_down(cfg);
18301 del_timer_sync(&cfg->scan_timeout);
18302 #ifdef DHD_LOSSLESS_ROAMING
18303 del_timer_sync(&cfg->roam_timeout);
18304 #endif // endif
18305 wl_deinit_priv_mem(cfg);
18306 if (wl_cfg80211_netdev_notifier_registered) {
18307 wl_cfg80211_netdev_notifier_registered = FALSE;
18308 unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
18309 }
18310 }
18311
18312 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18313 static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
18314 {
18315 WL_TRACE(("Enter \n"));
18316
18317 if (wl_cfgp2p_register_ndev(cfg) < 0) {
18318 WL_ERR(("P2P attach failed. \n"));
18319 return -ENODEV;
18320 }
18321
18322 return 0;
18323 }
18324
18325 static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
18326 {
18327 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18328 struct wireless_dev *wdev;
18329 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18330
18331 WL_DBG(("Enter \n"));
18332 if (!cfg) {
18333 WL_ERR(("Invalid Ptr\n"));
18334 return -EINVAL;
18335 }
18336 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18337 else {
18338 wdev = cfg->p2p_wdev;
18339 if (!wdev) {
18340 WL_ERR(("Invalid Ptr\n"));
18341 return -EINVAL;
18342 }
18343 }
18344 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18345
18346 wl_cfgp2p_unregister_ndev(cfg);
18347
18348 cfg->p2p_wdev = NULL;
18349 cfg->p2p_net = NULL;
18350 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18351 WL_DBG(("Freeing 0x%p \n", wdev));
18352 MFREE(cfg->osh, wdev, sizeof(*wdev));
18353 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18354
18355 return 0;
18356 }
18357 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
18358
18359 static s32 wl_cfg80211_attach_post(struct net_device *ndev)
18360 {
18361 struct bcm_cfg80211 * cfg;
18362 s32 err = 0;
18363 s32 ret = 0;
18364 WL_INFORM_MEM(("In\n"));
18365 if (unlikely(!ndev)) {
18366 WL_ERR(("ndev is invaild\n"));
18367 return -ENODEV;
18368 }
18369 cfg = wl_get_cfg(ndev);
18370 if (unlikely(!cfg)) {
18371 WL_ERR(("cfg is invaild\n"));
18372 return -EINVAL;
18373 }
18374 if (!wl_get_drv_status(cfg, READY, ndev)) {
18375 if (cfg->wdev) {
18376 ret = wl_cfgp2p_supported(cfg, ndev);
18377 if (ret > 0) {
18378 #if !defined(WL_ENABLE_P2P_IF)
18379 cfg->wdev->wiphy->interface_modes |=
18380 (BIT(NL80211_IFTYPE_P2P_CLIENT)|
18381 BIT(NL80211_IFTYPE_P2P_GO));
18382 #endif /* !WL_ENABLE_P2P_IF */
18383 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
18384 goto fail;
18385
18386 #if defined(WL_ENABLE_P2P_IF)
18387 if (cfg->p2p_net) {
18388 /* Update MAC addr for p2p0 interface here. */
18389 memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
18390 cfg->p2p_net->dev_addr[0] |= 0x02;
18391 WL_ERR(("%s: p2p_dev_addr="MACDBG "\n",
18392 cfg->p2p_net->name,
18393 MAC2STRDBG(cfg->p2p_net->dev_addr)));
18394 } else {
18395 WL_ERR(("p2p_net not yet populated."
18396 " Couldn't update the MAC Address for p2p0 \n"));
18397 return -ENODEV;
18398 }
18399 #endif /* WL_ENABLE_P2P_IF */
18400 cfg->p2p_supported = true;
18401 } else if (ret == 0) {
18402 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
18403 goto fail;
18404 } else {
18405 /* SDIO bus timeout */
18406 err = -ENODEV;
18407 goto fail;
18408 }
18409 }
18410 }
18411 wl_set_drv_status(cfg, READY, ndev);
18412 fail:
18413 return err;
18414 }
18415
18416 struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev)
18417 {
18418 struct wireless_dev *wdev = ndev->ieee80211_ptr;
18419
18420 if (!wdev)
18421 return NULL;
18422
18423 return wiphy_priv(wdev->wiphy);
18424 }
18425
18426 s32
18427 wl_cfg80211_net_attach(struct net_device *primary_ndev)
18428 {
18429 struct bcm_cfg80211 *cfg = wl_get_cfg(primary_ndev);
18430
18431 if (!cfg) {
18432 WL_ERR(("cfg null\n"));
18433 return BCME_ERROR;
18434 }
18435 #ifdef WL_STATIC_IF
18436 /* Register dummy n/w iface. FW init will happen only from dev_open */
18437 if (wl_cfg80211_register_static_if(cfg, NL80211_IFTYPE_STATION,
18438 WL_STATIC_IFNAME_PREFIX) == NULL) {
18439 WL_ERR(("static i/f registration failed!\n"));
18440 return BCME_ERROR;
18441 }
18442 #endif /* WL_STATIC_IF */
18443 return BCME_OK;
18444 }
18445
18446 s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
18447 {
18448 struct wireless_dev *wdev;
18449 struct bcm_cfg80211 *cfg;
18450 s32 err = 0;
18451 struct device *dev;
18452 u16 bssidx = 0;
18453 u16 ifidx = 0;
18454 dhd_pub_t *dhd = (struct dhd_pub *)(context);
18455
18456 WL_TRACE(("In\n"));
18457 if (!ndev) {
18458 WL_ERR(("ndev is invaild\n"));
18459 return -ENODEV;
18460 }
18461 WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
18462 dev = wl_cfg80211_get_parent_dev();
18463
18464 wdev = (struct wireless_dev *)MALLOCZ(dhd->osh, sizeof(*wdev));
18465 if (unlikely(!wdev)) {
18466 WL_ERR(("Could not allocate wireless device\n"));
18467 return -ENOMEM;
18468 }
18469 err = wl_setup_wiphy(wdev, dev, context);
18470 if (unlikely(err)) {
18471 MFREE(dhd->osh, wdev, sizeof(*wdev));
18472 return -ENOMEM;
18473 }
18474 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
18475 cfg = wiphy_priv(wdev->wiphy);
18476 cfg->wdev = wdev;
18477 cfg->pub = context;
18478 cfg->osh = dhd->osh;
18479 INIT_LIST_HEAD(&cfg->net_list);
18480 #ifdef WBTEXT
18481 INIT_LIST_HEAD(&cfg->wbtext_bssid_list);
18482 #endif /* WBTEXT */
18483 INIT_LIST_HEAD(&cfg->vndr_oui_list);
18484 spin_lock_init(&cfg->vndr_oui_sync);
18485 spin_lock_init(&cfg->net_list_sync);
18486 ndev->ieee80211_ptr = wdev;
18487 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
18488 wdev->netdev = ndev;
18489 cfg->state_notifier = wl_notifier_change_state;
18490 err = wl_alloc_netinfo(cfg, ndev, wdev, WL_IF_TYPE_STA, PM_ENABLE, bssidx, ifidx);
18491 if (err) {
18492 WL_ERR(("Failed to alloc net_info (%d)\n", err));
18493 goto cfg80211_attach_out;
18494 }
18495 err = wl_init_priv(cfg);
18496 if (err) {
18497 WL_ERR(("Failed to init iwm_priv (%d)\n", err));
18498 goto cfg80211_attach_out;
18499 }
18500
18501 err = wl_setup_rfkill(cfg, TRUE);
18502 if (err) {
18503 WL_ERR(("Failed to setup rfkill %d\n", err));
18504 goto cfg80211_attach_out;
18505 }
18506 #ifdef DEBUGFS_CFG80211
18507 err = wl_setup_debugfs(cfg);
18508 if (err) {
18509 WL_ERR(("Failed to setup debugfs %d\n", err));
18510 goto cfg80211_attach_out;
18511 }
18512 #endif // endif
18513 if (!wl_cfg80211_netdev_notifier_registered) {
18514 wl_cfg80211_netdev_notifier_registered = TRUE;
18515 err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
18516 if (err) {
18517 wl_cfg80211_netdev_notifier_registered = FALSE;
18518 WL_ERR(("Failed to register notifierl %d\n", err));
18519 goto cfg80211_attach_out;
18520 }
18521 }
18522 #if defined(COEX_DHCP)
18523 cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
18524 if (!cfg->btcoex_info)
18525 goto cfg80211_attach_out;
18526 #endif // endif
18527 #if defined(SUPPORT_RANDOM_MAC_SCAN) && defined(DHD_RANDOM_MAC_SCAN)
18528 cfg->random_mac_running = FALSE;
18529 #endif /* SUPPORT_RANDOM_MAC_SCAN && DHD_RANDOM_MAC_SCAN */
18530
18531 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18532 err = wl_cfg80211_attach_p2p(cfg);
18533 if (err)
18534 goto cfg80211_attach_out;
18535 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
18536
18537 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
18538 mutex_init(&cfg->pm_sync);
18539 #ifdef WL_NAN
18540 mutex_init(&cfg->nancfg.nan_sync);
18541 init_waitqueue_head(&cfg->nancfg.nan_event_wait);
18542 #endif /* WL_NAN */
18543 wl_cfg80211_set_bcmcfg(cfg);
18544 #ifdef BIGDATA_SOFTAP
18545 wl_attach_ap_stainfo(cfg);
18546 #endif /* BIGDATA_SOFTAP */
18547 cfg->rssi_sum_report = FALSE;
18548 #ifdef WL_BAM
18549 wl_bad_ap_mngr_init(cfg);
18550 #endif /* WL_BAM */
18551
18552 return err;
18553
18554 cfg80211_attach_out:
18555 wl_setup_rfkill(cfg, FALSE);
18556 wl_free_wdev(cfg);
18557 return err;
18558 }
18559
18560 void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
18561 {
18562 WL_DBG(("Enter\n"));
18563 if (!cfg) {
18564 return;
18565 }
18566 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
18567
18568 #if defined(COEX_DHCP)
18569 wl_cfg80211_btcoex_deinit();
18570 cfg->btcoex_info = NULL;
18571 #endif // endif
18572
18573 wl_setup_rfkill(cfg, FALSE);
18574 #ifdef DEBUGFS_CFG80211
18575 wl_free_debugfs(cfg);
18576 #endif // endif
18577 if (cfg->p2p_supported) {
18578 if (timer_pending(&cfg->p2p->listen_timer))
18579 del_timer_sync(&cfg->p2p->listen_timer);
18580 wl_cfgp2p_deinit_priv(cfg);
18581 }
18582
18583 #ifdef WL_WPS_SYNC
18584 wl_deinit_wps_reauth_sm(cfg);
18585 #endif /* WL_WPS_SYNC */
18586
18587 if (timer_pending(&cfg->scan_timeout))
18588 del_timer_sync(&cfg->scan_timeout);
18589 #ifdef DHD_LOSSLESS_ROAMING
18590 if (timer_pending(&cfg->roam_timeout)) {
18591 del_timer_sync(&cfg->roam_timeout);
18592 }
18593 #endif /* DHD_LOSSLESS_ROAMING */
18594
18595 #ifdef WL_STATIC_IF
18596 wl_cfg80211_unregister_static_if(cfg);
18597 #endif /* WL_STATIC_IF */
18598 #if defined(WL_CFG80211_P2P_DEV_IF)
18599 if (cfg->p2p_wdev)
18600 wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
18601 #endif /* WL_CFG80211_P2P_DEV_IF */
18602 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18603 wl_cfg80211_detach_p2p(cfg);
18604 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
18605 #ifdef BIGDATA_SOFTAP
18606 wl_detach_ap_stainfo(cfg);
18607 #endif /* BIGDATA_SOFTAP */
18608 #ifdef WL_BAM
18609 wl_bad_ap_mngr_deinit(cfg);
18610 #endif /* WL_BAM */
18611 wl_cfg80211_ibss_vsie_free(cfg);
18612 wl_dealloc_netinfo_by_wdev(cfg, cfg->wdev);
18613 wl_cfg80211_set_bcmcfg(NULL);
18614 wl_deinit_priv(cfg);
18615 wl_cfg80211_clear_parent_dev();
18616 wl_free_wdev(cfg);
18617 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
18618 * structure "cfg", which is the private part of wiphy, has been freed in
18619 * wl_free_wdev !!!!!!!!!!!
18620 */
18621 WL_DBG(("Exit\n"));
18622 }
18623
18624 static void wl_print_event_data(struct bcm_cfg80211 *cfg,
18625 uint32 event_type, const wl_event_msg_t *e)
18626 {
18627 s32 status = ntoh32(e->status);
18628 s32 reason = ntoh32(e->reason);
18629 s32 ifidx = ntoh32(e->ifidx);
18630 s32 bssidx = ntoh32(e->bsscfgidx);
18631
18632 switch (event_type) {
18633 case WLC_E_ESCAN_RESULT:
18634 if ((status == WLC_E_STATUS_SUCCESS) ||
18635 (status == WLC_E_STATUS_ABORT)) {
18636 WL_INFORM_MEM(("event_type (%d), ifidx: %d"
18637 " bssidx: %d scan_type:%d\n",
18638 event_type, ifidx, bssidx, status));
18639 }
18640 break;
18641 case WLC_E_LINK:
18642 case WLC_E_DISASSOC:
18643 case WLC_E_DISASSOC_IND:
18644 case WLC_E_DEAUTH:
18645 case WLC_E_DEAUTH_IND:
18646 WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
18647 " status:%d reason:%d\n",
18648 event_type, ifidx, bssidx, status, reason));
18649 break;
18650
18651 default:
18652 /* Print only when DBG verbose is enabled */
18653 WL_DBG(("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
18654 event_type, ifidx, bssidx, status, reason));
18655 }
18656 }
18657
18658 static void wl_event_handler(struct work_struct *work_data)
18659 {
18660 struct bcm_cfg80211 *cfg = NULL;
18661 struct wl_event_q *e;
18662 struct wireless_dev *wdev = NULL;
18663
18664 WL_DBG(("Enter \n"));
18665 BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
18666 cfg->wl_evt_hdlr_entry_time = OSL_LOCALTIME_NS();
18667 DHD_EVENT_WAKE_LOCK(cfg->pub);
18668 while ((e = wl_deq_event(cfg))) {
18669 s32 status = ntoh32(e->emsg.status);
18670 u32 event_type = ntoh32(e->emsg.event_type);
18671 bool scan_cmplt_evt = (event_type == WLC_E_ESCAN_RESULT) &&
18672 ((status == WLC_E_STATUS_SUCCESS) || (status == WLC_E_STATUS_ABORT));
18673
18674 cfg->wl_evt_deq_time = OSL_LOCALTIME_NS();
18675 if (scan_cmplt_evt) {
18676 cfg->scan_deq_time = OSL_LOCALTIME_NS();
18677 }
18678 /* Print only critical events to avoid too many prints */
18679 wl_print_event_data(cfg, e->etype, &e->emsg);
18680
18681 if (e->emsg.ifidx > WL_MAX_IFS) {
18682 WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
18683 goto fail;
18684 }
18685
18686 /* Make sure iface operations, don't creat race conditions */
18687 mutex_lock(&cfg->if_sync);
18688 if (!(wdev = wl_get_wdev_by_fw_idx(cfg,
18689 e->emsg.bsscfgidx, e->emsg.ifidx))) {
18690 /* For WLC_E_IF would be handled by wl_host_event */
18691 if (e->etype != WLC_E_IF)
18692 WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
18693 " Ignoring event.\n", e->emsg.bsscfgidx));
18694 } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
18695 dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
18696 if (dhd->busstate == DHD_BUS_DOWN) {
18697 WL_ERR((": BUS is DOWN.\n"));
18698 } else
18699 {
18700 WL_DBG(("event_type %d event_sub %d\n",
18701 ntoh32(e->emsg.event_type),
18702 ntoh32(e->emsg.reason)));
18703 cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
18704 &e->emsg, e->edata);
18705 if (scan_cmplt_evt) {
18706 cfg->scan_hdlr_cmplt_time = OSL_LOCALTIME_NS();
18707 }
18708 }
18709 } else {
18710 WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
18711 }
18712 mutex_unlock(&cfg->if_sync);
18713 fail:
18714 wl_put_event(cfg, e);
18715 if (scan_cmplt_evt) {
18716 cfg->scan_cmplt_time = OSL_LOCALTIME_NS();
18717 }
18718 cfg->wl_evt_hdlr_exit_time = OSL_LOCALTIME_NS();
18719 }
18720 DHD_EVENT_WAKE_UNLOCK(cfg->pub);
18721 }
18722
18723 void
18724 wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
18725 {
18726 s32 status = ntoh32(e->status);
18727 u32 event_type = ntoh32(e->event_type);
18728 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18729 struct net_info *netinfo;
18730
18731 WL_TRACE(("event_type (%d): reason (%d): %s\n", event_type, ntoh32(e->reason),
18732 bcmevent_get_name(event_type)));
18733 if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
18734 WL_ERR(("Stale event ignored\n"));
18735 return;
18736 }
18737
18738 if (cfg->event_workq == NULL) {
18739 WL_ERR(("Event handler is not created\n"));
18740 return;
18741 }
18742
18743 if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) {
18744 WL_ERR(("during IF change, ignore event %d\n", event_type));
18745 return;
18746 }
18747
18748 if (event_type == WLC_E_IF) {
18749 /* Don't process WLC_E_IF events in wl_cfg80211 layer */
18750 return;
18751 }
18752
18753 netinfo = wl_get_netinfo_by_fw_idx(cfg, e->bsscfgidx, e->ifidx);
18754 if (!netinfo) {
18755 /* Since the netinfo entry is not there, the netdev entry is not
18756 * created via cfg80211 interface. so the event is not of interest
18757 * to the cfg80211 layer.
18758 */
18759 WL_TRACE(("ignore event %d, not interested\n", event_type));
18760 return;
18761 }
18762
18763 if (event_type == WLC_E_PFN_NET_FOUND) {
18764 WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
18765 }
18766 else if (event_type == WLC_E_PFN_NET_LOST) {
18767 WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
18768 }
18769
18770 if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
18771 queue_work(cfg->event_workq, &cfg->event_work);
18772 }
18773 /* Mark timeout value for thread sched */
18774 if ((event_type == WLC_E_ESCAN_RESULT) &&
18775 ((status == WLC_E_STATUS_SUCCESS) ||
18776 (status == WLC_E_STATUS_ABORT))) {
18777 cfg->scan_enq_time = OSL_LOCALTIME_NS();
18778 WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
18779 status, work_busy(&cfg->event_work)));
18780 }
18781 }
18782
18783 static void wl_init_eq(struct bcm_cfg80211 *cfg)
18784 {
18785 wl_init_eq_lock(cfg);
18786 INIT_LIST_HEAD(&cfg->eq_list);
18787 }
18788
18789 static void wl_flush_eq(struct bcm_cfg80211 *cfg)
18790 {
18791 struct wl_event_q *e;
18792 unsigned long flags;
18793
18794 flags = wl_lock_eq(cfg);
18795 while (!list_empty_careful(&cfg->eq_list)) {
18796 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
18797 list_del(&e->eq_list);
18798 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
18799 }
18800 wl_unlock_eq(cfg, flags);
18801 }
18802
18803 /*
18804 * retrieve first queued event from head
18805 */
18806
18807 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
18808 {
18809 struct wl_event_q *e = NULL;
18810 unsigned long flags;
18811
18812 flags = wl_lock_eq(cfg);
18813 if (likely(!list_empty(&cfg->eq_list))) {
18814 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
18815 list_del(&e->eq_list);
18816 }
18817 wl_unlock_eq(cfg, flags);
18818
18819 return e;
18820 }
18821
18822 /*
18823 * push event to tail of the queue
18824 */
18825
18826 static s32
18827 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event,
18828 const wl_event_msg_t *msg, void *data)
18829 {
18830 struct wl_event_q *e;
18831 s32 err = 0;
18832 uint32 evtq_size;
18833 uint32 data_len;
18834 unsigned long flags;
18835
18836 data_len = 0;
18837 if (data)
18838 data_len = ntoh32(msg->datalen);
18839 evtq_size = (uint32)(sizeof(struct wl_event_q) + data_len);
18840 e = (struct wl_event_q *)MALLOCZ(cfg->osh, evtq_size);
18841 if (unlikely(!e)) {
18842 WL_ERR(("event alloc failed\n"));
18843 return -ENOMEM;
18844 }
18845 e->etype = event;
18846 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
18847 if (data)
18848 memcpy(e->edata, data, data_len);
18849 e->datalen = data_len;
18850 flags = wl_lock_eq(cfg);
18851 list_add_tail(&e->eq_list, &cfg->eq_list);
18852 wl_unlock_eq(cfg, flags);
18853
18854 return err;
18855 }
18856
18857 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e)
18858 {
18859 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
18860 }
18861
18862 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype)
18863 {
18864 s32 infra = 0;
18865 s32 err = 0;
18866 bool skip_infra = false;
18867
18868 switch (iftype) {
18869 case WL_IF_TYPE_IBSS:
18870 case WL_IF_TYPE_AIBSS:
18871 infra = 0;
18872 break;
18873 case WL_IF_TYPE_AP:
18874 case WL_IF_TYPE_STA:
18875 case WL_IF_TYPE_P2P_GO:
18876 case WL_IF_TYPE_P2P_GC:
18877 /* Intentional fall through */
18878 infra = 1;
18879 break;
18880 case WL_IF_TYPE_MONITOR:
18881 case WL_IF_TYPE_AWDL:
18882 case WL_IF_TYPE_NAN:
18883 /* Intentionall fall through */
18884 default:
18885 skip_infra = true;
18886 WL_ERR(("Skipping infra setting for type:%d\n", iftype));
18887 break;
18888 }
18889
18890 if (!skip_infra) {
18891 infra = htod32(infra);
18892 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
18893 if (unlikely(err)) {
18894 WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
18895 return err;
18896 }
18897 }
18898 return 0;
18899 }
18900
18901 void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set)
18902 {
18903 if (!ev || (event > WLC_E_LAST))
18904 return;
18905
18906 if (ev->num < MAX_EVENT_BUF_NUM) {
18907 ev->event[ev->num].type = event;
18908 ev->event[ev->num].set = set;
18909 ev->num++;
18910 } else {
18911 WL_ERR(("evenbuffer doesn't support > %u events. Update"
18912 " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
18913 ASSERT(0);
18914 }
18915 }
18916
18917 s32 wl_cfg80211_apply_eventbuffer(
18918 struct net_device *ndev,
18919 struct bcm_cfg80211 *cfg,
18920 wl_eventmsg_buf_t *ev)
18921 {
18922 char eventmask[WL_EVENTING_MASK_LEN];
18923 int i, ret = 0;
18924 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
18925
18926 if (!ev || (!ev->num))
18927 return -EINVAL;
18928
18929 mutex_lock(&cfg->event_sync);
18930
18931 /* Read event_msgs mask */
18932 ret = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
18933 if (unlikely(ret)) {
18934 WL_ERR(("Get event_msgs error (%d)\n", ret));
18935 goto exit;
18936 }
18937 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
18938
18939 /* apply the set bits */
18940 for (i = 0; i < ev->num; i++) {
18941 if (ev->event[i].set)
18942 setbit(eventmask, ev->event[i].type);
18943 else
18944 clrbit(eventmask, ev->event[i].type);
18945 }
18946
18947 /* Write updated Event mask */
18948 ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf,
18949 sizeof(iovbuf), NULL);
18950 if (unlikely(ret)) {
18951 WL_ERR(("Set event_msgs error (%d)\n", ret));
18952 }
18953
18954 exit:
18955 mutex_unlock(&cfg->event_sync);
18956 return ret;
18957 }
18958
18959 s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
18960 {
18961 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
18962 s8 eventmask[WL_EVENTING_MASK_LEN];
18963 s32 err = 0;
18964 struct bcm_cfg80211 *cfg;
18965
18966 if (!ndev)
18967 return -ENODEV;
18968
18969 cfg = wl_get_cfg(ndev);
18970 if (!cfg)
18971 return -ENODEV;
18972
18973 mutex_lock(&cfg->event_sync);
18974
18975 /* Setup event_msgs */
18976 err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
18977 if (unlikely(err)) {
18978 WL_ERR(("Get event_msgs error (%d)\n", err));
18979 goto eventmsg_out;
18980 }
18981 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
18982 if (add) {
18983 setbit(eventmask, event);
18984 } else {
18985 clrbit(eventmask, event);
18986 }
18987 err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
18988 sizeof(iovbuf), NULL);
18989 if (unlikely(err)) {
18990 WL_ERR(("Set event_msgs error (%d)\n", err));
18991 goto eventmsg_out;
18992 }
18993
18994 eventmsg_out:
18995 mutex_unlock(&cfg->event_sync);
18996 return err;
18997 }
18998
18999 static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
19000 {
19001 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
19002 struct ieee80211_channel *band_chan_arr = NULL;
19003 wl_uint32_list_t *list;
19004 u32 i, j, index, n_2g, n_5g, band, channel, array_size;
19005 u32 *n_cnt = NULL;
19006 chanspec_t c = 0;
19007 s32 err = BCME_OK;
19008 bool update;
19009 bool ht40_allowed;
19010 u8 *pbuf = NULL;
19011 bool dfs_radar_disabled = FALSE;
19012
19013 #define LOCAL_BUF_LEN 1024
19014 pbuf = (u8 *)MALLOCZ(cfg->osh, LOCAL_BUF_LEN);
19015 if (pbuf == NULL) {
19016 WL_ERR(("failed to allocate local buf\n"));
19017 return -ENOMEM;
19018 }
19019
19020 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
19021 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
19022 if (err != 0) {
19023 WL_ERR(("get chanspecs failed with %d\n", err));
19024 MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
19025 return err;
19026 }
19027
19028 list = (wl_uint32_list_t *)(void *)pbuf;
19029 band = array_size = n_2g = n_5g = 0;
19030 for (i = 0; i < dtoh32(list->count); i++) {
19031 index = 0;
19032 update = false;
19033 ht40_allowed = false;
19034 c = (chanspec_t)dtoh32(list->element[i]);
19035 c = wl_chspec_driver_to_host(c);
19036 channel = wf_chspec_ctlchan(c);
19037
19038 if (!CHSPEC_IS40(c) && ! CHSPEC_IS20(c)) {
19039 WL_DBG(("HT80/160/80p80 center channel : %d\n", channel));
19040 continue;
19041 }
19042 if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
19043 (channel <= CH_MAX_2G_CHANNEL)) {
19044 band_chan_arr = __wl_2ghz_channels;
19045 array_size = ARRAYSIZE(__wl_2ghz_channels);
19046 n_cnt = &n_2g;
19047 band = NL80211_BAND_2GHZ;
19048 ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false;
19049 } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
19050 band_chan_arr = __wl_5ghz_a_channels;
19051 array_size = ARRAYSIZE(__wl_5ghz_a_channels);
19052 n_cnt = &n_5g;
19053 band = NL80211_BAND_5GHZ;
19054 ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true;
19055 } else {
19056 WL_ERR(("Invalid channel Sepc. 0x%x.\n", c));
19057 continue;
19058 }
19059 if (!ht40_allowed && CHSPEC_IS40(c))
19060 continue;
19061 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
19062 if (band_chan_arr[j].hw_value == channel) {
19063 update = true;
19064 break;
19065 }
19066 }
19067 if (update)
19068 index = j;
19069 else
19070 index = *n_cnt;
19071 if (index < array_size) {
19072 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
19073 band_chan_arr[index].center_freq =
19074 ieee80211_channel_to_frequency(channel);
19075 #else
19076 band_chan_arr[index].center_freq =
19077 ieee80211_channel_to_frequency(channel, band);
19078 #endif // endif
19079 band_chan_arr[index].hw_value = channel;
19080 band_chan_arr[index].beacon_found = false;
19081
19082 if (CHSPEC_IS40(c) && ht40_allowed) {
19083 /* assuming the order is HT20, HT40 Upper,
19084 * HT40 lower from chanspecs
19085 */
19086 u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
19087 if (CHSPEC_SB_UPPER(c)) {
19088 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
19089 band_chan_arr[index].flags &=
19090 ~IEEE80211_CHAN_NO_HT40;
19091 band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
19092 } else {
19093 /* It should be one of
19094 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
19095 */
19096 band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
19097 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
19098 band_chan_arr[index].flags |=
19099 IEEE80211_CHAN_NO_HT40MINUS;
19100 }
19101 } else {
19102 band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
19103 if (!dfs_radar_disabled) {
19104 if (band == NL80211_BAND_2GHZ)
19105 channel |= WL_CHANSPEC_BAND_2G;
19106 else
19107 channel |= WL_CHANSPEC_BAND_5G;
19108 channel |= WL_CHANSPEC_BW_20;
19109 channel = wl_chspec_host_to_driver(channel);
19110 err = wldev_iovar_getint(dev, "per_chan_info", &channel);
19111 if (!err) {
19112 if (channel & WL_CHAN_RADAR) {
19113 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
19114 band_chan_arr[index].flags |=
19115 (IEEE80211_CHAN_RADAR
19116 | IEEE80211_CHAN_NO_IBSS);
19117 #else
19118 band_chan_arr[index].flags |=
19119 IEEE80211_CHAN_RADAR;
19120 #endif // endif
19121 }
19122
19123 if (channel & WL_CHAN_PASSIVE)
19124 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
19125 band_chan_arr[index].flags |=
19126 IEEE80211_CHAN_PASSIVE_SCAN;
19127 #else
19128 band_chan_arr[index].flags |=
19129 IEEE80211_CHAN_NO_IR;
19130 #endif // endif
19131 } else if (err == BCME_UNSUPPORTED) {
19132 dfs_radar_disabled = TRUE;
19133 WL_ERR(("does not support per_chan_info\n"));
19134 }
19135 }
19136 }
19137 if (!update)
19138 (*n_cnt)++;
19139 }
19140
19141 }
19142 __wl_band_2ghz.n_channels = n_2g;
19143 __wl_band_5ghz_a.n_channels = n_5g;
19144 MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
19145 #undef LOCAL_BUF_LEN
19146
19147 return err;
19148 }
19149
19150 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
19151 {
19152 struct wiphy *wiphy;
19153 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
19154 u32 bandlist[3];
19155 u32 nband = 0;
19156 u32 i = 0;
19157 s32 err = 0;
19158 s32 index = 0;
19159 s32 nmode = 0;
19160 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19161 u32 j = 0;
19162 s32 vhtmode = 0;
19163 s32 txstreams = 0;
19164 s32 rxstreams = 0;
19165 s32 ldpc_cap = 0;
19166 s32 stbc_rx = 0;
19167 s32 stbc_tx = 0;
19168 s32 txbf_bfe_cap = 0;
19169 s32 txbf_bfr_cap = 0;
19170 #endif // endif
19171 s32 bw_cap = 0;
19172 s32 cur_band = -1;
19173 struct ieee80211_supported_band *bands[NUM_NL80211_BANDS] = {NULL, };
19174
19175 memset(bandlist, 0, sizeof(bandlist));
19176 err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist,
19177 sizeof(bandlist));
19178 if (unlikely(err)) {
19179 WL_ERR(("error read bandlist (%d)\n", err));
19180 return err;
19181 }
19182 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band,
19183 sizeof(s32));
19184 if (unlikely(err)) {
19185 WL_ERR(("error (%d)\n", err));
19186 return err;
19187 }
19188
19189 err = wldev_iovar_getint(dev, "nmode", &nmode);
19190 if (unlikely(err)) {
19191 WL_ERR(("error reading nmode (%d)\n", err));
19192 }
19193
19194 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19195 err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
19196 if (unlikely(err)) {
19197 WL_ERR(("error reading vhtmode (%d)\n", err));
19198 }
19199
19200 if (vhtmode) {
19201 err = wldev_iovar_getint(dev, "txstreams", &txstreams);
19202 if (unlikely(err)) {
19203 WL_ERR(("error reading txstreams (%d)\n", err));
19204 }
19205
19206 err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
19207 if (unlikely(err)) {
19208 WL_ERR(("error reading rxstreams (%d)\n", err));
19209 }
19210
19211 err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
19212 if (unlikely(err)) {
19213 WL_ERR(("error reading ldpc_cap (%d)\n", err));
19214 }
19215
19216 err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
19217 if (unlikely(err)) {
19218 WL_ERR(("error reading stbc_rx (%d)\n", err));
19219 }
19220
19221 err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
19222 if (unlikely(err)) {
19223 WL_ERR(("error reading stbc_tx (%d)\n", err));
19224 }
19225
19226 err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
19227 if (unlikely(err)) {
19228 WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
19229 }
19230
19231 err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
19232 if (unlikely(err)) {
19233 WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
19234 }
19235 }
19236 #endif // endif
19237
19238 /* For nmode and vhtmode check bw cap */
19239 if (nmode ||
19240 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19241 vhtmode ||
19242 #endif // endif
19243 0) {
19244 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
19245 if (unlikely(err)) {
19246 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
19247 }
19248 }
19249
19250 err = wl_construct_reginfo(cfg, bw_cap);
19251 if (err) {
19252 WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
19253 if (err != BCME_UNSUPPORTED)
19254 return err;
19255 }
19256
19257 wiphy = bcmcfg_to_wiphy(cfg);
19258 nband = bandlist[0];
19259
19260 for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
19261 index = -1;
19262 if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
19263 bands[NL80211_BAND_5GHZ] =
19264 &__wl_band_5ghz_a;
19265 index = NL80211_BAND_5GHZ;
19266 if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
19267 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
19268
19269 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19270 /* VHT capabilities. */
19271 if (vhtmode) {
19272 /* Supported */
19273 bands[index]->vht_cap.vht_supported = TRUE;
19274
19275 for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
19276 /* TX stream rates. */
19277 if (j <= txstreams) {
19278 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
19279 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
19280 } else {
19281 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
19282 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
19283 }
19284
19285 /* RX stream rates. */
19286 if (j <= rxstreams) {
19287 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
19288 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
19289 } else {
19290 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
19291 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
19292 }
19293 }
19294
19295 /* Capabilities */
19296 /* 80 MHz is mandatory */
19297 bands[index]->vht_cap.cap |=
19298 IEEE80211_VHT_CAP_SHORT_GI_80;
19299
19300 if (WL_BW_CAP_160MHZ(bw_cap)) {
19301 bands[index]->vht_cap.cap |=
19302 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
19303 bands[index]->vht_cap.cap |=
19304 IEEE80211_VHT_CAP_SHORT_GI_160;
19305 }
19306
19307 bands[index]->vht_cap.cap |=
19308 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
19309
19310 if (ldpc_cap)
19311 bands[index]->vht_cap.cap |=
19312 IEEE80211_VHT_CAP_RXLDPC;
19313
19314 if (stbc_tx)
19315 bands[index]->vht_cap.cap |=
19316 IEEE80211_VHT_CAP_TXSTBC;
19317
19318 if (stbc_rx)
19319 bands[index]->vht_cap.cap |=
19320 (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
19321
19322 if (txbf_bfe_cap)
19323 bands[index]->vht_cap.cap |=
19324 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
19325
19326 if (txbf_bfr_cap) {
19327 bands[index]->vht_cap.cap |=
19328 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
19329 }
19330
19331 if (txbf_bfe_cap || txbf_bfr_cap) {
19332 bands[index]->vht_cap.cap |=
19333 (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
19334 bands[index]->vht_cap.cap |=
19335 ((txstreams - 1) <<
19336 VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
19337 bands[index]->vht_cap.cap |=
19338 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
19339 }
19340
19341 /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
19342 bands[index]->vht_cap.cap |=
19343 (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
19344 WL_DBG(("%s band[%d] vht_enab=%d vht_cap=%08x "
19345 "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
19346 __FUNCTION__, index,
19347 bands[index]->vht_cap.vht_supported,
19348 bands[index]->vht_cap.cap,
19349 bands[index]->vht_cap.vht_mcs.rx_mcs_map,
19350 bands[index]->vht_cap.vht_mcs.tx_mcs_map));
19351 }
19352 #endif // endif
19353 }
19354 else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
19355 bands[NL80211_BAND_2GHZ] =
19356 &__wl_band_2ghz;
19357 index = NL80211_BAND_2GHZ;
19358 if (bw_cap == WLC_N_BW_40ALL)
19359 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
19360 }
19361
19362 if ((index >= 0) && nmode) {
19363 bands[index]->ht_cap.cap |=
19364 (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
19365 bands[index]->ht_cap.ht_supported = TRUE;
19366 bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
19367 bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
19368 /* An HT shall support all EQM rates for one spatial stream */
19369 bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
19370 }
19371
19372 }
19373
19374 wiphy->bands[NL80211_BAND_2GHZ] = bands[NL80211_BAND_2GHZ];
19375 wiphy->bands[NL80211_BAND_5GHZ] = bands[NL80211_BAND_5GHZ];
19376
19377 /* check if any bands populated otherwise makes 2Ghz as default */
19378 if (wiphy->bands[NL80211_BAND_2GHZ] == NULL &&
19379 wiphy->bands[NL80211_BAND_5GHZ] == NULL) {
19380 /* Setup 2Ghz band as default */
19381 wiphy->bands[NL80211_BAND_2GHZ] = &__wl_band_2ghz;
19382 }
19383
19384 if (notify)
19385 wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
19386
19387 return 0;
19388 }
19389
19390 #ifdef WL_BCNRECV
19391 static s32
19392 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
19393 const wl_event_msg_t *e, void *data)
19394 {
19395 s32 status = ntoh32(e->status);
19396 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
19397 /* Abort fakeapscan, when Roam is in progress */
19398 if (status == WLC_E_STATUS_RXBCN_ABORT) {
19399 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_ROAMABORT);
19400 } else {
19401 WL_ERR(("UNKNOWN STATUS. status:%d\n", status));
19402 }
19403 return BCME_OK;
19404 }
19405 #endif /* WL_BCNRECV */
19406
19407 /* Get the concurrency mode */
19408 int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg)
19409 {
19410 struct net_info *iter, *next;
19411 uint cmode = CONCURRENCY_MODE_NONE;
19412 u32 connected_cnt = 0;
19413 u32 pre_channel = 0, channel = 0;
19414 u32 pre_band = 0;
19415 u32 chanspec = 0;
19416 u32 band = 0;
19417
19418 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
19419 if (connected_cnt <= 1) {
19420 return cmode;
19421 }
19422 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19423 4 && __GNUC_MINOR__ >= 6))
19424 _Pragma("GCC diagnostic push")
19425 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
19426 #endif // endif
19427 for_each_ndev(cfg, iter, next) {
19428 if (iter->ndev) {
19429 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
19430 if (wldev_iovar_getint(iter->ndev, "chanspec",
19431 (s32 *)&chanspec) == BCME_OK) {
19432 channel = wf_chspec_ctlchan(
19433 wl_chspec_driver_to_host(chanspec));
19434 band = (channel <= CH_MAX_2G_CHANNEL) ?
19435 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
19436 }
19437 if ((!pre_channel && channel)) {
19438 pre_band = band;
19439 pre_channel = channel;
19440 } else if (pre_channel) {
19441 if ((pre_band == band) && (pre_channel == channel)) {
19442 cmode = CONCURRENCY_SCC_MODE;
19443 goto exit;
19444 } else if ((pre_band == band) && (pre_channel != channel)) {
19445 cmode = CONCURRENCY_VSDB_MODE;
19446 goto exit;
19447 } else if (pre_band != band) {
19448 cmode = CONCURRENCY_RSDB_MODE;
19449 goto exit;
19450 }
19451 }
19452 }
19453 }
19454 }
19455 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19456 4 && __GNUC_MINOR__ >= 6))
19457 _Pragma("GCC diagnostic pop")
19458 #endif // endif
19459 exit:
19460 return cmode;
19461 }
19462 s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
19463 {
19464 s32 err;
19465
19466 mutex_lock(&cfg->usr_sync);
19467 err = __wl_update_wiphybands(cfg, notify);
19468 mutex_unlock(&cfg->usr_sync);
19469
19470 return err;
19471 }
19472
19473 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
19474 {
19475 s32 err = 0;
19476 #ifdef WL_HOST_BAND_MGMT
19477 s32 ret = 0;
19478 #endif /* WL_HOST_BAND_MGMT */
19479 struct net_info *netinfo = NULL;
19480 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
19481 struct wireless_dev *wdev = ndev->ieee80211_ptr;
19482 #ifdef WBTEXT
19483 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
19484 #endif /* WBTEXT */
19485 #ifdef WLTDLS
19486 u32 tdls;
19487 #endif /* WLTDLS */
19488 u16 wl_iftype = 0;
19489 u16 wl_mode = 0;
19490
19491 WL_DBG(("In\n"));
19492
19493 /* Reserve 0x8000 toggle bit for P2P GO/GC */
19494 cfg->vif_macaddr_mask = 0x8000;
19495
19496 err = dhd_config_dongle(cfg);
19497 if (unlikely(err))
19498 return err;
19499
19500 /* Always bring up interface in STA mode.
19501 * Did observe , if previous SofAP Bringup/cleanup
19502 * is not done properly, iftype is stuck with AP mode.
19503 * So during next wlan0 up, forcing the type to STA
19504 */
19505 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
19506 if (!netinfo) {
19507 WL_ERR(("there is no netinfo\n"));
19508 return -ENODEV;
19509 }
19510 ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
19511 netinfo->iftype = WL_IF_TYPE_STA;
19512
19513 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
19514 return -EINVAL;
19515 }
19516 err = wl_config_infra(cfg, ndev, wl_iftype);
19517 if (unlikely(err && err != -EINPROGRESS)) {
19518 WL_ERR(("wl_config_infra failed\n"));
19519 if (err == -1) {
19520 WL_ERR(("return error %d\n", err));
19521 return err;
19522 }
19523 }
19524 err = __wl_update_wiphybands(cfg, true);
19525 if (unlikely(err)) {
19526 WL_ERR(("wl_update_wiphybands failed\n"));
19527 if (err == -1) {
19528 WL_ERR(("return error %d\n", err));
19529 return err;
19530 }
19531 }
19532 if (!dhd_download_fw_on_driverload) {
19533 err = wl_create_event_handler(cfg);
19534 if (err) {
19535 WL_ERR(("wl_create_event_handler failed\n"));
19536 return err;
19537 }
19538 wl_init_event_handler(cfg);
19539 }
19540 err = wl_init_scan(cfg);
19541 if (err) {
19542 WL_ERR(("wl_init_scan failed\n"));
19543 return err;
19544 }
19545 #ifdef DHD_LOSSLESS_ROAMING
19546 if (timer_pending(&cfg->roam_timeout)) {
19547 del_timer_sync(&cfg->roam_timeout);
19548 }
19549 #endif /* DHD_LOSSLESS_ROAMING */
19550
19551 err = dhd_monitor_init(cfg->pub);
19552
19553 #ifdef WL_HOST_BAND_MGMT
19554 /* By default the curr_band is initialized to BAND_AUTO */
19555 if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) {
19556 if (ret == BCME_UNSUPPORTED) {
19557 /* Don't fail the initialization, lets just
19558 * fall back to the original method
19559 */
19560 WL_ERR(("WL_HOST_BAND_MGMT defined, "
19561 "but roam_band iovar not supported \n"));
19562 } else {
19563 WL_ERR(("roam_band failed. ret=%d", ret));
19564 err = -1;
19565 }
19566 }
19567 #endif /* WL_HOST_BAND_MGMT */
19568 #if defined(WES_SUPPORT)
19569 /* Reset WES mode to 0 */
19570 wes_mode = 0;
19571 #endif // endif
19572 #ifdef WBTEXT
19573 /* when wifi up, set roam_prof to default value */
19574 if (dhd->wbtext_support) {
19575 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
19576 wl_cfg80211_wbtext_set_default(ndev);
19577 wl_cfg80211_wbtext_clear_bssid_list(cfg);
19578 }
19579 }
19580 #endif /* WBTEXT */
19581 #ifdef WLTDLS
19582 if (wldev_iovar_getint(ndev, "tdls_enable", &tdls) == 0) {
19583 WL_DBG(("TDLS supported in fw\n"));
19584 cfg->tdls_supported = true;
19585 }
19586 #endif /* WLTDLS */
19587 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
19588 wl_set_drv_status(cfg, READY, ndev);
19589 return err;
19590 }
19591
19592 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
19593 {
19594 s32 err = 0;
19595 unsigned long flags;
19596 struct net_info *iter, *next;
19597 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
19598 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
19599 defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
19600 struct net_device *p2p_net = cfg->p2p_net;
19601 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) && !PLATFORM_SLP */
19602 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
19603 WL_INFORM_MEM(("cfg80211 down\n"));
19604
19605 /* Check if cfg80211 interface is already down */
19606 if (!wl_get_drv_status(cfg, READY, ndev)) {
19607 WL_DBG(("cfg80211 interface is already down\n"));
19608 return err; /* it is even not ready */
19609 }
19610
19611 #ifdef SHOW_LOGTRACE
19612 /* Stop the event logging */
19613 wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
19614 #endif /* SHOW_LOGTRACE */
19615
19616 /* clear vendor OUI list */
19617 wl_vndr_ies_clear_vendor_oui_list(cfg);
19618
19619 /* Delete pm_enable_work */
19620 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
19621
19622 if (cfg->p2p_supported) {
19623 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
19624 #ifdef PROP_TXSTATUS_VSDB
19625 #if defined(BCMSDIO)
19626 if (wl_cfgp2p_vif_created(cfg)) {
19627 bool enabled = false;
19628 dhd_wlfc_get_enable(dhd, &enabled);
19629 if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
19630 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
19631 dhd_wlfc_deinit(dhd);
19632 cfg->wlfc_on = false;
19633 }
19634 }
19635 #endif /* defined(BCMSDIO) */
19636 #endif /* PROP_TXSTATUS_VSDB */
19637 }
19638
19639 if (!dhd_download_fw_on_driverload) {
19640 /* For built-in drivers/other drivers that do reset on
19641 * "ifconfig <primary_iface> down", cleanup any left
19642 * over interfaces
19643 */
19644 wl_cfg80211_cleanup_virtual_ifaces(cfg, false);
19645 }
19646 /* Clear used mac addr mask */
19647 cfg->vif_macaddr_mask = 0;
19648
19649 #ifdef WL_NAN
19650 err = wl_cfgnan_disable(cfg, NAN_BUS_IS_DOWN);
19651 if (err != BCME_OK) {
19652 WL_ERR(("failed to disable nan, error[%d]\n", err));
19653 }
19654 #endif /* WL_NAN */
19655
19656 if (dhd->up)
19657 {
19658 /* If primary BSS is operational (for e.g SoftAP), bring it down */
19659 if (wl_cfg80211_bss_isup(ndev, 0)) {
19660 if (wl_cfg80211_bss_up(cfg, ndev, 0, 0) < 0)
19661 WL_ERR(("BSS down failed \n"));
19662 }
19663
19664 /* clear all the security setting on primary Interface */
19665 wl_cfg80211_clear_security(cfg);
19666 }
19667
19668 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19669 4 && __GNUC_MINOR__ >= 6))
19670 _Pragma("GCC diagnostic push")
19671 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
19672 #endif // endif
19673 for_each_ndev(cfg, iter, next) {
19674 if (iter->ndev) /* p2p discovery iface is null */
19675 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
19676 }
19677 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19678 4 && __GNUC_MINOR__ >= 6))
19679 _Pragma("GCC diagnostic pop")
19680 #endif // endif
19681
19682 #ifdef P2P_LISTEN_OFFLOADING
19683 wl_cfg80211_p2plo_deinit(cfg);
19684 #endif /* P2P_LISTEN_OFFLOADING */
19685
19686 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
19687 if (cfg->scan_request) {
19688 wl_notify_scan_done(cfg, true);
19689 cfg->scan_request = NULL;
19690 }
19691 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
19692 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19693 4 && __GNUC_MINOR__ >= 6))
19694 _Pragma("GCC diagnostic push")
19695 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
19696 #endif // endif
19697 for_each_ndev(cfg, iter, next) {
19698 /* p2p discovery iface ndev ptr could be null */
19699 if (iter->ndev == NULL)
19700 continue;
19701 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19702 WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
19703 wl_get_drv_status(cfg, CONNECTING, ndev),
19704 wl_get_drv_status(cfg, CONNECTED, ndev),
19705 wl_get_drv_status(cfg, DISCONNECTING, ndev),
19706 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
19707
19708 if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
19709 wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
19710 CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
19711 }
19712
19713 if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
19714 wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
19715 u8 *latest_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
19716 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
19717 struct wireless_dev *wdev = ndev->ieee80211_ptr;
19718 struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid,
19719 wdev->ssid, wdev->ssid_len);
19720
19721 prhex("bssid:", (uchar *)latest_bssid, ETHER_ADDR_LEN);
19722 prhex("ssid:", (uchar *)wdev->ssid, wdev->ssid_len);
19723 if (!bss) {
19724 WL_DBG(("null bss\n"));
19725 }
19726
19727 CFG80211_CONNECT_RESULT(ndev,
19728 latest_bssid, bss, NULL, 0, NULL, 0,
19729 WLAN_STATUS_UNSPECIFIED_FAILURE,
19730 GFP_KERNEL);
19731 }
19732 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19733 wl_clr_drv_status(cfg, READY, iter->ndev);
19734 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
19735 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
19736 wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
19737 wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
19738 wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
19739 wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
19740 wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
19741 wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev);
19742 wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev);
19743 }
19744 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19745 4 && __GNUC_MINOR__ >= 6))
19746 _Pragma("GCC diagnostic pop")
19747 #endif // endif
19748 bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
19749 NL80211_IFTYPE_STATION;
19750 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
19751 defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
19752 #ifdef SUPPORT_DEEP_SLEEP
19753 if (!trigger_deep_sleep)
19754 #endif /* SUPPORT_DEEP_SLEEP */
19755 if (p2p_net)
19756 dev_close(p2p_net);
19757 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT)&& !PLATFORM_SLP */
19758
19759 /* Avoid deadlock from wl_cfg80211_down */
19760 if (!dhd_download_fw_on_driverload) {
19761 mutex_unlock(&cfg->usr_sync);
19762 wl_destroy_event_handler(cfg);
19763 mutex_lock(&cfg->usr_sync);
19764 }
19765
19766 wl_flush_eq(cfg);
19767 wl_link_down(cfg);
19768 if (cfg->p2p_supported) {
19769 if (timer_pending(&cfg->p2p->listen_timer))
19770 del_timer_sync(&cfg->p2p->listen_timer);
19771 wl_cfgp2p_down(cfg);
19772 }
19773
19774 if (timer_pending(&cfg->scan_timeout)) {
19775 del_timer_sync(&cfg->scan_timeout);
19776 }
19777
19778 wl_cfg80211_clear_mgmt_vndr_ies(cfg);
19779 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
19780
19781 dhd_monitor_uninit();
19782 #ifdef WLAIBSS_MCHAN
19783 bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
19784 #endif /* WLAIBSS_MCHAN */
19785
19786 #ifdef WL11U
19787 /* Clear interworking element. */
19788 if (cfg->wl11u) {
19789 cfg->wl11u = FALSE;
19790 }
19791 #endif /* WL11U */
19792
19793 #ifdef CUSTOMER_HW4_DEBUG
19794 if (wl_scan_timeout_dbg_enabled) {
19795 wl_scan_timeout_dbg_clear();
19796 }
19797 #endif /* CUSTOMER_HW4_DEBUG */
19798
19799 cfg->disable_roam_event = false;
19800
19801 DNGL_FUNC(dhd_cfg80211_down, (cfg));
19802
19803 #ifdef DHD_IFDEBUG
19804 /* Printout all netinfo entries */
19805 wl_probe_wdev_all(cfg);
19806 #endif /* DHD_IFDEBUG */
19807
19808 return err;
19809 }
19810
19811 s32 wl_cfg80211_up(struct net_device *net)
19812 {
19813 struct bcm_cfg80211 *cfg;
19814 s32 err = 0;
19815 int val = 1;
19816 dhd_pub_t *dhd;
19817 #ifdef DISABLE_PM_BCNRX
19818 s32 interr = 0;
19819 uint param = 0;
19820 s8 iovbuf[WLC_IOCTL_SMLEN];
19821 #endif /* DISABLE_PM_BCNRX */
19822
19823 WL_DBG(("In\n"));
19824 cfg = wl_get_cfg(net);
19825
19826 if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
19827 sizeof(int)) < 0)) {
19828 WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
19829 return err;
19830 }
19831 val = dtoh32(val);
19832 if (val != WLC_IOCTL_VERSION && val != 1) {
19833 WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
19834 val, WLC_IOCTL_VERSION));
19835 return BCME_VERSION;
19836 }
19837 ioctl_version = val;
19838 WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
19839
19840 mutex_lock(&cfg->usr_sync);
19841 dhd = (dhd_pub_t *)(cfg->pub);
19842 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
19843 err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
19844 if (unlikely(err)) {
19845 mutex_unlock(&cfg->usr_sync);
19846 return err;
19847 }
19848 }
19849 #if defined(BCMSUP_4WAY_HANDSHAKE)
19850 if (dhd->fw_4way_handshake) {
19851 /* This is a hacky method to indicate fw 4WHS support and
19852 * is used only for kernels (kernels < 3.14). For newer
19853 * kernels, we would be using vendor extn. path to advertise
19854 * FW based 4-way handshake feature support.
19855 */
19856 cfg->wdev->wiphy->features |= NL80211_FEATURE_FW_4WAY_HANDSHAKE;
19857 }
19858 #endif /* BCMSUP_4WAY_HANDSHAKE */
19859 err = __wl_cfg80211_up(cfg);
19860 if (unlikely(err))
19861 WL_ERR(("__wl_cfg80211_up failed\n"));
19862
19863 #ifdef ROAM_CHANNEL_CACHE
19864 if (init_roam_cache(cfg, ioctl_version) == 0) {
19865 /* Enable support for Roam cache */
19866 cfg->rcc_enabled = true;
19867 WL_ERR(("Roam channel cache enabled\n"));
19868 } else {
19869 WL_ERR(("Failed to enable RCC.\n"));
19870 }
19871 #endif /* ROAM_CHANNEL_CACHE */
19872
19873 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
19874 dhd_force_disable_singlcore_scan(dhd);
19875 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
19876
19877 /* IOVAR configurations with 'up' condition */
19878 #ifdef DISABLE_PM_BCNRX
19879 interr = wldev_iovar_setbuf(net, "pm_bcnrx", (char *)&param, sizeof(param), iovbuf,
19880 sizeof(iovbuf), &cfg->ioctl_buf_sync);
19881
19882 if (unlikely(interr)) {
19883 WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
19884 }
19885 #endif /* DISABLE_PM_BCNRX */
19886
19887 mutex_unlock(&cfg->usr_sync);
19888
19889 #ifdef WLAIBSS_MCHAN
19890 bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
19891 #endif /* WLAIBSS_MCHAN */
19892
19893 #ifdef DUAL_STA_STATIC_IF
19894 /* Static Interface support is currently supported only for STA only builds (without P2P) */
19895 wl_cfg80211_create_iface(cfg->wdev->wiphy, WL_IF_TYPE_STA, NULL, "wlan%d");
19896 #endif /* DUAL_STA_STATIC_IF */
19897
19898 #ifdef SUPPORT_CUSTOM_SET_CAC
19899 cfg->enable_cac = 0;
19900 #endif /* SUPPORT_CUSTOM_SET_CAC */
19901
19902 return err;
19903 }
19904
19905 /* Private Event to Supplicant with indication that chip hangs */
19906 int wl_cfg80211_hang(struct net_device *dev, u16 reason)
19907 {
19908 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19909 dhd_pub_t *dhd;
19910 #if defined(SOFTAP_SEND_HANGEVT)
19911 /* specifc mac address used for hang event */
19912 uint8 hang_mac[ETHER_ADDR_LEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
19913 #endif /* SOFTAP_SEND_HANGEVT */
19914 if (!cfg) {
19915 return BCME_ERROR;
19916 }
19917
19918 RETURN_EIO_IF_NOT_UP(cfg);
19919
19920 dhd = (dhd_pub_t *)(cfg->pub);
19921 #if defined(DHD_HANG_SEND_UP_TEST)
19922 if (dhd->req_hang_type) {
19923 WL_ERR(("%s, Clear HANG test request 0x%x\n",
19924 __FUNCTION__, dhd->req_hang_type));
19925 dhd->req_hang_type = 0;
19926 }
19927 #endif /* DHD_HANG_SEND_UP_TEST */
19928 if ((dhd->hang_reason <= HANG_REASON_MASK) || (dhd->hang_reason >= HANG_REASON_MAX)) {
19929 WL_ERR(("%s, Invalid hang reason 0x%x\n",
19930 __FUNCTION__, dhd->hang_reason));
19931 dhd->hang_reason = HANG_REASON_UNKNOWN;
19932 }
19933 #ifdef DHD_USE_EXTENDED_HANG_REASON
19934 if (dhd->hang_reason != 0) {
19935 reason = dhd->hang_reason;
19936 }
19937 #endif /* DHD_USE_EXTENDED_HANG_REASON */
19938 WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32)(dhd->hang_reason)));
19939
19940 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
19941 #ifdef SOFTAP_SEND_HANGEVT
19942 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
19943 cfg80211_del_sta(dev, hang_mac, GFP_ATOMIC);
19944 } else
19945 #endif /* SOFTAP_SEND_HANGEVT */
19946 {
19947 if (dhd->up == TRUE) {
19948 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
19949 wl_cfgvendor_send_hang_event(dev, reason,
19950 dhd->hang_info, dhd->hang_info_cnt);
19951 #else
19952 CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
19953 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
19954 }
19955 }
19956 if (cfg != NULL) {
19957 wl_link_down(cfg);
19958 }
19959 return 0;
19960 }
19961
19962 s32 wl_cfg80211_down(struct net_device *dev)
19963 {
19964 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19965 s32 err = BCME_ERROR;
19966
19967 WL_DBG(("In\n"));
19968
19969 if (cfg) {
19970 mutex_lock(&cfg->usr_sync);
19971 err = __wl_cfg80211_down(cfg);
19972 mutex_unlock(&cfg->usr_sync);
19973 }
19974
19975 return err;
19976 }
19977
19978 void
19979 wl_cfg80211_sta_ifdown(struct net_device *dev)
19980 {
19981 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19982
19983 WL_DBG(("In\n"));
19984
19985 if (cfg) {
19986 if (cfg->scan_request) {
19987 wl_notify_scan_done(cfg, true);
19988 cfg->scan_request = NULL;
19989 }
19990 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19991 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
19992 wl_get_drv_status(cfg, CONNECTED, dev)) {
19993 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
19994 }
19995 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19996 }
19997 }
19998
19999 static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
20000 {
20001 unsigned long flags;
20002 void *rptr = NULL;
20003 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
20004
20005 if (!profile)
20006 return NULL;
20007 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
20008 switch (item) {
20009 case WL_PROF_SEC:
20010 rptr = &profile->sec;
20011 break;
20012 case WL_PROF_ACT:
20013 rptr = &profile->active;
20014 break;
20015 case WL_PROF_BSSID:
20016 rptr = profile->bssid;
20017 break;
20018 case WL_PROF_SSID:
20019 rptr = &profile->ssid;
20020 break;
20021 case WL_PROF_CHAN:
20022 rptr = &profile->channel;
20023 break;
20024 case WL_PROF_LATEST_BSSID:
20025 rptr = profile->latest_bssid;
20026 break;
20027 }
20028 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
20029 if (!rptr)
20030 WL_ERR(("invalid item (%d)\n", item));
20031 return rptr;
20032 }
20033
20034 static s32
20035 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
20036 const wl_event_msg_t *e, const void *data, s32 item)
20037 {
20038 s32 err = 0;
20039 const struct wlc_ssid *ssid;
20040 unsigned long flags;
20041 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
20042
20043 if (!profile)
20044 return WL_INVALID;
20045 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
20046 switch (item) {
20047 case WL_PROF_SSID:
20048 ssid = (const wlc_ssid_t *) data;
20049 memset(profile->ssid.SSID, 0,
20050 sizeof(profile->ssid.SSID));
20051 profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
20052 memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
20053 break;
20054 case WL_PROF_BSSID:
20055 if (data)
20056 memcpy(profile->bssid, data, ETHER_ADDR_LEN);
20057 else
20058 memset(profile->bssid, 0, ETHER_ADDR_LEN);
20059 break;
20060 case WL_PROF_SEC:
20061 memcpy(&profile->sec, data, sizeof(profile->sec));
20062 break;
20063 case WL_PROF_ACT:
20064 profile->active = *(const bool *)data;
20065 break;
20066 case WL_PROF_BEACONINT:
20067 profile->beacon_interval = *(const u16 *)data;
20068 break;
20069 case WL_PROF_DTIMPERIOD:
20070 profile->dtim_period = *(const u8 *)data;
20071 break;
20072 case WL_PROF_CHAN:
20073 profile->channel = *(const u32*)data;
20074 break;
20075 case WL_PROF_LATEST_BSSID:
20076 if (data) {
20077 memcpy(profile->latest_bssid, data, ETHER_ADDR_LEN);
20078 } else {
20079 memset(profile->latest_bssid, 0, ETHER_ADDR_LEN);
20080 }
20081 break;
20082 default:
20083 err = -EOPNOTSUPP;
20084 break;
20085 }
20086 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
20087
20088 if (err == -EOPNOTSUPP)
20089 WL_ERR(("unsupported item (%d)\n", item));
20090
20091 return err;
20092 }
20093
20094 void wl_cfg80211_dbg_level(u32 level)
20095 {
20096 /*
20097 * prohibit to change debug level
20098 * by insmod parameter.
20099 * eventually debug level will be configured
20100 * in compile time by using CONFIG_XXX
20101 */
20102 /* wl_dbg_level = level; */
20103 }
20104
20105 static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev)
20106 {
20107 return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS;
20108 }
20109
20110 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
20111 {
20112 return cfg->ibss_starter;
20113 }
20114
20115 static void wl_rst_ie(struct bcm_cfg80211 *cfg)
20116 {
20117 struct wl_ie *ie = wl_to_ie(cfg);
20118
20119 ie->offset = 0;
20120 }
20121
20122 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
20123 {
20124 struct wl_ie *ie = wl_to_ie(cfg);
20125 s32 err = 0;
20126
20127 if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
20128 WL_ERR(("ei crosses buffer boundary\n"));
20129 return -ENOSPC;
20130 }
20131 ie->buf[ie->offset] = t;
20132 ie->buf[ie->offset + 1] = l;
20133 memcpy(&ie->buf[ie->offset + 2], v, l);
20134 ie->offset += l + 2;
20135
20136 return err;
20137 }
20138
20139 static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 *ie_size,
20140 bool roam)
20141 {
20142 u8 *ssidie;
20143 int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN);
20144 int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len;
20145 /* cfg80211_find_ie defined in kernel returning const u8 */
20146
20147 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
20148 4 && __GNUC_MINOR__ >= 6))
20149 _Pragma("GCC diagnostic push")
20150 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
20151 #endif // endif
20152 ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
20153 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
20154 4 && __GNUC_MINOR__ >= 6))
20155 _Pragma("GCC diagnostic pop")
20156 #endif // endif
20157
20158 /* ERROR out if
20159 * 1. No ssid IE is FOUND or
20160 * 2. New ssid length is > what was allocated for existing ssid (as
20161 * we do not want to overwrite the rest of the IEs) or
20162 * 3. If in case of erroneous buffer input where ssid length doesnt match the space
20163 * allocated to it.
20164 */
20165 if (!ssidie) {
20166 return;
20167 }
20168 available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream);
20169 remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
20170 unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size);
20171 if (ssidie[1] > available_buffer_len) {
20172 WL_ERR_MEM(("%s: skip wl_update_hidden_ap_ie : overflow\n", __FUNCTION__));
20173 return;
20174 }
20175
20176 if (ssidie[1] != ssid_len) {
20177 if (ssidie[1]) {
20178 WL_INFORM_MEM(("%s: Wrong SSID len: %d != %d\n",
20179 __FUNCTION__, ssidie[1], bi->SSID_len));
20180 }
20181 if ((roam && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) {
20182 WL_INFORM_MEM(("Changing the SSID Info.\n"));
20183 memmove(ssidie + ssid_len + 2,
20184 (ssidie + 2) + ssidie[1],
20185 remaining_ie_buf_len);
20186 memcpy(ssidie + 2, bi->SSID, ssid_len);
20187 *ie_size = *ie_size + ssid_len - ssidie[1];
20188 ssidie[1] = ssid_len;
20189 } else if (ssid_len < ssidie[1]) {
20190 WL_ERR_MEM(("%s: Invalid SSID len: %d < %d\n",
20191 __FUNCTION__, bi->SSID_len, ssidie[1]));
20192 }
20193 return;
20194 }
20195 if (*(ssidie + 2) == '\0')
20196 memcpy(ssidie + 2, bi->SSID, ssid_len);
20197 return;
20198 }
20199
20200 static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size)
20201 {
20202 struct wl_ie *ie = wl_to_ie(cfg);
20203 s32 err = 0;
20204
20205 if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
20206 WL_ERR(("ei_stream crosses buffer boundary\n"));
20207 return -ENOSPC;
20208 }
20209 memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
20210 ie->offset += ie_size;
20211
20212 return err;
20213 }
20214
20215 static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size)
20216 {
20217 struct wl_ie *ie = wl_to_ie(cfg);
20218 s32 err = 0;
20219
20220 if (unlikely(ie->offset > dst_size)) {
20221 WL_ERR(("dst_size is not enough\n"));
20222 return -ENOSPC;
20223 }
20224 memcpy(dst, &ie->buf[0], ie->offset);
20225
20226 return err;
20227 }
20228
20229 static u32 wl_get_ielen(struct bcm_cfg80211 *cfg)
20230 {
20231 struct wl_ie *ie = wl_to_ie(cfg);
20232
20233 return ie->offset;
20234 }
20235
20236 static void wl_link_up(struct bcm_cfg80211 *cfg)
20237 {
20238 cfg->link_up = true;
20239 }
20240
20241 static void wl_link_down(struct bcm_cfg80211 *cfg)
20242 {
20243 struct wl_connect_info *conn_info = wl_to_conn(cfg);
20244
20245 WL_DBG(("In\n"));
20246 cfg->link_up = false;
20247 conn_info->req_ie_len = 0;
20248 conn_info->resp_ie_len = 0;
20249 }
20250
20251 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
20252 {
20253 unsigned long flags;
20254
20255 spin_lock_irqsave(&cfg->eq_lock, flags);
20256 return flags;
20257 }
20258
20259 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
20260 {
20261 spin_unlock_irqrestore(&cfg->eq_lock, flags);
20262 }
20263
20264 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
20265 {
20266 spin_lock_init(&cfg->eq_lock);
20267 }
20268
20269 static void wl_delay(u32 ms)
20270 {
20271 if (in_atomic() || (ms < jiffies_to_msecs(1))) {
20272 OSL_DELAY(ms*1000);
20273 } else {
20274 OSL_SLEEP(ms);
20275 }
20276 }
20277
20278 s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
20279 {
20280 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20281 struct ether_addr primary_mac;
20282 if (!cfg->p2p)
20283 return -1;
20284 if (!p2p_is_on(cfg)) {
20285 get_primary_mac(cfg, &primary_mac);
20286 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
20287 memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN);
20288 } else {
20289 memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
20290 ETHER_ADDR_LEN);
20291 }
20292
20293 return 0;
20294 }
20295 s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
20296 {
20297 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20298
20299 return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
20300 }
20301
20302 s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
20303 {
20304 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20305
20306 return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
20307 }
20308
20309 s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
20310 {
20311 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20312
20313 return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
20314 }
20315
20316 s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
20317 {
20318 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20319
20320 return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
20321 }
20322
20323 s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
20324 {
20325 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20326
20327 return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
20328 }
20329
20330 #ifdef P2PLISTEN_AP_SAMECHN
20331 s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
20332 {
20333 s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
20334
20335 if ((ret == 0) && enable) {
20336 /* disable PM for p2p responding on infra AP channel */
20337 s32 pm = PM_OFF;
20338
20339 ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm));
20340 }
20341
20342 return ret;
20343 }
20344 #endif /* P2PLISTEN_AP_SAMECHN */
20345
20346 s32 wl_cfg80211_channel_to_freq(u32 channel)
20347 {
20348 int freq = 0;
20349
20350 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
20351 freq = ieee80211_channel_to_frequency(channel);
20352 #else
20353 {
20354 u16 band = 0;
20355 if (channel <= CH_MAX_2G_CHANNEL)
20356 band = NL80211_BAND_2GHZ;
20357 else
20358 band = NL80211_BAND_5GHZ;
20359 freq = ieee80211_channel_to_frequency(channel, band);
20360 }
20361 #endif // endif
20362 return freq;
20363 }
20364
20365 #ifdef WLTDLS
20366 static s32
20367 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
20368 const wl_event_msg_t *e, void *data) {
20369
20370 struct net_device *ndev = NULL;
20371 u32 reason = ntoh32(e->reason);
20372 s8 *msg = NULL;
20373
20374 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
20375
20376 switch (reason) {
20377 case WLC_E_TDLS_PEER_DISCOVERED :
20378 msg = " TDLS PEER DISCOVERD ";
20379 break;
20380 case WLC_E_TDLS_PEER_CONNECTED :
20381 if (cfg->tdls_mgmt_frame) {
20382 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
20383 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
20384 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0);
20385 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
20386 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
20387 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0,
20388 GFP_ATOMIC);
20389 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
20390 defined(WL_COMPAT_WIRELESS)
20391 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
20392 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
20393 GFP_ATOMIC);
20394 #else
20395 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
20396 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, GFP_ATOMIC);
20397
20398 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
20399 }
20400 msg = " TDLS PEER CONNECTED ";
20401 #ifdef SUPPORT_SET_CAC
20402 /* TDLS connect reset CAC */
20403 wl_cfg80211_set_cac(cfg, 0);
20404 #endif /* SUPPORT_SET_CAC */
20405 break;
20406 case WLC_E_TDLS_PEER_DISCONNECTED :
20407 if (cfg->tdls_mgmt_frame) {
20408 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
20409 cfg->tdls_mgmt_frame = NULL;
20410 cfg->tdls_mgmt_frame_len = 0;
20411 cfg->tdls_mgmt_freq = 0;
20412 }
20413 msg = "TDLS PEER DISCONNECTED ";
20414 #ifdef SUPPORT_SET_CAC
20415 /* TDLS disconnec, set CAC */
20416 wl_cfg80211_set_cac(cfg, 1);
20417 #endif /* SUPPORT_SET_CAC */
20418 break;
20419 }
20420 if (msg) {
20421 WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((const u8*)(&e->addr)),
20422 (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
20423 }
20424 return 0;
20425
20426 }
20427 #endif /* WLTDLS */
20428
20429 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
20430 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
20431 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
20432 static s32
20433 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
20434 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
20435 u32 peer_capability, const u8 *buf, size_t len)
20436 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
20437 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
20438 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
20439 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
20440 u32 peer_capability, const u8 *buf, size_t len)
20441 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
20442 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
20443 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
20444 u32 peer_capability, bool initiator, const u8 *buf, size_t len)
20445 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20446 static s32
20447 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
20448 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
20449 const u8 *buf, size_t len)
20450 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20451 {
20452 s32 ret = 0;
20453 #ifdef WLTDLS
20454 struct bcm_cfg80211 *cfg;
20455 tdls_wfd_ie_iovar_t info;
20456 memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
20457 cfg = wl_get_cfg(dev);
20458
20459 #if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
20460 /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
20461 * and that cuases build error
20462 */
20463 BCM_REFERENCE(peer_capability);
20464 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20465
20466 switch (action_code) {
20467 /* We need to set TDLS Wifi Display IE to firmware
20468 * using tdls_wfd_ie iovar
20469 */
20470 case WLAN_TDLS_SET_PROBE_WFD_IE:
20471 WL_ERR(("%s WLAN_TDLS_SET_PROBE_WFD_IE\n", __FUNCTION__));
20472 info.mode = TDLS_WFD_PROBE_IE_TX;
20473 memcpy(&info.data, buf, len);
20474 info.length = len;
20475 break;
20476 case WLAN_TDLS_SET_SETUP_WFD_IE:
20477 WL_ERR(("%s WLAN_TDLS_SET_SETUP_WFD_IE\n", __FUNCTION__));
20478 info.mode = TDLS_WFD_IE_TX;
20479 memcpy(&info.data, buf, len);
20480 info.length = len;
20481 break;
20482 case WLAN_TDLS_SET_WFD_ENABLED:
20483 WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_ENABLED\n", __FUNCTION__));
20484 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
20485 goto out;
20486 case WLAN_TDLS_SET_WFD_DISABLED:
20487 WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_DISABLED\n", __FUNCTION__));
20488 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
20489 goto out;
20490 default:
20491 WL_ERR(("Unsupported action code : %d\n", action_code));
20492 goto out;
20493 }
20494 ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
20495 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
20496
20497 if (ret) {
20498 WL_ERR(("tdls_wfd_ie error %d\n", ret));
20499 }
20500
20501 out:
20502 #endif /* WLTDLS */
20503 return ret;
20504 }
20505
20506 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
20507 static s32
20508 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
20509 const u8 *peer, enum nl80211_tdls_operation oper)
20510 #else
20511 static s32
20512 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
20513 u8 *peer, enum nl80211_tdls_operation oper)
20514 #endif // endif
20515 {
20516 s32 ret = 0;
20517 #ifdef WLTDLS
20518 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20519 tdls_iovar_t info;
20520 dhd_pub_t *dhdp;
20521 bool tdls_auto_mode = false;
20522 dhdp = (dhd_pub_t *)(cfg->pub);
20523 memset(&info, 0, sizeof(tdls_iovar_t));
20524 if (peer) {
20525 memcpy(&info.ea, peer, ETHER_ADDR_LEN);
20526 } else {
20527 return -1;
20528 }
20529 switch (oper) {
20530 case NL80211_TDLS_DISCOVERY_REQ:
20531 /* If the discovery request is broadcast then we need to set
20532 * info.mode to Tunneled Probe Request
20533 */
20534 if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
20535 info.mode = TDLS_MANUAL_EP_WFD_TPQ;
20536 WL_ERR(("%s TDLS TUNNELED PRBOBE REQUEST\n", __FUNCTION__));
20537 } else {
20538 info.mode = TDLS_MANUAL_EP_DISCOVERY;
20539 }
20540 break;
20541 case NL80211_TDLS_SETUP:
20542 if (dhdp->tdls_mode == true) {
20543 info.mode = TDLS_MANUAL_EP_CREATE;
20544 tdls_auto_mode = false;
20545 /* Do tear down and create a fresh one */
20546 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_TEARDOWN, tdls_auto_mode);
20547 if (ret < 0) {
20548 return ret;
20549 }
20550 } else {
20551 tdls_auto_mode = true;
20552 }
20553 break;
20554 case NL80211_TDLS_TEARDOWN:
20555 info.mode = TDLS_MANUAL_EP_DELETE;
20556 break;
20557 default:
20558 WL_ERR(("Unsupported operation : %d\n", oper));
20559 goto out;
20560 }
20561 /* turn on TDLS */
20562 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_SETUP, tdls_auto_mode);
20563 if (ret < 0) {
20564 return ret;
20565 }
20566 if (info.mode) {
20567 ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
20568 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
20569 if (ret) {
20570 WL_ERR(("tdls_endpoint error %d\n", ret));
20571 }
20572 }
20573 out:
20574 if (ret) {
20575 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
20576 return -ENOTSUPP;
20577 }
20578 #endif /* WLTDLS */
20579 return ret;
20580 }
20581 #endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
20582
20583 s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
20584 enum wl_management_type type)
20585 {
20586 struct bcm_cfg80211 *cfg;
20587 s32 ret = 0;
20588 struct ether_addr primary_mac;
20589 s32 bssidx = 0;
20590 s32 pktflag = 0;
20591 cfg = wl_get_cfg(ndev);
20592
20593 if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
20594 /* Vendor IEs should be set to FW
20595 * after SoftAP interface is brought up
20596 */
20597 WL_DBG(("Skipping set IE since AP is not up \n"));
20598 goto exit;
20599 } else if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
20600 /* Either stand alone AP case or P2P discovery */
20601 if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
20602 /* Stand alone AP case on primary interface */
20603 WL_DBG(("Apply IEs for Primary AP Interface \n"));
20604 bssidx = 0;
20605 } else {
20606 if (!cfg->p2p) {
20607 /* If p2p not initialized, return failure */
20608 WL_ERR(("P2P not initialized \n"));
20609 goto exit;
20610 }
20611 /* P2P Discovery case (p2p listen) */
20612 if (!cfg->p2p->on) {
20613 /* Turn on Discovery interface */
20614 get_primary_mac(cfg, &primary_mac);
20615 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
20616 p2p_on(cfg) = true;
20617 ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
20618 if (unlikely(ret)) {
20619 WL_ERR(("Enable discovery failed \n"));
20620 goto exit;
20621 }
20622 }
20623 WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
20624 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
20625 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
20626 }
20627 } else {
20628 /* Virtual AP/ P2P Group Interface */
20629 WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
20630 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
20631 }
20632
20633 if (ndev != NULL) {
20634 switch (type) {
20635 case WL_BEACON:
20636 pktflag = VNDR_IE_BEACON_FLAG;
20637 break;
20638 case WL_PROBE_RESP:
20639 pktflag = VNDR_IE_PRBRSP_FLAG;
20640 break;
20641 case WL_ASSOC_RESP:
20642 pktflag = VNDR_IE_ASSOCRSP_FLAG;
20643 break;
20644 }
20645 if (pktflag) {
20646 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
20647 ndev_to_cfgdev(ndev), bssidx, pktflag, buf, len);
20648 }
20649 }
20650 exit:
20651 return ret;
20652 }
20653
20654 #ifdef WL_SUPPORT_AUTO_CHANNEL
20655 static s32
20656 wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev)
20657 {
20658 u32 val = 0;
20659 s32 ret = BCME_ERROR;
20660 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20661
20662 if (wl_check_dongle_idle(bcmcfg_to_wiphy(cfg)) != TRUE) {
20663 WL_ERR(("FW is busy to add interface"));
20664 return ret;
20665 }
20666
20667 /* Set interface up, explicitly. */
20668 val = 1;
20669
20670 ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
20671 if (ret < 0) {
20672 WL_ERR(("set interface up failed, error = %d\n", ret));
20673 goto done;
20674 }
20675
20676 /* Stop all scan explicitly, till auto channel selection complete. */
20677 wl_set_drv_status(cfg, SCANNING, ndev);
20678 if (cfg->escan_info.ndev == NULL) {
20679 ret = BCME_OK;
20680 goto done;
20681 }
20682
20683 wl_cfg80211_cancel_scan(cfg);
20684
20685 done:
20686 return ret;
20687 }
20688
20689 static bool
20690 wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec)
20691 {
20692 bool valid = false;
20693 char chanbuf[CHANSPEC_STR_LEN];
20694
20695 /* channel 1 to 14 */
20696 if ((chanspec >= 0x2b01) && (chanspec <= 0x2b0e)) {
20697 valid = true;
20698 }
20699 /* channel 36 to 48 */
20700 else if ((chanspec >= 0x1b24) && (chanspec <= 0x1b30)) {
20701 valid = true;
20702 }
20703 /* channel 149 to 161 */
20704 else if ((chanspec >= 0x1b95) && (chanspec <= 0x1ba1)) {
20705 valid = true;
20706 }
20707 else {
20708 valid = false;
20709 WL_INFORM_MEM(("invalid P2P chanspec, chanspec = %s\n",
20710 wf_chspec_ntoa_ex(chanspec, chanbuf)));
20711 }
20712
20713 return valid;
20714 }
20715
20716 s32
20717 wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
20718 {
20719 s32 ret = BCME_ERROR;
20720 struct bcm_cfg80211 *cfg = NULL;
20721 chanspec_t chanspec = 0;
20722
20723 cfg = wl_get_cfg(ndev);
20724
20725 /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
20726 chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 |
20727 WL_CHANSPEC_CTL_SB_NONE);
20728 chanspec = wl_chspec_host_to_driver(chanspec);
20729
20730 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
20731 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
20732 if (ret < 0) {
20733 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
20734 }
20735
20736 return ret;
20737 }
20738
20739 s32
20740 wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
20741 {
20742 u32 channel = 0;
20743 s32 ret = BCME_ERROR;
20744 s32 i = 0;
20745 s32 j = 0;
20746 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20747 wl_uint32_list_t *list = NULL;
20748 chanspec_t chanspec = 0;
20749
20750 /* Restrict channels to 5GHz, 20MHz BW, no SB. */
20751 chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 |
20752 WL_CHANSPEC_CTL_SB_NONE);
20753 chanspec = wl_chspec_host_to_driver(chanspec);
20754
20755 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
20756 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
20757 if (ret < 0) {
20758 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
20759 goto done;
20760 }
20761
20762 list = (wl_uint32_list_t *)buf;
20763 /* Skip DFS and inavlid P2P channel. */
20764 for (i = 0, j = 0; i < dtoh32(list->count); i++) {
20765 chanspec = (chanspec_t) dtoh32(list->element[i]);
20766 channel = CHSPEC_CHANNEL(chanspec);
20767
20768 ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
20769 if (ret < 0) {
20770 WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret));
20771 goto done;
20772 }
20773
20774 if (CHANNEL_IS_RADAR(channel) ||
20775 !(wl_cfg80211_valid_chanspec_p2p(chanspec))) {
20776 continue;
20777 } else {
20778 list->element[j] = list->element[i];
20779 }
20780
20781 j++;
20782 }
20783
20784 list->count = j;
20785
20786 done:
20787 return ret;
20788 }
20789
20790 static s32
20791 wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen,
20792 int *channel)
20793 {
20794 s32 ret = BCME_ERROR;
20795 int chosen = 0;
20796 int retry = 0;
20797
20798 /* Start auto channel selection scan. */
20799 ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, NULL, 0);
20800 if (ret < 0) {
20801 WL_ERR(("can't start auto channel scan, error = %d\n", ret));
20802 *channel = 0;
20803 goto done;
20804 }
20805
20806 /* Wait for auto channel selection, worst case possible delay is 5250ms. */
20807 retry = CHAN_SEL_RETRY_COUNT;
20808
20809 while (retry--) {
20810 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
20811 chosen = 0;
20812 ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
20813 if ((ret == 0) && (dtoh32(chosen) != 0)) {
20814 *channel = (u16)(chosen & 0x00FF);
20815 WL_INFORM_MEM(("selected channel = %d\n", *channel));
20816 break;
20817 }
20818 WL_DBG(("attempt = %d, ret = %d, chosen = %d\n",
20819 (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
20820 }
20821
20822 if (retry <= 0) {
20823 WL_ERR(("failure, auto channel selection timed out\n"));
20824 *channel = 0;
20825 ret = BCME_ERROR;
20826 }
20827
20828 done:
20829 return ret;
20830 }
20831
20832 static s32
20833 wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev)
20834 {
20835 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20836 /* Clear scan stop driver status. */
20837 wl_clr_drv_status(cfg, SCANNING, ndev);
20838
20839 return BCME_OK;
20840 }
20841
20842 s32
20843 wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len)
20844 {
20845 int channel = 0;
20846 s32 ret = BCME_ERROR;
20847 u8 *buf = NULL;
20848 char *pos = cmd;
20849 struct bcm_cfg80211 *cfg = NULL;
20850 struct net_device *ndev = NULL;
20851
20852 memset(cmd, 0, total_len);
20853 cfg = wl_get_cfg(dev);
20854
20855 buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
20856 if (buf == NULL) {
20857 WL_ERR(("failed to allocate chanspec buffer\n"));
20858 return -ENOMEM;
20859 }
20860
20861 /*
20862 * Always use primary interface, irrespective of interface on which
20863 * command came.
20864 */
20865 ndev = bcmcfg_to_prmry_ndev(cfg);
20866
20867 /*
20868 * Make sure that FW and driver are in right state to do auto channel
20869 * selection scan.
20870 */
20871 ret = wl_cfg80211_set_auto_channel_scan_state(ndev);
20872 if (ret < 0) {
20873 WL_ERR(("can't set auto channel scan state, error = %d\n", ret));
20874 goto done;
20875 }
20876
20877 /* Best channel selection in 2.4GHz band. */
20878 ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
20879 if (ret < 0) {
20880 WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
20881 goto done;
20882 }
20883
20884 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
20885 &channel);
20886 if (ret < 0) {
20887 WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
20888 goto done;
20889 }
20890
20891 if (CHANNEL_IS_2G(channel)) {
20892 channel = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
20893 } else {
20894 WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel));
20895 channel = 0;
20896 }
20897
20898 pos += snprintf(pos, total_len, "%04d ", channel);
20899
20900 /* Best channel selection in 5GHz band. */
20901 ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
20902 if (ret < 0) {
20903 WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret));
20904 goto done;
20905 }
20906
20907 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
20908 &channel);
20909 if (ret < 0) {
20910 WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret));
20911 goto done;
20912 }
20913
20914 if (CHANNEL_IS_5G(channel)) {
20915 channel = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
20916 } else {
20917 WL_ERR(("invalid 5GHz channel, channel = %d\n", channel));
20918 channel = 0;
20919 }
20920
20921 pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
20922
20923 /* Set overall best channel same as 5GHz best channel. */
20924 pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
20925
20926 done:
20927 if (NULL != buf) {
20928 MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
20929 }
20930
20931 /* Restore FW and driver back to normal state. */
20932 ret = wl_cfg80211_restore_auto_channel_scan_state(ndev);
20933 if (ret < 0) {
20934 WL_ERR(("can't restore auto channel scan state, error = %d\n", ret));
20935 }
20936
20937 return (pos - cmd);
20938 }
20939 #endif /* WL_SUPPORT_AUTO_CHANNEL */
20940
20941 static const struct rfkill_ops wl_rfkill_ops = {
20942 .set_block = wl_rfkill_set
20943 };
20944
20945 static int wl_rfkill_set(void *data, bool blocked)
20946 {
20947 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
20948
20949 WL_DBG(("Enter \n"));
20950 WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
20951
20952 if (!cfg)
20953 return -EINVAL;
20954
20955 cfg->rf_blocked = blocked;
20956
20957 return 0;
20958 }
20959
20960 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
20961 {
20962 s32 err = 0;
20963
20964 WL_DBG(("Enter \n"));
20965 if (!cfg)
20966 return -EINVAL;
20967 if (setup) {
20968 cfg->rfkill = rfkill_alloc("brcmfmac-wifi",
20969 wl_cfg80211_get_parent_dev(),
20970 RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
20971
20972 if (!cfg->rfkill) {
20973 err = -ENOMEM;
20974 goto err_out;
20975 }
20976
20977 err = rfkill_register(cfg->rfkill);
20978
20979 if (err)
20980 rfkill_destroy(cfg->rfkill);
20981 } else {
20982 if (!cfg->rfkill) {
20983 err = -ENOMEM;
20984 goto err_out;
20985 }
20986
20987 rfkill_unregister(cfg->rfkill);
20988 rfkill_destroy(cfg->rfkill);
20989 }
20990
20991 err_out:
20992 return err;
20993 }
20994
20995 #ifdef DEBUGFS_CFG80211
20996 /**
20997 * Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
20998 * to turn on SCAN and DBG log.
20999 * To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
21000 * To see current setting of debug level,
21001 * cat /sys/kernel/debug/dhd/debug_level
21002 */
21003 static ssize_t
21004 wl_debuglevel_write(struct file *file, const char __user *userbuf,
21005 size_t count, loff_t *ppos)
21006 {
21007 char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)], sublog[SUBLOGLEVELZ];
21008 char *params, *token, *colon;
21009 uint i, tokens, log_on = 0;
21010 size_t minsize = min_t(size_t, (sizeof(tbuf) - 1), count);
21011
21012 memset(tbuf, 0, sizeof(tbuf));
21013 memset(sublog, 0, sizeof(sublog));
21014 if (copy_from_user(&tbuf, userbuf, minsize)) {
21015 return -EFAULT;
21016 }
21017
21018 tbuf[minsize] = '\0';
21019 params = &tbuf[0];
21020 colon = strchr(params, '\n');
21021 if (colon != NULL)
21022 *colon = '\0';
21023 while ((token = strsep(&params, " ")) != NULL) {
21024 memset(sublog, 0, sizeof(sublog));
21025 if (token == NULL || !*token)
21026 break;
21027 if (*token == '\0')
21028 continue;
21029 colon = strchr(token, ':');
21030 if (colon != NULL) {
21031 *colon = ' ';
21032 }
21033 tokens = sscanf(token, "%"S(SUBLOGLEVEL)"s %u", sublog, &log_on);
21034 if (colon != NULL)
21035 *colon = ':';
21036
21037 if (tokens == 2) {
21038 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
21039 if (!strncmp(sublog, sublogname_map[i].sublogname,
21040 strlen(sublogname_map[i].sublogname))) {
21041 if (log_on)
21042 wl_dbg_level |=
21043 (sublogname_map[i].log_level);
21044 else
21045 wl_dbg_level &=
21046 ~(sublogname_map[i].log_level);
21047 }
21048 }
21049 } else
21050 WL_ERR(("%s: can't parse '%s' as a "
21051 "SUBMODULE:LEVEL (%d tokens)\n",
21052 tbuf, token, tokens));
21053
21054 }
21055 return count;
21056 }
21057
21058 static ssize_t
21059 wl_debuglevel_read(struct file *file, char __user *user_buf,
21060 size_t count, loff_t *ppos)
21061 {
21062 char *param;
21063 char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)];
21064 uint i;
21065 memset(tbuf, 0, sizeof(tbuf));
21066 param = &tbuf[0];
21067 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
21068 param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
21069 sublogname_map[i].sublogname,
21070 (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0);
21071 }
21072 *param = '\n';
21073 return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0]));
21074
21075 }
21076 static const struct file_operations fops_debuglevel = {
21077 .open = NULL,
21078 .write = wl_debuglevel_write,
21079 .read = wl_debuglevel_read,
21080 .owner = THIS_MODULE,
21081 .llseek = NULL,
21082 };
21083
21084 static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg)
21085 {
21086 s32 err = 0;
21087 struct dentry *_dentry;
21088 if (!cfg)
21089 return -EINVAL;
21090 cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
21091 if (!cfg->debugfs || IS_ERR(cfg->debugfs)) {
21092 if (cfg->debugfs == ERR_PTR(-ENODEV))
21093 WL_ERR(("Debugfs is not enabled on this kernel\n"));
21094 else
21095 WL_ERR(("Can not create debugfs directory\n"));
21096 cfg->debugfs = NULL;
21097 goto exit;
21098
21099 }
21100 _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR,
21101 cfg->debugfs, cfg, &fops_debuglevel);
21102 if (!_dentry || IS_ERR(_dentry)) {
21103 WL_ERR(("failed to create debug_level debug file\n"));
21104 wl_free_debugfs(cfg);
21105 }
21106 exit:
21107 return err;
21108 }
21109 static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg)
21110 {
21111 if (!cfg)
21112 return -EINVAL;
21113 if (cfg->debugfs)
21114 debugfs_remove_recursive(cfg->debugfs);
21115 cfg->debugfs = NULL;
21116 return 0;
21117 }
21118 #endif /* DEBUGFS_CFG80211 */
21119
21120 struct bcm_cfg80211 *wl_cfg80211_get_bcmcfg(void)
21121 {
21122 return g_bcmcfg;
21123 }
21124
21125 void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 *cfg)
21126 {
21127 g_bcmcfg = cfg;
21128 }
21129
21130 struct device *wl_cfg80211_get_parent_dev(void)
21131 {
21132 return cfg80211_parent_dev;
21133 }
21134
21135 void wl_cfg80211_set_parent_dev(void *dev)
21136 {
21137 cfg80211_parent_dev = dev;
21138 }
21139
21140 static void wl_cfg80211_clear_parent_dev(void)
21141 {
21142 cfg80211_parent_dev = NULL;
21143 }
21144
21145 void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
21146 {
21147 u8 ioctl_buf[WLC_IOCTL_SMLEN];
21148
21149 if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
21150 "cur_etheraddr", NULL, 0, ioctl_buf, sizeof(ioctl_buf),
21151 0, NULL) == BCME_OK) {
21152 memcpy(mac->octet, ioctl_buf, ETHER_ADDR_LEN);
21153 } else {
21154 memset(mac->octet, 0, ETHER_ADDR_LEN);
21155 }
21156 }
21157 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
21158 {
21159 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
21160 if (((dev_role == NL80211_IFTYPE_AP) &&
21161 !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
21162 ((dev_role == NL80211_IFTYPE_P2P_GO) &&
21163 !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
21164 {
21165 WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
21166 return false;
21167 }
21168 return true;
21169 }
21170
21171 int wl_cfg80211_do_driver_init(struct net_device *net)
21172 {
21173 struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
21174
21175 if (!cfg || !cfg->wdev)
21176 return -EINVAL;
21177
21178 if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
21179 return -1;
21180
21181 return 0;
21182 }
21183
21184 void wl_cfg80211_enable_trace(bool set, u32 level)
21185 {
21186 if (set)
21187 wl_dbg_level = level & WL_DBG_LEVEL;
21188 else
21189 wl_dbg_level |= (WL_DBG_LEVEL & level);
21190 }
21191 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
21192 2, 0))
21193 static s32
21194 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
21195 bcm_struct_cfgdev *cfgdev, u64 cookie)
21196 {
21197 /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
21198 * is passed with CMD_FRAME. This callback is supposed to cancel
21199 * the OFFCHANNEL Wait. Since we are already taking care of that
21200 * with the tx_mgmt logic, do nothing here.
21201 */
21202
21203 return 0;
21204 }
21205 #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
21206
21207 #ifdef WL11U
21208 static bcm_tlv_t *
21209 wl_cfg80211_find_interworking_ie(const u8 *parse, u32 len)
21210 {
21211 bcm_tlv_t *ie;
21212
21213 /* unfortunately it's too much work to dispose the const cast - bcm_parse_tlvs
21214 * is used everywhere and changing its prototype to take const qualifier needs
21215 * a massive change to all its callers...
21216 */
21217
21218 if ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_INTERWORKING_ID))) {
21219 return ie;
21220 }
21221 return NULL;
21222 }
21223
21224 static s32
21225 wl_cfg80211_clear_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx)
21226 {
21227 ie_setbuf_t ie_setbuf;
21228
21229 WL_DBG(("clear interworking IE\n"));
21230
21231 memset(&ie_setbuf, 0, sizeof(ie_setbuf_t));
21232
21233 ie_setbuf.ie_buffer.iecount = htod32(1);
21234 ie_setbuf.ie_buffer.ie_list[0].ie_data.id = DOT11_MNG_INTERWORKING_ID;
21235 ie_setbuf.ie_buffer.ie_list[0].ie_data.len = 0;
21236
21237 return wldev_iovar_setbuf_bsscfg(ndev, "ie", &ie_setbuf, sizeof(ie_setbuf),
21238 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
21239 }
21240
21241 static s32
21242 wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
21243 uint8 ie_id, uint8 *data, uint8 data_len)
21244 {
21245 s32 err = BCME_OK;
21246 s32 buf_len;
21247 ie_setbuf_t *ie_setbuf;
21248 ie_getbuf_t ie_getbufp;
21249 char getbuf[WLC_IOCTL_SMLEN];
21250
21251 if (ie_id != DOT11_MNG_INTERWORKING_ID) {
21252 WL_ERR(("unsupported (id=%d)\n", ie_id));
21253 return BCME_UNSUPPORTED;
21254 }
21255
21256 /* access network options (1 octet) is the mandatory field */
21257 if (!data || data_len == 0 || data_len > IW_IES_MAX_BUF_LEN) {
21258 WL_ERR(("wrong interworking IE (len=%d)\n", data_len));
21259 return BCME_BADARG;
21260 }
21261
21262 /* Validate the pktflag parameter */
21263 if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
21264 VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
21265 VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG|
21266 VNDR_IE_CUSTOM_FLAG))) {
21267 WL_ERR(("invalid packet flag 0x%x\n", pktflag));
21268 return BCME_BADARG;
21269 }
21270
21271 buf_len = sizeof(ie_setbuf_t) + data_len - 1;
21272
21273 ie_getbufp.id = DOT11_MNG_INTERWORKING_ID;
21274 if (wldev_iovar_getbuf_bsscfg(ndev, "ie", (void *)&ie_getbufp,
21275 sizeof(ie_getbufp), getbuf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)
21276 == BCME_OK) {
21277 if (!memcmp(&getbuf[TLV_HDR_LEN], data, data_len)) {
21278 WL_DBG(("skip to set interworking IE\n"));
21279 return BCME_OK;
21280 }
21281 }
21282
21283 /* if already set with previous values, delete it first */
21284 if (cfg->wl11u) {
21285 if ((err = wl_cfg80211_clear_iw_ie(cfg, ndev, bssidx)) != BCME_OK) {
21286 return err;
21287 }
21288 }
21289
21290 ie_setbuf = (ie_setbuf_t *)MALLOCZ(cfg->osh, buf_len);
21291 if (!ie_setbuf) {
21292 WL_ERR(("Error allocating buffer for IE\n"));
21293 return -ENOMEM;
21294 }
21295 strncpy(ie_setbuf->cmd, "add", sizeof(ie_setbuf->cmd));
21296 ie_setbuf->cmd[sizeof(ie_setbuf->cmd) - 1] = '\0';
21297
21298 /* Buffer contains only 1 IE */
21299 ie_setbuf->ie_buffer.iecount = htod32(1);
21300 /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */
21301 ie_setbuf->ie_buffer.ie_list[0].pktflag = htod32(pktflag);
21302
21303 /* Now, add the IE to the buffer */
21304 ie_setbuf->ie_buffer.ie_list[0].ie_data.id = DOT11_MNG_INTERWORKING_ID;
21305 ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len;
21306 memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len);
21307
21308 if ((err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
21309 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync))
21310 == BCME_OK) {
21311 WL_DBG(("set interworking IE\n"));
21312 cfg->wl11u = TRUE;
21313 err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx);
21314 }
21315
21316 MFREE(cfg->osh, ie_setbuf, buf_len);
21317 return err;
21318 }
21319 #endif /* WL11U */
21320
21321 #ifdef WL_HOST_BAND_MGMT
21322 s32
21323 wl_cfg80211_set_band(struct net_device *ndev, int band)
21324 {
21325 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21326 int ret = 0;
21327 char ioctl_buf[50];
21328
21329 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
21330 WL_ERR(("Invalid band\n"));
21331 return -EINVAL;
21332 }
21333
21334 if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band,
21335 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
21336 WL_ERR(("seting roam_band failed code=%d\n", ret));
21337 return ret;
21338 }
21339
21340 WL_DBG(("Setting band to %d\n", band));
21341 cfg->curr_band = band;
21342
21343 return 0;
21344 }
21345 #endif /* WL_HOST_BAND_MGMT */
21346
21347 s32
21348 wl_cfg80211_set_if_band(struct net_device *ndev, int band)
21349 {
21350 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21351 int ret = 0, wait_cnt;
21352 char ioctl_buf[32];
21353
21354 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
21355 WL_ERR(("Invalid band\n"));
21356 return -EINVAL;
21357 }
21358 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
21359 ret = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
21360 if (ret < 0) {
21361 WL_ERR(("WLC_DISASSOC error %d\n", ret));
21362 /* continue to set 'if_band' */
21363 }
21364 else {
21365 /* This is to ensure that 'if_band' iovar is issued only after
21366 * disconnection is completed
21367 */
21368 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
21369 while (wl_get_drv_status(cfg, CONNECTED, ndev) && wait_cnt) {
21370 WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt));
21371 wait_cnt--;
21372 OSL_SLEEP(50);
21373 }
21374 }
21375 }
21376 if ((ret = wldev_iovar_setbuf(ndev, "if_band", &band,
21377 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
21378 WL_ERR(("seting if_band failed ret=%d\n", ret));
21379 /* issue 'WLC_SET_BAND' if if_band is not supported */
21380 if (ret == BCME_UNSUPPORTED) {
21381 ret = wldev_set_band(ndev, band);
21382 if (ret < 0) {
21383 WL_ERR(("seting band failed ret=%d\n", ret));
21384 }
21385 }
21386 }
21387 return ret;
21388 }
21389
21390 s32
21391 wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int total_len)
21392 {
21393 char ioctl_buf[WLC_IOCTL_SMLEN];
21394 int err = 0;
21395 uint32 val = 0;
21396 chanspec_t chanspec = 0;
21397 int abort;
21398 int bytes_written = 0;
21399 struct wl_dfs_ap_move_status_v2 *status;
21400 char chanbuf[CHANSPEC_STR_LEN];
21401 const char *dfs_state_str[DFS_SCAN_S_MAX] = {
21402 "Radar Free On Channel",
21403 "Radar Found On Channel",
21404 "Radar Scan In Progress",
21405 "Radar Scan Aborted",
21406 "RSDB Mode switch in Progress For Scan"
21407 };
21408 if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
21409 bytes_written = snprintf(command, total_len, "AP is not up\n");
21410 return bytes_written;
21411 }
21412 if (!*data) {
21413 if ((err = wldev_iovar_getbuf(ndev, "dfs_ap_move", NULL, 0,
21414 ioctl_buf, sizeof(ioctl_buf), NULL))) {
21415 WL_ERR(("setting dfs_ap_move failed with err=%d \n", err));
21416 return err;
21417 }
21418 status = (struct wl_dfs_ap_move_status_v2 *)ioctl_buf;
21419
21420 if (status->version != WL_DFS_AP_MOVE_VERSION) {
21421 err = BCME_UNSUPPORTED;
21422 WL_ERR(("err=%d version=%d\n", err, status->version));
21423 return err;
21424 }
21425
21426 if (status->move_status != (int8) DFS_SCAN_S_IDLE) {
21427 chanspec = wl_chspec_driver_to_host(status->chanspec);
21428 if (chanspec != 0 && chanspec != INVCHANSPEC) {
21429 wf_chspec_ntoa(chanspec, chanbuf);
21430 bytes_written = snprintf(command, total_len,
21431 "AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
21432 }
21433 bytes_written += snprintf(command + bytes_written,
21434 total_len - bytes_written,
21435 "%s\n", dfs_state_str[status->move_status]);
21436 return bytes_written;
21437 } else {
21438 bytes_written = snprintf(command, total_len, "dfs AP move in IDLE state\n");
21439 return bytes_written;
21440 }
21441 }
21442
21443 abort = bcm_atoi(data);
21444 if (abort == -1) {
21445 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &abort,
21446 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
21447 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
21448 return err;
21449 }
21450 } else {
21451 chanspec = wf_chspec_aton(data);
21452 if (chanspec != 0) {
21453 val = wl_chspec_host_to_driver(chanspec);
21454 if (val != INVCHANSPEC) {
21455 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &val,
21456 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
21457 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
21458 return err;
21459 }
21460 WL_DBG((" set dfs_ap_move successfull"));
21461 } else {
21462 err = BCME_USAGE_ERROR;
21463 }
21464 }
21465 }
21466 return err;
21467 }
21468
21469 #ifdef WBTEXT
21470 s32
21471 wl_cfg80211_wbtext_set_default(struct net_device *ndev)
21472 {
21473 char commandp[WLC_IOCTL_SMLEN];
21474 s32 ret = BCME_OK;
21475 char *data;
21476
21477 WL_DBG(("set wbtext to default\n"));
21478
21479 /* set roam profile */
21480 memset(commandp, 0, sizeof(commandp));
21481 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21482 CMD_WBTEXT_PROFILE_CONFIG, DEFAULT_WBTEXT_PROFILE_A);
21483 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
21484 ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21485 if (ret != BCME_OK) {
21486 WL_ERR(("%s: Failed to set roam_prof %s error = %d\n",
21487 __FUNCTION__, data, ret));
21488 return ret;
21489 }
21490
21491 memset(commandp, 0, sizeof(commandp));
21492 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21493 CMD_WBTEXT_PROFILE_CONFIG, DEFAULT_WBTEXT_PROFILE_B);
21494 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
21495 ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21496 if (ret != BCME_OK) {
21497 WL_ERR(("%s: Failed to set roam_prof %s error = %d\n",
21498 __FUNCTION__, data, ret));
21499 return ret;
21500 }
21501
21502 /* set RSSI weight */
21503 memset(commandp, 0, sizeof(commandp));
21504 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21505 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_A);
21506 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
21507 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21508 if (ret != BCME_OK) {
21509 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
21510 __FUNCTION__, data, ret));
21511 return ret;
21512 }
21513
21514 memset(commandp, 0, sizeof(commandp));
21515 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21516 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_B);
21517 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
21518 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21519 if (ret != BCME_OK) {
21520 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
21521 __FUNCTION__, data, ret));
21522 return ret;
21523 }
21524
21525 /* set CU weight */
21526 memset(commandp, 0, sizeof(commandp));
21527 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21528 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_A);
21529 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
21530 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21531 if (ret != BCME_OK) {
21532 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
21533 __FUNCTION__, data, ret));
21534 return ret;
21535 }
21536
21537 memset(commandp, 0, sizeof(commandp));
21538 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21539 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_B);
21540 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
21541 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21542 if (ret != BCME_OK) {
21543 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
21544 __FUNCTION__, data, ret));
21545 return ret;
21546 }
21547
21548 /* set RSSI table */
21549 memset(commandp, 0, sizeof(commandp));
21550 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21551 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_A);
21552 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
21553 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21554 if (ret != BCME_OK) {
21555 WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
21556 __FUNCTION__, data, ret));
21557 return ret;
21558 }
21559
21560 memset(commandp, 0, sizeof(commandp));
21561 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21562 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_B);
21563 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
21564 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21565 if (ret != BCME_OK) {
21566 WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
21567 __FUNCTION__, data, ret));
21568 return ret;
21569 }
21570
21571 /* set CU table */
21572 memset(commandp, 0, sizeof(commandp));
21573 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21574 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_A);
21575 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
21576 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21577 if (ret != BCME_OK) {
21578 WL_ERR(("%s: Failed to set CU table %s error = %d\n",
21579 __FUNCTION__, data, ret));
21580 return ret;
21581 }
21582
21583 memset(commandp, 0, sizeof(commandp));
21584 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
21585 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_B);
21586 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
21587 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
21588 if (ret != BCME_OK) {
21589 WL_ERR(("%s: Failed to set CU table %s error = %d\n",
21590 __FUNCTION__, data, ret));
21591 return ret;
21592 }
21593
21594 return ret;
21595 }
21596
21597 s32
21598 wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
21599 {
21600 uint i = 0;
21601 long int rssi_lower, roam_trigger;
21602 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21603 wl_roam_prof_band_v2_t *rp;
21604 int err = -EINVAL, bytes_written = 0;
21605 size_t len = strlen(data);
21606 int rp_len = 0;
21607 u8 ioctl_buf[WLC_IOCTL_MEDLEN];
21608
21609 data[len] = '\0';
21610 rp = (wl_roam_prof_band_v2_t *)MALLOCZ(cfg->osh, sizeof(*rp)
21611 * WL_MAX_ROAM_PROF_BRACKETS);
21612 if (unlikely(!rp)) {
21613 WL_ERR(("%s: failed to allocate memory\n", __func__));
21614 err = -ENOMEM;
21615 goto exit;
21616 }
21617 rp->ver = WL_MAX_ROAM_PROF_VER;
21618 if (*data && (!strncmp(data, "b", 1))) {
21619 rp->band = WLC_BAND_2G;
21620 } else if (*data && (!strncmp(data, "a", 1))) {
21621 rp->band = WLC_BAND_5G;
21622 } else {
21623 err = snprintf(command, total_len, "Missing band\n");
21624 goto exit;
21625 }
21626 data++;
21627 rp->len = 0;
21628 /* Getting roam profile from fw */
21629 if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
21630 ioctl_buf, sizeof(ioctl_buf), NULL))) {
21631 WL_ERR(("Getting roam_profile failed with err=%d \n", err));
21632 goto exit;
21633 }
21634 memcpy(rp, ioctl_buf, sizeof(*rp) * WL_MAX_ROAM_PROF_BRACKETS);
21635 /* roam_prof version get */
21636 if (rp->ver != WL_MAX_ROAM_PROF_VER) {
21637 WL_ERR(("bad version (=%d) in return data\n", rp->ver));
21638 err = -EINVAL;
21639 goto exit;
21640 }
21641 if ((rp->len % sizeof(wl_roam_prof_v2_t)) != 0) {
21642 WL_ERR(("bad length (=%d) in return data\n", rp->len));
21643 err = -EINVAL;
21644 goto exit;
21645 }
21646
21647 if (!*data) {
21648 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
21649 /* printing contents of roam profile data from fw and exits
21650 * if code hits any of one of the below condtion. If remaining
21651 * length of buffer is less than roam profile size or
21652 * if there is no valid entry.
21653 */
21654 if (((i * sizeof(wl_roam_prof_v2_t)) > rp->len) ||
21655 (rp->roam_prof[i].fullscan_period == 0)) {
21656 break;
21657 }
21658 bytes_written += snprintf(command+bytes_written,
21659 total_len - bytes_written,
21660 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)\n",
21661 rp->roam_prof[i].roam_trigger, rp->roam_prof[i].rssi_lower,
21662 rp->roam_prof[i].channel_usage,
21663 rp->roam_prof[i].cu_avg_calc_dur);
21664 }
21665 err = bytes_written;
21666 goto exit;
21667 } else {
21668 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
21669 /* reading contents of roam profile data from fw and exits
21670 * if code hits any of one of the below condtion, If remaining
21671 * length of buffer is less than roam profile size or if there
21672 * is no valid entry.
21673 */
21674 if (((i * sizeof(wl_roam_prof_v2_t)) > rp->len) ||
21675 (rp->roam_prof[i].fullscan_period == 0)) {
21676 break;
21677 }
21678 }
21679 /* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
21680 if (i != 2) {
21681 WL_ERR(("FW must have 2 rows to fill roam_prof\n"));
21682 err = -EINVAL;
21683 goto exit;
21684 }
21685 /* setting roam profile to fw */
21686 data++;
21687 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
21688 roam_trigger = simple_strtol(data, &data, 10);
21689 if (roam_trigger >= 0) {
21690 WL_ERR(("roam trigger[%d] value must be negative\n", i));
21691 err = -EINVAL;
21692 goto exit;
21693 }
21694 rp->roam_prof[i].roam_trigger = roam_trigger;
21695 data++;
21696 rssi_lower = simple_strtol(data, &data, 10);
21697 if (rssi_lower >= 0) {
21698 WL_ERR(("rssi lower[%d] value must be negative\n", i));
21699 err = -EINVAL;
21700 goto exit;
21701 }
21702 rp->roam_prof[i].rssi_lower = rssi_lower;
21703 data++;
21704 rp->roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
21705 data++;
21706 rp->roam_prof[i].cu_avg_calc_dur = simple_strtol(data, &data, 10);
21707
21708 rp_len += sizeof(wl_roam_prof_v2_t);
21709
21710 if (*data == '\0') {
21711 break;
21712 }
21713 data++;
21714 }
21715 if (i != 1) {
21716 WL_ERR(("Only two roam_prof rows supported.\n"));
21717 err = -EINVAL;
21718 goto exit;
21719 }
21720 rp->len = rp_len;
21721 if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
21722 sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
21723 &cfg->ioctl_buf_sync)) < 0) {
21724 WL_ERR(("seting roam_profile failed with err %d\n", err));
21725 }
21726 }
21727 exit:
21728 if (rp) {
21729 MFREE(cfg->osh, rp, sizeof(*rp) * WL_MAX_ROAM_PROF_BRACKETS);
21730 }
21731 return err;
21732 }
21733
21734 int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
21735 char *command, int total_len)
21736 {
21737 int bytes_written = 0, err = -EINVAL, argc = 0;
21738 char rssi[BUFSZN], band[BUFSZN], weight[BUFSZN];
21739 char *endptr = NULL;
21740 wnm_bss_select_weight_cfg_t *bwcfg;
21741 u8 ioctl_buf[WLC_IOCTL_SMLEN];
21742 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21743
21744 bwcfg = (wnm_bss_select_weight_cfg_t *)MALLOCZ(cfg->osh, sizeof(*bwcfg));
21745 if (unlikely(!bwcfg)) {
21746 WL_ERR(("%s: failed to allocate memory\n", __func__));
21747 err = -ENOMEM;
21748 goto exit;
21749 }
21750 bwcfg->version = WNM_BSSLOAD_MONITOR_VERSION;
21751 bwcfg->type = 0;
21752 bwcfg->weight = 0;
21753
21754 argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight);
21755
21756 if (!strcasecmp(rssi, "rssi"))
21757 bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
21758 else if (!strcasecmp(rssi, "cu"))
21759 bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
21760 else {
21761 /* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu> <band> <weight> */
21762 WL_ERR(("%s: Command usage error\n", __func__));
21763 goto exit;
21764 }
21765
21766 if (!strcasecmp(band, "a"))
21767 bwcfg->band = WLC_BAND_5G;
21768 else if (!strcasecmp(band, "b"))
21769 bwcfg->band = WLC_BAND_2G;
21770 else if (!strcasecmp(band, "all"))
21771 bwcfg->band = WLC_BAND_ALL;
21772 else {
21773 WL_ERR(("%s: Command usage error\n", __func__));
21774 goto exit;
21775 }
21776
21777 if (argc == 2) {
21778 /* If there is no data after band, getting wnm_bss_select_weight from fw */
21779 if (bwcfg->band == WLC_BAND_ALL) {
21780 WL_ERR(("band option \"all\" is for set only, not get\n"));
21781 goto exit;
21782 }
21783 if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
21784 sizeof(*bwcfg),
21785 ioctl_buf, sizeof(ioctl_buf), NULL))) {
21786 WL_ERR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
21787 goto exit;
21788 }
21789 memcpy(bwcfg, ioctl_buf, sizeof(*bwcfg));
21790 bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
21791 (bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU",
21792 (bwcfg->band == WLC_BAND_2G) ? "2G" : "5G", bwcfg->weight);
21793 err = bytes_written;
21794 goto exit;
21795 } else {
21796 /* if weight is non integer returns command usage error */
21797 bwcfg->weight = simple_strtol(weight, &endptr, 0);
21798 if (*endptr != '\0') {
21799 WL_ERR(("%s: Command usage error", __func__));
21800 goto exit;
21801 }
21802 /* setting weight for iovar wnm_bss_select_weight to fw */
21803 if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
21804 sizeof(*bwcfg),
21805 ioctl_buf, sizeof(ioctl_buf), NULL))) {
21806 WL_ERR(("Getting wnm_bss_select_weight failed with err=%d\n", err));
21807 }
21808 }
21809 exit:
21810 if (bwcfg) {
21811 MFREE(cfg->osh, bwcfg, sizeof(*bwcfg));
21812 }
21813 return err;
21814 }
21815
21816 /* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
21817 #define WBTEXT_TUPLE_MIN_LEN_CHECK 5
21818
21819 int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
21820 char *command, int total_len)
21821 {
21822 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21823 int bytes_written = 0, err = -EINVAL;
21824 char rssi[BUFSZN], band[BUFSZN];
21825 int btcfg_len = 0, i = 0, parsed_len = 0;
21826 wnm_bss_select_factor_cfg_t *btcfg;
21827 size_t slen = strlen(data);
21828 char *start_addr = NULL;
21829 u8 ioctl_buf[WLC_IOCTL_SMLEN];
21830
21831 data[slen] = '\0';
21832 btcfg = (wnm_bss_select_factor_cfg_t *)MALLOCZ(cfg->osh,
21833 (sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
21834 if (unlikely(!btcfg)) {
21835 WL_ERR(("%s: failed to allocate memory\n", __func__));
21836 err = -ENOMEM;
21837 goto exit;
21838 }
21839
21840 btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
21841 btcfg->band = WLC_BAND_AUTO;
21842 btcfg->type = 0;
21843 btcfg->count = 0;
21844
21845 sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band);
21846
21847 if (!strcasecmp(rssi, "rssi")) {
21848 btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
21849 }
21850 else if (!strcasecmp(rssi, "cu")) {
21851 btcfg->type = WNM_BSS_SELECT_TYPE_CU;
21852 }
21853 else {
21854 WL_ERR(("%s: Command usage error\n", __func__));
21855 goto exit;
21856 }
21857
21858 if (!strcasecmp(band, "a")) {
21859 btcfg->band = WLC_BAND_5G;
21860 }
21861 else if (!strcasecmp(band, "b")) {
21862 btcfg->band = WLC_BAND_2G;
21863 }
21864 else if (!strcasecmp(band, "all")) {
21865 btcfg->band = WLC_BAND_ALL;
21866 }
21867 else {
21868 WL_ERR(("%s: Command usage, Wrong band\n", __func__));
21869 goto exit;
21870 }
21871
21872 if ((slen - 1) == (strlen(rssi) + strlen(band))) {
21873 /* Getting factor table using iovar 'wnm_bss_select_table' from fw */
21874 if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
21875 sizeof(*btcfg),
21876 ioctl_buf, sizeof(ioctl_buf), NULL))) {
21877 WL_ERR(("Getting wnm_bss_select_table failed with err=%d \n", err));
21878 goto exit;
21879 }
21880 memcpy(btcfg, ioctl_buf, sizeof(*btcfg));
21881 memcpy(btcfg, ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
21882
21883 bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
21884 "No of entries in table: %d\n", btcfg->count);
21885 bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
21886 "%s factor table\n",
21887 (btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
21888 bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
21889 "low\thigh\tfactor\n");
21890 for (i = 0; i <= btcfg->count-1; i++) {
21891 bytes_written += snprintf(command + bytes_written,
21892 total_len - bytes_written, "%d\t%d\t%d\n", btcfg->params[i].low,
21893 btcfg->params[i].high, btcfg->params[i].factor);
21894 }
21895 err = bytes_written;
21896 goto exit;
21897 } else {
21898 memset(btcfg->params, 0, sizeof(wnm_bss_select_factor_params_t)
21899 * WL_FACTOR_TABLE_MAX_LIMIT);
21900 data += (strlen(rssi) + strlen(band) + 2);
21901 start_addr = data;
21902 slen = slen - (strlen(rssi) + strlen(band) + 2);
21903 for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
21904 if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
21905 btcfg->params[i].low = simple_strtol(data, &data, 10);
21906 data++;
21907 btcfg->params[i].high = simple_strtol(data, &data, 10);
21908 data++;
21909 btcfg->params[i].factor = simple_strtol(data, &data, 10);
21910 btcfg->count++;
21911 if (*data == '\0') {
21912 break;
21913 }
21914 data++;
21915 parsed_len = data - start_addr;
21916 } else {
21917 WL_ERR(("%s:Command usage:less no of args\n", __func__));
21918 goto exit;
21919 }
21920 }
21921 btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
21922 if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
21923 cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
21924 WL_ERR(("seting wnm_bss_select_table failed with err %d\n", err));
21925 goto exit;
21926 }
21927 }
21928 exit:
21929 if (btcfg) {
21930 MFREE(cfg->osh, btcfg,
21931 (sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
21932 }
21933 return err;
21934 }
21935
21936 s32
21937 wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
21938 {
21939 uint i = 0;
21940 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21941 int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
21942 char delta[BUFSZN], band[BUFSZN], *endptr = NULL;
21943 wl_roam_prof_band_v2_t *rp;
21944 u8 ioctl_buf[WLC_IOCTL_MEDLEN];
21945
21946 rp = (wl_roam_prof_band_v2_t *)MALLOCZ(cfg->osh, sizeof(*rp)
21947 * WL_MAX_ROAM_PROF_BRACKETS);
21948 if (unlikely(!rp)) {
21949 WL_ERR(("%s: failed to allocate memory\n", __func__));
21950 err = -ENOMEM;
21951 goto exit;
21952 }
21953
21954 argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta);
21955 if (!strcasecmp(band, "a"))
21956 rp->band = WLC_BAND_5G;
21957 else if (!strcasecmp(band, "b"))
21958 rp->band = WLC_BAND_2G;
21959 else {
21960 WL_ERR(("%s: Missing band\n", __func__));
21961 goto exit;
21962 }
21963 /* Getting roam profile from fw */
21964 if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
21965 ioctl_buf, sizeof(ioctl_buf), NULL))) {
21966 WL_ERR(("Getting roam_profile failed with err=%d \n", err));
21967 goto exit;
21968 }
21969 memcpy(rp, ioctl_buf, sizeof(wl_roam_prof_band_v2_t));
21970 if (rp->ver != WL_MAX_ROAM_PROF_VER) {
21971 WL_ERR(("bad version (=%d) in return data\n", rp->ver));
21972 err = -EINVAL;
21973 goto exit;
21974 }
21975 if ((rp->len % sizeof(wl_roam_prof_v2_t)) != 0) {
21976 WL_ERR(("bad length (=%d) in return data\n", rp->len));
21977 err = -EINVAL;
21978 goto exit;
21979 }
21980
21981 if (argc == 2) {
21982 /* if delta is non integer returns command usage error */
21983 val = simple_strtol(delta, &endptr, 0);
21984 if (*endptr != '\0') {
21985 WL_ERR(("%s: Command usage error", __func__));
21986 goto exit;
21987 }
21988 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
21989 /*
21990 * Checking contents of roam profile data from fw and exits
21991 * if code hits below condtion. If remaining length of buffer is
21992 * less than roam profile size or if there is no valid entry.
21993 */
21994 if (((i * sizeof(wl_roam_prof_v2_t)) > rp->len) ||
21995 (rp->roam_prof[i].fullscan_period == 0)) {
21996 break;
21997 }
21998 if (rp->roam_prof[i].channel_usage != 0) {
21999 rp->roam_prof[i].roam_delta = val;
22000 }
22001 len += sizeof(wl_roam_prof_v2_t);
22002 }
22003 }
22004 else {
22005 if (rp->roam_prof[i].channel_usage != 0) {
22006 bytes_written = snprintf(command, total_len,
22007 "%s Delta %d\n", (rp->band == WLC_BAND_2G) ? "2G" : "5G",
22008 rp->roam_prof[0].roam_delta);
22009 }
22010 err = bytes_written;
22011 goto exit;
22012 }
22013 rp->len = len;
22014 if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
22015 sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
22016 &cfg->ioctl_buf_sync)) < 0) {
22017 WL_ERR(("seting roam_profile failed with err %d\n", err));
22018 }
22019 exit :
22020 if (rp) {
22021 MFREE(cfg->osh, rp, sizeof(*rp)
22022 * WL_MAX_ROAM_PROF_BRACKETS);
22023 }
22024 return err;
22025 }
22026 #endif /* WBTEXT */
22027
22028 int wl_cfg80211_scan_stop(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev)
22029 {
22030 struct net_device *ndev = NULL;
22031 unsigned long flags;
22032 int clear_flag = 0;
22033 int ret = 0;
22034
22035 WL_TRACE(("Enter\n"));
22036
22037 if (!cfg || !cfgdev)
22038 return -EINVAL;
22039
22040 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22041
22042 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
22043 #ifdef WL_CFG80211_P2P_DEV_IF
22044 if (cfg->scan_request && cfg->scan_request->wdev == cfgdev) {
22045 #else
22046 if (cfg->scan_request && cfg->scan_request->dev == cfgdev) {
22047 #endif // endif
22048 wl_notify_scan_done(cfg, true);
22049 cfg->scan_request = NULL;
22050 clear_flag = 1;
22051 }
22052 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
22053
22054 if (clear_flag)
22055 wl_clr_drv_status(cfg, SCANNING, ndev);
22056
22057 return ret;
22058 }
22059
22060 bool wl_cfg80211_is_concurrent_mode(struct net_device *dev)
22061 {
22062 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22063 if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
22064 return true;
22065 } else {
22066 return false;
22067 }
22068 }
22069
22070 void* wl_cfg80211_get_dhdp(struct net_device *dev)
22071 {
22072 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22073
22074 return cfg->pub;
22075 }
22076
22077 bool wl_cfg80211_is_p2p_active(struct net_device *dev)
22078 {
22079 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22080 return (cfg && cfg->p2p);
22081 }
22082
22083 bool wl_cfg80211_is_roam_offload(struct net_device * dev)
22084 {
22085 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22086 return (cfg && cfg->roam_offload);
22087 }
22088
22089 bool wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev, const wl_event_msg_t *e,
22090 int ifidx)
22091 {
22092 u8 *curbssid = NULL;
22093 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22094
22095 if (!cfg) {
22096 return NULL;
22097 }
22098 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
22099
22100 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
22101 return true;
22102 }
22103 return false;
22104 }
22105
22106 static void wl_cfg80211_work_handler(struct work_struct * work)
22107 {
22108 struct bcm_cfg80211 *cfg = NULL;
22109 struct net_info *iter, *next;
22110 s32 err = BCME_OK;
22111 s32 pm = PM_FAST;
22112 BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
22113 WL_DBG(("Enter \n"));
22114 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
22115 4 && __GNUC_MINOR__ >= 6))
22116 _Pragma("GCC diagnostic push")
22117 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
22118 #endif // endif
22119 for_each_ndev(cfg, iter, next) {
22120 /* p2p discovery iface ndev could be null */
22121 if (iter->ndev) {
22122 if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
22123 (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
22124 wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
22125 continue;
22126 if (iter->ndev) {
22127 if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM,
22128 &pm, sizeof(pm))) != 0) {
22129 if (err == -ENODEV)
22130 WL_DBG(("%s:netdev not ready\n",
22131 iter->ndev->name));
22132 else
22133 WL_ERR(("%s:error (%d)\n",
22134 iter->ndev->name, err));
22135 } else
22136 wl_cfg80211_update_power_mode(iter->ndev);
22137 }
22138 }
22139 }
22140 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
22141 4 && __GNUC_MINOR__ >= 6))
22142 _Pragma("GCC diagnostic pop")
22143 #endif // endif
22144 DHD_PM_WAKE_UNLOCK(cfg->pub);
22145 }
22146
22147 u8
22148 wl_get_action_category(void *frame, u32 frame_len)
22149 {
22150 u8 category;
22151 u8 *ptr = (u8 *)frame;
22152 if (frame == NULL)
22153 return DOT11_ACTION_CAT_ERR_MASK;
22154 if (frame_len < DOT11_ACTION_HDR_LEN)
22155 return DOT11_ACTION_CAT_ERR_MASK;
22156 category = ptr[DOT11_ACTION_CAT_OFF];
22157 WL_DBG(("Action Category: %d\n", category));
22158 return category;
22159 }
22160
22161 int
22162 wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
22163 {
22164 u8 *ptr = (u8 *)frame;
22165 if (frame == NULL || ret_action == NULL)
22166 return BCME_ERROR;
22167 if (frame_len < DOT11_ACTION_HDR_LEN)
22168 return BCME_ERROR;
22169 if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
22170 return BCME_ERROR;
22171 *ret_action = ptr[DOT11_ACTION_ACT_OFF];
22172 WL_DBG(("Public Action : %d\n", *ret_action));
22173 return BCME_OK;
22174 }
22175
22176 #ifdef WLFBT
22177 int
22178 wl_cfg80211_get_fbt_key(struct net_device *dev, uint8 *key, int total_len)
22179 {
22180 struct bcm_cfg80211 * cfg = wl_get_cfg(dev);
22181 int bytes_written = -1;
22182
22183 if (total_len < FBT_KEYLEN) {
22184 WL_ERR(("%s: Insufficient buffer \n", __FUNCTION__));
22185 goto end;
22186 }
22187 if (cfg) {
22188 memcpy(key, cfg->fbt_key, FBT_KEYLEN);
22189 bytes_written = FBT_KEYLEN;
22190 } else {
22191 memset(key, 0, FBT_KEYLEN);
22192 WL_ERR(("%s: Failed to copy KCK and KEK \n", __FUNCTION__));
22193 }
22194 prhex("KCK, KEK", (uchar *)key, FBT_KEYLEN);
22195 end:
22196 return bytes_written;
22197 }
22198 #endif /* WLFBT */
22199
22200 static int
22201 wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
22202 const struct ether_addr *bssid)
22203 {
22204 s32 err;
22205 wl_event_msg_t e;
22206
22207 bzero(&e, sizeof(e));
22208 e.event_type = cpu_to_be32(WLC_E_ROAM);
22209 memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
22210 /* trigger the roam event handler */
22211 err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
22212
22213 return err;
22214 }
22215
22216 static s32
22217 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
22218 struct parsed_vndr_ies *vndr_ies)
22219 {
22220 s32 err = BCME_OK;
22221 const vndr_ie_t *vndrie;
22222 const bcm_tlv_t *ie;
22223 struct parsed_vndr_ie_info *parsed_info;
22224 u32 count = 0;
22225 s32 remained_len;
22226
22227 remained_len = (s32)len;
22228 memset(vndr_ies, 0, sizeof(*vndr_ies));
22229
22230 WL_DBG(("---> len %d\n", len));
22231 ie = (const bcm_tlv_t *) parse;
22232 if (!bcm_valid_tlv(ie, remained_len))
22233 ie = NULL;
22234 while (ie) {
22235 if (count >= MAX_VNDR_IE_NUMBER)
22236 break;
22237 if (ie->id == DOT11_MNG_VS_ID) {
22238 vndrie = (const vndr_ie_t *) ie;
22239 /* len should be bigger than OUI length + one data length at least */
22240 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
22241 WL_ERR(("%s: invalid vndr ie. length is too small %d\n",
22242 __FUNCTION__, vndrie->len));
22243 goto end;
22244 }
22245 /* if wpa or wme ie, do not add ie */
22246 if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
22247 ((vndrie->data[0] == WPA_OUI_TYPE) ||
22248 (vndrie->data[0] == WME_OUI_TYPE))) {
22249 CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
22250 goto end;
22251 }
22252
22253 parsed_info = &vndr_ies->ie_info[count++];
22254
22255 /* save vndr ie information */
22256 parsed_info->ie_ptr = (const char *)vndrie;
22257 parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
22258 memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
22259 vndr_ies->count = count;
22260
22261 WL_DBG(("\t ** OUI "MACOUIDBG", type 0x%02x len:%d\n",
22262 MACOUI2STRDBG(parsed_info->vndrie.oui),
22263 parsed_info->vndrie.data[0], parsed_info->ie_len));
22264 }
22265 end:
22266 ie = bcm_next_tlv(ie, &remained_len);
22267 }
22268 return err;
22269 }
22270
22271 static bool
22272 wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info *vndr_info)
22273 {
22274 int i = 0;
22275
22276 while (exclude_vndr_oui_list[i]) {
22277 if (!memcmp(vndr_info->vndrie.oui,
22278 exclude_vndr_oui_list[i],
22279 DOT11_OUI_LEN)) {
22280 return TRUE;
22281 }
22282 i++;
22283 }
22284
22285 return FALSE;
22286 }
22287
22288 static bool
22289 wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 *cfg,
22290 struct parsed_vndr_ie_info *vndr_info)
22291 {
22292 wl_vndr_oui_entry_t *oui_entry = NULL;
22293 unsigned long flags;
22294
22295 spin_lock_irqsave(&cfg->vndr_oui_sync, flags);
22296 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22297 #pragma GCC diagnostic push
22298 #pragma GCC diagnostic ignored "-Wcast-qual"
22299 #endif // endif
22300 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
22301 if (!memcmp(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN)) {
22302 spin_unlock_irqrestore(&cfg->vndr_oui_sync, flags);
22303 return TRUE;
22304 }
22305 }
22306 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22307 #pragma GCC diagnostic pop
22308 #endif // endif
22309 spin_unlock_irqrestore(&cfg->vndr_oui_sync, flags);
22310 return FALSE;
22311 }
22312
22313 static bool
22314 wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 *cfg,
22315 struct parsed_vndr_ie_info *vndr_info)
22316 {
22317 wl_vndr_oui_entry_t *oui_entry = NULL;
22318 unsigned long flags;
22319
22320 oui_entry = (wl_vndr_oui_entry_t *)MALLOC(cfg->osh, sizeof(*oui_entry));
22321 if (oui_entry == NULL) {
22322 WL_ERR(("alloc failed\n"));
22323 return FALSE;
22324 }
22325
22326 memcpy(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN);
22327
22328 INIT_LIST_HEAD(&oui_entry->list);
22329 spin_lock_irqsave(&cfg->vndr_oui_sync, flags);
22330 list_add_tail(&oui_entry->list, &cfg->vndr_oui_list);
22331 spin_unlock_irqrestore(&cfg->vndr_oui_sync, flags);
22332
22333 return TRUE;
22334 }
22335
22336 static void
22337 wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg)
22338 {
22339 wl_vndr_oui_entry_t *oui_entry = NULL;
22340 unsigned long flags;
22341
22342 spin_lock_irqsave(&cfg->vndr_oui_sync, flags);
22343 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22344 #pragma GCC diagnostic push
22345 #pragma GCC diagnostic ignored "-Wcast-qual"
22346 #endif // endif
22347 while (!list_empty(&cfg->vndr_oui_list)) {
22348 oui_entry = list_entry(cfg->vndr_oui_list.next, wl_vndr_oui_entry_t, list);
22349 if (oui_entry) {
22350 list_del(&oui_entry->list);
22351 MFREE(cfg->osh, oui_entry, sizeof(*oui_entry));
22352 }
22353 }
22354 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22355 #pragma GCC diagnostic pop
22356 #endif // endif
22357 spin_unlock_irqrestore(&cfg->vndr_oui_sync, flags);
22358 }
22359
22360 static int
22361 wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
22362 char *vndr_oui, u32 vndr_oui_len)
22363 {
22364 int i;
22365 int vndr_oui_num = 0;
22366
22367 struct wl_connect_info *conn_info = wl_to_conn(cfg);
22368 wl_vndr_oui_entry_t *oui_entry = NULL;
22369 struct parsed_vndr_ie_info *vndr_info;
22370 struct parsed_vndr_ies vndr_ies;
22371
22372 char *pos = vndr_oui;
22373 u32 remained_buf_len = vndr_oui_len;
22374 unsigned long flags;
22375
22376 if (!conn_info->resp_ie_len) {
22377 return BCME_ERROR;
22378 }
22379
22380 wl_vndr_ies_clear_vendor_oui_list(cfg);
22381
22382 if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
22383 conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
22384 for (i = 0; i < vndr_ies.count; i++) {
22385 vndr_info = &vndr_ies.ie_info[i];
22386 if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
22387 continue;
22388 }
22389
22390 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
22391 continue;
22392 }
22393
22394 wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
22395 vndr_oui_num++;
22396 }
22397 }
22398
22399 if (vndr_oui) {
22400 spin_lock_irqsave(&cfg->vndr_oui_sync, flags);
22401 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22402 #pragma GCC diagnostic push
22403 #pragma GCC diagnostic ignored "-Wcast-qual"
22404 #endif // endif
22405 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
22406 if (remained_buf_len < VNDR_OUI_STR_LEN) {
22407 spin_unlock_irqrestore(&cfg->vndr_oui_sync, flags);
22408 return BCME_ERROR;
22409 }
22410 pos += snprintf(pos, VNDR_OUI_STR_LEN, "%02X-%02X-%02X ",
22411 oui_entry->oui[0], oui_entry->oui[1], oui_entry->oui[2]);
22412 remained_buf_len -= VNDR_OUI_STR_LEN;
22413 }
22414 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22415 #pragma GCC diagnostic pop
22416 #endif // endif
22417 spin_unlock_irqrestore(&cfg->vndr_oui_sync, flags);
22418 }
22419
22420 return vndr_oui_num;
22421 }
22422
22423 void
22424 wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 *cfg)
22425 {
22426 /* Legacy P2P used to store it in primary dev cache */
22427 s32 index;
22428 struct net_device *ndev;
22429 s32 bssidx;
22430 s32 ret;
22431 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
22432 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
22433
22434 WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
22435 /* certain vendors uses p2p0 interface in addition to
22436 * the dedicated p2p interface supported by the linux
22437 * kernel.
22438 */
22439 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
22440 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
22441 if (bssidx == WL_INVALID) {
22442 WL_DBG(("No discovery I/F available. Do nothing.\n"));
22443 return;
22444 }
22445
22446 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
22447 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
22448 bssidx, vndrie_flag[index], NULL, 0)) < 0) {
22449 if (ret != BCME_NOTFOUND) {
22450 WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret));
22451 }
22452 }
22453 }
22454
22455 if (cfg->p2p_wdev && (ndev->ieee80211_ptr != cfg->p2p_wdev)) {
22456 /* clear IEs for dedicated p2p interface */
22457 wl_cfg80211_clear_per_bss_ies(cfg, cfg->p2p_wdev);
22458 }
22459 }
22460
22461 s32
22462 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
22463 {
22464 s32 index;
22465 s32 ret;
22466 struct net_info *netinfo;
22467 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
22468 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
22469
22470 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
22471 if (!netinfo || !netinfo->wdev) {
22472 WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
22473 return -1;
22474 }
22475
22476 WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo->bssidx));
22477 /* Clear the IEs set in the firmware so that host is in sync with firmware */
22478 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
22479 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
22480 netinfo->bssidx, vndrie_flag[index], NULL, 0)) < 0)
22481 if (ret != BCME_NOTFOUND) {
22482 WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
22483 }
22484 }
22485
22486 return 0;
22487 }
22488
22489 s32
22490 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
22491 {
22492 struct net_info *iter, *next;
22493
22494 WL_DBG(("clear management vendor IEs \n"));
22495 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
22496 4 && __GNUC_MINOR__ >= 6))
22497 _Pragma("GCC diagnostic push")
22498 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
22499 #endif // endif
22500 for_each_ndev(cfg, iter, next) {
22501 wl_cfg80211_clear_per_bss_ies(cfg, iter->wdev);
22502 }
22503 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
22504 4 && __GNUC_MINOR__ >= 6))
22505 _Pragma("GCC diagnostic pop")
22506 #endif // endif
22507 return 0;
22508 }
22509
22510 #define WL_VNDR_IE_MAXLEN 2048
22511 static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
22512 int
22513 wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
22514 s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
22515 {
22516 struct net_device *ndev = NULL;
22517 s32 ret = BCME_OK;
22518 u8 *curr_ie_buf = NULL;
22519 u8 *mgmt_ie_buf = NULL;
22520 u32 mgmt_ie_buf_len = 0;
22521 u32 *mgmt_ie_len = 0;
22522 u32 del_add_ie_buf_len = 0;
22523 u32 total_ie_buf_len = 0;
22524 u32 parsed_ie_buf_len = 0;
22525 struct parsed_vndr_ies old_vndr_ies;
22526 struct parsed_vndr_ies new_vndr_ies;
22527 s32 i;
22528 u8 *ptr;
22529 s32 remained_buf_len;
22530 wl_bss_vndr_ies_t *ies = NULL;
22531 struct net_info *netinfo;
22532 struct wireless_dev *wdev;
22533
22534 if (!cfgdev) {
22535 WL_ERR(("cfgdev is NULL\n"));
22536 return -EINVAL;
22537 }
22538
22539 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22540 wdev = cfgdev_to_wdev(cfgdev);
22541
22542 if (bssidx > WL_MAX_IFS) {
22543 WL_ERR(("bssidx > supported concurrent Ifaces \n"));
22544 return -EINVAL;
22545 }
22546
22547 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
22548 if (!netinfo) {
22549 WL_ERR(("net_info ptr is NULL \n"));
22550 return -EINVAL;
22551 }
22552
22553 /* Clear the global buffer */
22554 memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf));
22555 curr_ie_buf = g_mgmt_ie_buf;
22556 ies = &netinfo->bss.ies;
22557
22558 WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d wdev:%p\n",
22559 pktflag, bssidx, vndr_ie_len, wdev));
22560
22561 switch (pktflag) {
22562 case VNDR_IE_PRBRSP_FLAG :
22563 mgmt_ie_buf = ies->probe_res_ie;
22564 mgmt_ie_len = &ies->probe_res_ie_len;
22565 mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
22566 break;
22567 case VNDR_IE_ASSOCRSP_FLAG :
22568 mgmt_ie_buf = ies->assoc_res_ie;
22569 mgmt_ie_len = &ies->assoc_res_ie_len;
22570 mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
22571 break;
22572 case VNDR_IE_BEACON_FLAG :
22573 mgmt_ie_buf = ies->beacon_ie;
22574 mgmt_ie_len = &ies->beacon_ie_len;
22575 mgmt_ie_buf_len = sizeof(ies->beacon_ie);
22576 break;
22577 case VNDR_IE_PRBREQ_FLAG :
22578 mgmt_ie_buf = ies->probe_req_ie;
22579 mgmt_ie_len = &ies->probe_req_ie_len;
22580 mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
22581 break;
22582 case VNDR_IE_ASSOCREQ_FLAG :
22583 mgmt_ie_buf = ies->assoc_req_ie;
22584 mgmt_ie_len = &ies->assoc_req_ie_len;
22585 mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
22586 break;
22587 default:
22588 mgmt_ie_buf = NULL;
22589 mgmt_ie_len = NULL;
22590 WL_ERR(("not suitable packet type (%d)\n", pktflag));
22591 return BCME_ERROR;
22592 }
22593
22594 if (vndr_ie_len > mgmt_ie_buf_len) {
22595 WL_ERR(("extra IE size too big\n"));
22596 ret = -ENOMEM;
22597 } else {
22598 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
22599 if (vndr_ie && vndr_ie_len && curr_ie_buf) {
22600 ptr = curr_ie_buf;
22601
22602 if ((ret = wl_cfg80211_parse_vndr_ies((const u8 *)vndr_ie,
22603 vndr_ie_len, &new_vndr_ies)) < 0) {
22604 WL_ERR(("parse vndr ie failed \n"));
22605 goto exit;
22606 }
22607
22608 for (i = 0; i < new_vndr_ies.count; i++) {
22609 struct parsed_vndr_ie_info *vndrie_info =
22610 &new_vndr_ies.ie_info[i];
22611
22612 if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
22613 WL_ERR(("IE size is too big (%d > %d)\n",
22614 parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
22615 ret = -EINVAL;
22616 goto exit;
22617 }
22618
22619 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
22620 vndrie_info->ie_len);
22621 parsed_ie_buf_len += vndrie_info->ie_len;
22622 }
22623 }
22624
22625 if (mgmt_ie_buf != NULL) {
22626 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
22627 (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
22628 WL_DBG(("Previous mgmt IE is equals to current IE"));
22629 goto exit;
22630 }
22631
22632 /* parse old vndr_ie */
22633 if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
22634 &old_vndr_ies)) < 0) {
22635 WL_ERR(("parse vndr ie failed \n"));
22636 goto exit;
22637 }
22638 /* make a command to delete old ie */
22639 for (i = 0; i < old_vndr_ies.count; i++) {
22640 struct parsed_vndr_ie_info *vndrie_info =
22641 &old_vndr_ies.ie_info[i];
22642
22643 WL_DBG(("DELETED ID : %d, Len: %d , OUI:"MACOUIDBG"\n",
22644 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
22645 MACOUI2STRDBG(vndrie_info->vndrie.oui)));
22646
22647 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
22648 pktflag, vndrie_info->vndrie.oui,
22649 vndrie_info->vndrie.id,
22650 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
22651 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
22652 "del");
22653
22654 curr_ie_buf += del_add_ie_buf_len;
22655 total_ie_buf_len += del_add_ie_buf_len;
22656 }
22657 }
22658
22659 *mgmt_ie_len = 0;
22660 /* Add if there is any extra IE */
22661 if (mgmt_ie_buf && parsed_ie_buf_len) {
22662 ptr = mgmt_ie_buf;
22663
22664 remained_buf_len = mgmt_ie_buf_len;
22665
22666 /* make a command to add new ie */
22667 for (i = 0; i < new_vndr_ies.count; i++) {
22668 struct parsed_vndr_ie_info *vndrie_info =
22669 &new_vndr_ies.ie_info[i];
22670
22671 WL_DBG(("ADDED ID : %d, Len: %d(%d), OUI:"MACOUIDBG"\n",
22672 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
22673 vndrie_info->ie_len - 2,
22674 MACOUI2STRDBG(vndrie_info->vndrie.oui)));
22675
22676 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
22677 pktflag, vndrie_info->vndrie.oui,
22678 vndrie_info->vndrie.id,
22679 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
22680 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
22681 "add");
22682
22683 /* verify remained buf size before copy data */
22684 if (remained_buf_len >= vndrie_info->ie_len) {
22685 remained_buf_len -= vndrie_info->ie_len;
22686 } else {
22687 WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
22688 "found vndr ies # = %d(cur %d), remained len %d, "
22689 "cur mgmt_ie_len %d, new ie len = %d\n",
22690 pktflag, new_vndr_ies.count, i, remained_buf_len,
22691 *mgmt_ie_len, vndrie_info->ie_len));
22692 break;
22693 }
22694
22695 /* save the parsed IE in cfg struct */
22696 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
22697 vndrie_info->ie_len);
22698 *mgmt_ie_len += vndrie_info->ie_len;
22699 curr_ie_buf += del_add_ie_buf_len;
22700 total_ie_buf_len += del_add_ie_buf_len;
22701 }
22702 }
22703
22704 if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
22705 ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
22706 total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
22707 bssidx, &cfg->ioctl_buf_sync);
22708 if (ret)
22709 WL_ERR(("vndr ie set error : %d\n", ret));
22710 }
22711 }
22712 exit:
22713
22714 return ret;
22715 }
22716
22717 #ifdef WL_CFG80211_ACL
22718 static int
22719 wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
22720 const struct cfg80211_acl_data *acl)
22721 {
22722 int i;
22723 int ret = 0;
22724 int macnum = 0;
22725 int macmode = MACLIST_MODE_DISABLED;
22726 struct maclist *list;
22727 struct bcm_cfg80211 *cfg = wl_get_cfg(cfgdev);
22728
22729 /* get the MAC filter mode */
22730 if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
22731 macmode = MACLIST_MODE_ALLOW;
22732 } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
22733 acl->n_acl_entries) {
22734 macmode = MACLIST_MODE_DENY;
22735 }
22736
22737 /* if acl == NULL, macmode is still disabled.. */
22738 if (macmode == MACLIST_MODE_DISABLED) {
22739 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0)
22740 WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
22741
22742 return ret;
22743 }
22744
22745 macnum = acl->n_acl_entries;
22746 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
22747 WL_ERR(("%s : invalid number of MAC address entries %d\n",
22748 __FUNCTION__, macnum));
22749 return -1;
22750 }
22751
22752 /* allocate memory for the MAC list */
22753 list = (struct maclist *)MALLOC(cfg->osh, sizeof(int) +
22754 sizeof(struct ether_addr) * macnum);
22755 if (!list) {
22756 WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__));
22757 return -1;
22758 }
22759
22760 /* prepare the MAC list */
22761 list->count = htod32(macnum);
22762 for (i = 0; i < macnum; i++) {
22763 memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN);
22764 }
22765 /* set the list */
22766 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0)
22767 WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
22768
22769 MFREE(cfg->osh, list, sizeof(int) +
22770 sizeof(struct ether_addr) * macnum);
22771
22772 return ret;
22773 }
22774 #endif /* WL_CFG80211_ACL */
22775 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22776 int wl_chspec_chandef(chanspec_t chanspec,
22777 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
22778 struct cfg80211_chan_def *chandef,
22779 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22780 \
22781 0)))
22782 struct chan_info *chaninfo,
22783 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
22784 struct wiphy *wiphy)
22785 {
22786 uint16 freq = 0;
22787 int chan_type = 0;
22788 int channel = 0;
22789 struct ieee80211_channel *chan;
22790
22791 if (!chandef) {
22792 return -1;
22793 }
22794 channel = CHSPEC_CHANNEL(chanspec);
22795
22796 switch (CHSPEC_BW(chanspec)) {
22797 case WL_CHANSPEC_BW_20:
22798 chan_type = NL80211_CHAN_HT20;
22799 break;
22800 case WL_CHANSPEC_BW_40:
22801 {
22802 if (CHSPEC_SB_UPPER(chanspec)) {
22803 channel += CH_10MHZ_APART;
22804 } else {
22805 channel -= CH_10MHZ_APART;
22806 }
22807 }
22808 chan_type = NL80211_CHAN_HT40PLUS;
22809 break;
22810
22811 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22812 case WL_CHANSPEC_BW_80:
22813 case WL_CHANSPEC_BW_8080:
22814 {
22815 uint16 sb = CHSPEC_CTL_SB(chanspec);
22816
22817 if (sb == WL_CHANSPEC_CTL_SB_LL) {
22818 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
22819 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
22820 channel -= CH_10MHZ_APART;
22821 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
22822 channel += CH_10MHZ_APART;
22823 } else {
22824 /* WL_CHANSPEC_CTL_SB_UU */
22825 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
22826 }
22827
22828 if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_LU)
22829 chan_type = NL80211_CHAN_HT40MINUS;
22830 else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU)
22831 chan_type = NL80211_CHAN_HT40PLUS;
22832 }
22833 break;
22834 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22835 default:
22836 chan_type = NL80211_CHAN_HT20;
22837 break;
22838
22839 }
22840
22841 if (CHSPEC_IS5G(chanspec))
22842 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
22843 else
22844 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
22845
22846 chan = ieee80211_get_channel(wiphy, freq);
22847 WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
22848 channel, freq, chan_type, chan));
22849
22850 if (unlikely(!chan)) {
22851 /* fw and cfg80211 channel lists are not in sync */
22852 WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
22853 ASSERT(0);
22854 return -EINVAL;
22855 }
22856
22857 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22858 cfg80211_chandef_create(chandef, chan, chan_type);
22859 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22860 \
22861 0)))
22862 chaninfo->freq = freq;
22863 chaninfo->chan_type = chan_type;
22864 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22865 return 0;
22866 }
22867
22868 void
22869 wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy)
22870 {
22871 u32 freq;
22872 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22873 struct cfg80211_chan_def chandef;
22874 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22875 \
22876 0)))
22877 struct chan_info chaninfo;
22878 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22879
22880 if (!wiphy) {
22881 WL_ERR(("wiphy is null\n"));
22882 return;
22883 }
22884 #if (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0))
22885 /* Channel switch support is only for AP/GO/ADHOC/MESH */
22886 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
22887 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
22888 WL_ERR(("No channel switch notify support for STA/GC\n"));
22889 return;
22890 }
22891 #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
22892 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22893 if (wl_chspec_chandef(chanspec, &chandef, wiphy)) {
22894 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22895 \
22896 0)))
22897 if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) {
22898 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22899
22900 WL_ERR(("chspec_chandef failed\n"));
22901 return;
22902 }
22903 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22904 freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1;
22905 cfg80211_ch_switch_notify(dev, &chandef);
22906 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22907 \
22908 0)))
22909 freq = chan_info.freq;
22910 cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type);
22911 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22912
22913 WL_ERR(("Channel switch notification for freq: %d chanspec: 0x%x\n", freq, chanspec));
22914 return;
22915 }
22916 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
22917
22918 static void
22919 wl_ap_channel_ind(struct bcm_cfg80211 *cfg,
22920 struct net_device *ndev,
22921 chanspec_t chanspec)
22922 {
22923 u32 channel = LCHSPEC_CHANNEL(chanspec);
22924
22925 WL_INFORM_MEM(("(%s) AP channel:%d chspec:0x%x \n",
22926 ndev->name, channel, chanspec));
22927 if (cfg->ap_oper_channel && (cfg->ap_oper_channel != channel)) {
22928 /*
22929 * If cached channel is different from the channel indicated
22930 * by the event, notify user space about the channel switch.
22931 */
22932 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22933 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
22934 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
22935 cfg->ap_oper_channel = channel;
22936 }
22937 }
22938
22939 static s32
22940 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
22941 const wl_event_msg_t *e, void *data)
22942 {
22943 struct net_device *ndev = NULL;
22944 chanspec_t chanspec;
22945
22946 WL_DBG(("Enter\n"));
22947 if (unlikely(e->status)) {
22948 WL_ERR(("status:0x%x \n", e->status));
22949 return -1;
22950 }
22951
22952 if (!data) {
22953 return -EINVAL;
22954 }
22955
22956 if (likely(cfgdev)) {
22957 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22958 chanspec = *((chanspec_t *)data);
22959
22960 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
22961 /* For AP/GO role */
22962 wl_ap_channel_ind(cfg, ndev, chanspec);
22963 }
22964 }
22965
22966 return 0;
22967 }
22968
22969 static s32
22970 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
22971 const wl_event_msg_t *e, void *data)
22972 {
22973 int error = 0;
22974 u32 chanspec = 0;
22975 struct net_device *ndev = NULL;
22976
22977 WL_DBG(("Enter\n"));
22978 if (unlikely(e->status)) {
22979 WL_ERR(("status:0x%x \n", e->status));
22980 return -1;
22981 }
22982
22983 if (likely(cfgdev)) {
22984 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22985 error = wldev_iovar_getint(ndev, "chanspec", &chanspec);
22986 if (unlikely(error)) {
22987 WL_ERR(("Get chanspec error: %d \n", error));
22988 return -1;
22989 }
22990
22991 WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev->name, chanspec));
22992 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
22993 /* For AP/GO role */
22994 wl_ap_channel_ind(cfg, ndev, chanspec);
22995 } else {
22996 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22997 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
22998 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
22999 }
23000
23001 }
23002
23003 return 0;
23004 }
23005
23006 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
23007 {
23008 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
23009 int err;
23010
23011 /* Clear the security settings on the primary Interface */
23012 err = wldev_iovar_setint(dev, "wsec", 0);
23013 if (unlikely(err)) {
23014 WL_ERR(("wsec clear failed \n"));
23015 }
23016 err = wldev_iovar_setint(dev, "auth", 0);
23017 if (unlikely(err)) {
23018 WL_ERR(("auth clear failed \n"));
23019 }
23020 err = wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
23021 if (unlikely(err)) {
23022 WL_ERR(("wpa_auth clear failed \n"));
23023 }
23024 }
23025
23026 #ifdef WL_CFG80211_P2P_DEV_IF
23027 void wl_cfg80211_del_p2p_wdev(struct net_device *dev)
23028 {
23029 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23030 struct wireless_dev *wdev = NULL;
23031
23032 WL_DBG(("Enter \n"));
23033 if (!cfg) {
23034 WL_ERR(("Invalid Ptr\n"));
23035 return;
23036 } else {
23037 wdev = cfg->p2p_wdev;
23038 }
23039
23040 if (wdev) {
23041 wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
23042 }
23043 }
23044 #endif /* WL_CFG80211_P2P_DEV_IF */
23045
23046 #ifdef GTK_OFFLOAD_SUPPORT
23047 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
23048 static s32
23049 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
23050 struct cfg80211_gtk_rekey_data *data)
23051 {
23052 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
23053 s32 err = 0;
23054 gtk_keyinfo_t keyinfo;
23055
23056 WL_DBG(("Enter\n"));
23057 if (data == NULL || cfg->p2p_net == dev) {
23058 WL_ERR(("data is NULL or wrong net device\n"));
23059 return -EINVAL;
23060 }
23061
23062 prhex("kck", (const u8 *) (data->kck), RSN_KCK_LENGTH);
23063 prhex("kek", (const u8 *) (data->kek), RSN_KEK_LENGTH);
23064 prhex("replay_ctr", (const u8 *) (data->replay_ctr), RSN_REPLAY_LEN);
23065 bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH);
23066 bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH);
23067 bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN);
23068
23069 if ((err = wldev_iovar_setbuf(dev, "gtk_key_info", &keyinfo, sizeof(keyinfo),
23070 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync)) < 0) {
23071 WL_ERR(("seting gtk_key_info failed code=%d\n", err));
23072 return err;
23073 }
23074 WL_DBG(("Exit\n"));
23075 return err;
23076 }
23077 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
23078 #endif /* GTK_OFFLOAD_SUPPORT */
23079
23080 #if defined(WL_SUPPORT_AUTO_CHANNEL)
23081 int
23082 wl_cfg80211_set_spect(struct net_device *dev, int spect)
23083 {
23084 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23085 int wlc_down = 1;
23086 int wlc_up = 1;
23087 int err = BCME_OK;
23088
23089 if (!wl_get_drv_status_all(cfg, CONNECTED)) {
23090 err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
23091 if (err) {
23092 WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
23093 return err;
23094 }
23095
23096 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
23097 if (err) {
23098 WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
23099 return err;
23100 }
23101
23102 err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
23103 if (err) {
23104 WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
23105 return err;
23106 }
23107 }
23108 return err;
23109 }
23110
23111 int
23112 wl_cfg80211_get_sta_channel(struct bcm_cfg80211 *cfg)
23113 {
23114 int channel = 0;
23115
23116 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
23117 channel = cfg->channel;
23118 }
23119 return channel;
23120 }
23121 #endif /* WL_SUPPORT_AUTO_CHANNEL */
23122
23123 u64
23124 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
23125 {
23126 u64 id = 0;
23127 id = ++cfg->last_roc_id;
23128 #ifdef P2P_LISTEN_OFFLOADING
23129 if (id == P2PO_COOKIE) {
23130 id = ++cfg->last_roc_id;
23131 }
23132 #endif /* P2P_LISTEN_OFFLOADING */
23133 if (id == 0)
23134 id = ++cfg->last_roc_id;
23135 return id;
23136 }
23137
23138 #if defined(SUPPORT_RANDOM_MAC_SCAN)
23139 int
23140 wl_cfg80211_set_random_mac(struct net_device *dev, bool enable)
23141 {
23142 return BCME_OK;
23143 }
23144
23145 #if defined(DHD_RANDOM_MAC_SCAN)
23146 int
23147 wl_cfg80211_dhd_driven_random_mac_enable(struct net_device *dev, uint8 *rand_mac, uint8 *rand_mask)
23148 {
23149 u8 random_mac_addr[ETHER_ADDR_LEN] = {0, };
23150 s32 err = BCME_ERROR;
23151 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23152 int i = 0;
23153
23154 if ((rand_mac == NULL) || (rand_mask == NULL)) {
23155 err = BCME_BADARG;
23156 WL_ERR(("Fail to Set random mac, bad argument\n"));
23157 wl_cfg80211_random_mac_disable(dev);
23158 return err;
23159 }
23160
23161 if (ETHER_ISNULLADDR(rand_mac)) {
23162 WL_DBG(("Fail to Set random mac, Invalid rand mac\n"));
23163 wl_cfg80211_random_mac_disable(dev);
23164 return err;
23165 }
23166
23167 if (wl_get_drv_status_all(cfg, CONNECTED) || wl_get_drv_status_all(cfg, CONNECTING) ||
23168 wl_get_drv_status_all(cfg, AP_CREATED) || wl_get_drv_status_all(cfg, AP_CREATING)) {
23169 WL_ERR(("Skip to set random mac by current stastus\n"));
23170 return err;
23171 }
23172
23173 /* Generate 6 bytes random address */
23174 get_random_bytes(&random_mac_addr, sizeof(random_mac_addr));
23175
23176 /* Overwrite unmasked MAC address */
23177 for (i = 0; i < ETHER_ADDR_LEN; i++) {
23178 if (rand_mask[i]) {
23179 random_mac_addr[i] = rand_mac[i];
23180 }
23181 }
23182
23183 /* Modify last mac address if 0x00 or 0xff */
23184 if (random_mac_addr[5] == 0x0 || random_mac_addr[5] == 0xff) {
23185 random_mac_addr[5] = 0xf0;
23186 }
23187 err = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr",
23188 random_mac_addr, ETHER_ADDR_LEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
23189 0, &cfg->ioctl_buf_sync);
23190
23191 if (err != BCME_OK) {
23192 WL_ERR(("Failed to set random generate MAC address\n"));
23193 } else {
23194 cfg->random_mac_running = TRUE;
23195 WL_INFORM(("Set random mac " MACDBG " to " MACDBG "\n",
23196 MAC2STRDBG((const u8 *)bcmcfg_to_prmry_ndev(cfg)->dev_addr),
23197 MAC2STRDBG((const u8 *)&random_mac_addr)));
23198 }
23199 return err;
23200 }
23201
23202 int
23203 wl_cfg80211_dhd_driven_random_mac_disable(struct net_device *dev)
23204 {
23205 s32 err = BCME_ERROR;
23206 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23207
23208 if (cfg->random_mac_running) {
23209 WL_INFORM(("Restore to original MAC address " MACDBG "\n",
23210 MAC2STRDBG((const u8 *)bcmcfg_to_prmry_ndev(cfg)->dev_addr)));
23211
23212 err = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr",
23213 bcmcfg_to_prmry_ndev(cfg)->dev_addr, ETHER_ADDR_LEN,
23214 cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
23215
23216 if (err != BCME_OK) {
23217 WL_ERR(("Failed to restore original MAC address\n"));
23218 } else {
23219 cfg->random_mac_running = FALSE;
23220 WL_ERR(("Random MAC disable done\n"));
23221 }
23222 }
23223 return err;
23224 }
23225
23226 #endif /* DHD_RANDOM_MAC_SCAN */
23227
23228 int
23229 wl_cfg80211_random_mac_enable(struct net_device *dev, uint8 *rand_mac, uint8 *rand_mask)
23230 {
23231 s32 err = BCME_ERROR;
23232 #if defined(DHD_RANDOM_MAC_SCAN)
23233 err = wl_cfg80211_dhd_driven_random_mac_enable(dev, rand_mac, rand_mask);
23234 #else /* Random mac by scan mac feature */
23235 err = wl_cfg80211_scan_mac_enable(dev, rand_mac, rand_mask);
23236 #endif /* DHD_RANDOM_MAC_SCAN */
23237
23238 return err;
23239 }
23240
23241 int
23242 wl_cfg80211_random_mac_disable(struct net_device *dev)
23243 {
23244 s32 err = BCME_ERROR;
23245 #if defined(DHD_RANDOM_MAC_SCAN)
23246 err = wl_cfg80211_dhd_driven_random_mac_disable(dev);
23247 #else /* Random mac by scan mac featur */
23248 err = wl_cfg80211_scan_mac_disable(dev);
23249 #endif /* DHD_RANDOM_MAC_SCAN */
23250
23251 return err;
23252 }
23253
23254 /*
23255 * This is new interface for mac randomization. It takes randmac and randmask
23256 * as arg and it uses scanmac iovar to offload the mac randomization to firmware.
23257 */
23258 int wl_cfg80211_scan_mac_enable(struct net_device *dev, uint8 *rand_mac, uint8 *rand_mask)
23259 {
23260 int byte_index = 0;
23261 s32 err = BCME_ERROR;
23262 uint8 buffer[WLC_IOCTL_SMLEN] = {0, };
23263 wl_scanmac_t *sm = NULL;
23264 int len = 0;
23265 wl_scanmac_enable_t *sm_enable = NULL;
23266 wl_scanmac_config_t *sm_config = NULL;
23267 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23268
23269 if ((rand_mac == NULL) || (rand_mask == NULL)) {
23270 err = BCME_BADARG;
23271 WL_ERR(("fail to Set random mac, bad argument\n"));
23272 /* Disable the current scanmac config */
23273 wl_cfg80211_scan_mac_disable(dev);
23274 return err;
23275 }
23276
23277 if (ETHER_ISNULLADDR(rand_mac)) {
23278 WL_DBG(("fail to Set random mac, Invalid rand mac\n"));
23279 /* Disable the current scanmac config */
23280 wl_cfg80211_scan_mac_disable(dev);
23281 return err;
23282 }
23283
23284 if (wl_get_drv_status_all(cfg, CONNECTED) || wl_get_drv_status_all(cfg, CONNECTING) ||
23285 wl_get_drv_status_all(cfg, AP_CREATED) || wl_get_drv_status_all(cfg, AP_CREATING)) {
23286 WL_ERR(("fail to Set random mac, current state is wrong\n"));
23287 return BCME_UNSUPPORTED;
23288 }
23289
23290 /* Enable scan mac */
23291 sm = (wl_scanmac_t *)buffer;
23292 sm_enable = (wl_scanmac_enable_t *)sm->data;
23293 sm->len = sizeof(*sm_enable);
23294 sm_enable->enable = 1;
23295 len = OFFSETOF(wl_scanmac_t, data) + sm->len;
23296 sm->subcmd_id = WL_SCANMAC_SUBCMD_ENABLE;
23297
23298 err = wldev_iovar_setbuf_bsscfg(dev, "scanmac",
23299 sm, len, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
23300
23301 if (err == BCME_OK) {
23302 /* Configure scanmac */
23303 memset(buffer, 0x0, sizeof(buffer));
23304 sm_config = (wl_scanmac_config_t *)sm->data;
23305 sm->len = sizeof(*sm_config);
23306 sm->subcmd_id = WL_SCANMAC_SUBCMD_CONFIG;
23307 sm_config->scan_bitmap = WL_SCANMAC_SCAN_UNASSOC;
23308
23309 /* Set randomize mac address recv from upper layer */
23310 memcpy(&sm_config->mac.octet, rand_mac, ETH_ALEN);
23311
23312 /* Set randomize mask recv from upper layer */
23313
23314 /* There is a difference in how to interpret rand_mask between
23315 * upperlayer and firmware. If the byte is set as FF then for
23316 * upper layer it means keep that byte and do not randomize whereas
23317 * for firmware it means randomize those bytes and vice versa. Hence
23318 * conversion is needed before setting the iovar
23319 */
23320 memset(&sm_config->random_mask.octet, 0x0, ETH_ALEN);
23321 /* Only byte randomization is supported currently. If mask recv is 0x0F
23322 * for a particular byte then it will be treated as no randomization
23323 * for that byte.
23324 */
23325 while (byte_index < ETH_ALEN) {
23326 if (rand_mask[byte_index] == 0xFF) {
23327 sm_config->random_mask.octet[byte_index] = 0x00;
23328 } else if (rand_mask[byte_index] == 0x00) {
23329 sm_config->random_mask.octet[byte_index] = 0xFF;
23330 }
23331 byte_index++;
23332 }
23333
23334 WL_DBG(("recv random mac addr " MACDBG "recv rand mask" MACDBG "\n",
23335 MAC2STRDBG((const u8 *)&sm_config->mac.octet),
23336 MAC2STRDBG((const u8 *)&sm_config->random_mask)));
23337
23338 len = OFFSETOF(wl_scanmac_t, data) + sm->len;
23339 err = wldev_iovar_setbuf_bsscfg(dev, "scanmac",
23340 sm, len, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
23341
23342 if (err != BCME_OK) {
23343 WL_ERR(("failed scanmac configuration\n"));
23344
23345 /* Disable scan mac for clean-up */
23346 wl_cfg80211_scan_mac_disable(dev);
23347 return err;
23348 }
23349 WL_DBG(("scanmac enable done"));
23350 } else {
23351 WL_ERR(("failed to enable scanmac, err=%d\n", err));
23352 }
23353
23354 return err;
23355 }
23356
23357 int wl_cfg80211_scan_mac_disable(struct net_device *dev)
23358 {
23359 s32 err = BCME_ERROR;
23360 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23361 uint8 buffer[WLC_IOCTL_SMLEN] = {0, };
23362 wl_scanmac_t *sm = NULL;
23363 int len = 0;
23364 wl_scanmac_enable_t *sm_enable = NULL;
23365
23366 sm = (wl_scanmac_t *)buffer;
23367 sm_enable = (wl_scanmac_enable_t *)sm->data;
23368 sm->len = sizeof(*sm_enable);
23369 /* Disable scanmac */
23370 sm_enable->enable = 0;
23371 len = OFFSETOF(wl_scanmac_t, data) + sm->len;
23372
23373 sm->subcmd_id = WL_SCANMAC_SUBCMD_ENABLE;
23374
23375 err = wldev_iovar_setbuf_bsscfg(dev, "scanmac",
23376 sm, len, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
23377
23378 if (err != BCME_OK) {
23379 WL_ERR(("failed to disable scanmac, err=%d\n", err));
23380 } else {
23381 WL_DBG(("random MAC disable done\n"));
23382 }
23383 return err;
23384 }
23385 #endif /* SUPPORT_RANDOM_MAC_SCAN */
23386
23387 #ifdef WLTDLS
23388 static s32
23389 wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg, enum wl_tdls_config state, bool auto_mode)
23390 {
23391 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
23392 int err = 0;
23393 struct net_info *iter, *next;
23394 int update_reqd = 0;
23395 int enable = 0;
23396 dhd_pub_t *dhdp;
23397 dhdp = (dhd_pub_t *)(cfg->pub);
23398
23399 /*
23400 * TDLS need to be enabled only if we have a single STA/GC
23401 * connection.
23402 */
23403
23404 WL_DBG(("Enter state:%d\n", state));
23405 if (!cfg->tdls_supported) {
23406 /* FW doesn't support tdls. Do nothing */
23407 return -ENODEV;
23408 }
23409
23410 /* Protect tdls config session */
23411 mutex_lock(&cfg->tdls_sync);
23412
23413 if (state == TDLS_STATE_TEARDOWN) {
23414 /* Host initiated TDLS tear down */
23415 err = dhd_tdls_enable(ndev, false, auto_mode, NULL);
23416 goto exit;
23417 } else if ((state == TDLS_STATE_AP_CREATE) ||
23418 (state == TDLS_STATE_NDI_CREATE)) {
23419 /* We don't support tdls while AP/GO/NAN is operational */
23420 update_reqd = true;
23421 enable = false;
23422 } else if ((state == TDLS_STATE_CONNECT) || (state == TDLS_STATE_IF_CREATE)) {
23423 if (wl_get_drv_status_all(cfg,
23424 CONNECTED) >= TDLS_MAX_IFACE_FOR_ENABLE) {
23425 /* For STA/GC connect command request, disable
23426 * tdls if we have any concurrent interfaces
23427 * operational.
23428 */
23429 WL_DBG(("Interface limit restriction. disable tdls.\n"));
23430 update_reqd = true;
23431 enable = false;
23432 }
23433 } else if ((state == TDLS_STATE_DISCONNECT) ||
23434 (state == TDLS_STATE_AP_DELETE) ||
23435 (state == TDLS_STATE_SETUP) ||
23436 (state == TDLS_STATE_IF_DELETE)) {
23437 /* Enable back the tdls connection only if we have less than
23438 * or equal to a single STA/GC connection.
23439 */
23440 if (wl_get_drv_status_all(cfg,
23441 CONNECTED) == 0) {
23442 /* If there are no interfaces connected, enable tdls */
23443 update_reqd = true;
23444 enable = true;
23445 } else if (wl_get_drv_status_all(cfg,
23446 CONNECTED) == TDLS_MAX_IFACE_FOR_ENABLE) {
23447 /* We have one interface in CONNECTED state.
23448 * Verify whether its a STA interface before
23449 * we enable back tdls.
23450 */
23451 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23452 #pragma GCC diagnostic push
23453 #pragma GCC diagnostic ignored "-Wcast-qual"
23454 #endif // endif
23455 for_each_ndev(cfg, iter, next) {
23456 if ((iter->ndev) &&
23457 (wl_get_drv_status(cfg, CONNECTED, ndev)) &&
23458 (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)) {
23459 WL_DBG(("Non STA iface operational. cfg_iftype:%d "
23460 "Can't enable tdls.\n",
23461 ndev->ieee80211_ptr->iftype));
23462 err = -ENOTSUPP;
23463 goto exit;
23464 }
23465 }
23466 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23467 #pragma GCC diagnostic pop
23468 #endif // endif
23469 /* No AP/GO found. Enable back tdls */
23470 update_reqd = true;
23471 enable = true;
23472 } else {
23473 WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
23474 err = -ENOTSUPP;
23475 goto exit;
23476 }
23477 } else {
23478 WL_ERR(("Unknown tdls state:%d \n", state));
23479 err = -EINVAL;
23480 goto exit;
23481 }
23482
23483 if (update_reqd == true) {
23484 if (dhdp->tdls_enable == enable) {
23485 WL_DBG(("No change in tdls state. Do nothing."
23486 " tdls_enable:%d\n", enable));
23487 goto exit;
23488 }
23489 err = wldev_iovar_setint(ndev, "tdls_enable", enable);
23490 if (unlikely(err)) {
23491 WL_ERR(("tdls_enable setting failed. err:%d\n", err));
23492 goto exit;
23493 } else {
23494 WL_INFORM_MEM(("tdls_enable %d state:%d\n", enable, state));
23495 /* Update the dhd state variable to be in sync */
23496 dhdp->tdls_enable = enable;
23497 if (state == TDLS_STATE_SETUP) {
23498 /* For host initiated setup, apply TDLS params
23499 * Don't propagate errors up for param config
23500 * failures
23501 */
23502 dhd_tdls_enable(ndev, true, auto_mode, NULL);
23503
23504 }
23505 }
23506 } else {
23507 WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
23508 "current_status:%d \n",
23509 state, update_reqd, dhdp->tdls_enable));
23510 }
23511
23512 exit:
23513 if (err) {
23514 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
23515 }
23516 mutex_unlock(&cfg->tdls_sync);
23517 return err;
23518 }
23519 #endif /* WLTDLS */
23520
23521 struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname)
23522 {
23523 struct net_info *iter, *next;
23524 struct net_device *ndev = NULL;
23525
23526 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23527 #pragma GCC diagnostic push
23528 #pragma GCC diagnostic ignored "-Wcast-qual"
23529 #endif // endif
23530 for_each_ndev(cfg, iter, next) {
23531 if (iter->ndev) {
23532 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
23533 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
23534 ndev = iter->ndev;
23535 break;
23536 }
23537 }
23538 }
23539 }
23540 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23541 #pragma GCC diagnostic pop
23542 #endif // endif
23543
23544 return ndev;
23545 }
23546
23547 struct net_device*
23548 wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname)
23549 {
23550 struct net_info *iter, *next;
23551 struct net_device *ndev = NULL;
23552
23553 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23554 #pragma GCC diagnostic push
23555 #pragma GCC diagnostic ignored "-Wcast-qual"
23556 #endif // endif
23557 for_each_ndev(cfg, iter, next) {
23558 if (iter->ndev) {
23559 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
23560 ndev = iter->ndev;
23561 break;
23562 }
23563 }
23564 }
23565 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23566 #pragma GCC diagnostic pop
23567 #endif // endif
23568
23569 return ndev;
23570 }
23571
23572 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
23573 #define WLC_RATE_FLAG 0x80
23574 #define RATE_MASK 0x7f
23575
23576 int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname)
23577 {
23578 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23579 dhd_pub_t *dhdp;
23580 wl_rateset_args_t rs;
23581 int error = BCME_ERROR, i;
23582 struct net_device *ndev = NULL;
23583
23584 dhdp = (dhd_pub_t *)(cfg->pub);
23585
23586 if (dhdp && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23587 WL_ERR(("Not Hostapd mode\n"));
23588 return BCME_NOTAP;
23589 }
23590
23591 ndev = wl_get_ap_netdev(cfg, ifname);
23592
23593 if (ndev == NULL) {
23594 WL_ERR(("No softAP interface named %s\n", ifname));
23595 return BCME_NOTAP;
23596 }
23597
23598 bzero(&rs, sizeof(wl_rateset_args_t));
23599 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
23600 &rs, sizeof(wl_rateset_args_t), NULL);
23601 if (error < 0) {
23602 WL_ERR(("get rateset failed = %d\n", error));
23603 return error;
23604 }
23605
23606 if (rs.count < 1) {
23607 WL_ERR(("Failed to get rate count\n"));
23608 return BCME_ERROR;
23609 }
23610
23611 /* Host delivers target rate in the unit of 500kbps */
23612 /* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic rate */
23613 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
23614 if (rs.rates[i] & WLC_RATE_FLAG)
23615 if ((rs.rates[i] & RATE_MASK) == val)
23616 break;
23617
23618 /* Valid rate has been delivered as an argument */
23619 if (i < rs.count && i < WL_NUMRATES) {
23620 error = wldev_iovar_setint(ndev, "force_bcn_rspec", val);
23621 if (error < 0) {
23622 WL_ERR(("set beacon rate failed = %d\n", error));
23623 return BCME_ERROR;
23624 }
23625 } else {
23626 WL_ERR(("Rate is invalid"));
23627 return BCME_BADARG;
23628 }
23629
23630 return BCME_OK;
23631 }
23632
23633 int
23634 wl_get_ap_basic_rate(struct net_device *dev, char* command, char *ifname, int total_len)
23635 {
23636 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23637 dhd_pub_t *dhdp;
23638 wl_rateset_args_t rs;
23639 int error = BCME_ERROR;
23640 int i, bytes_written = 0;
23641 struct net_device *ndev = NULL;
23642
23643 dhdp = (dhd_pub_t *)(cfg->pub);
23644
23645 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23646 WL_ERR(("Not Hostapd mode\n"));
23647 return BCME_NOTAP;
23648 }
23649
23650 ndev = wl_get_ap_netdev(cfg, ifname);
23651
23652 if (ndev == NULL) {
23653 WL_ERR(("No softAP interface named %s\n", ifname));
23654 return BCME_NOTAP;
23655 }
23656
23657 bzero(&rs, sizeof(wl_rateset_args_t));
23658 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
23659 &rs, sizeof(wl_rateset_args_t), NULL);
23660 if (error < 0) {
23661 WL_ERR(("get rateset failed = %d\n", error));
23662 return error;
23663 }
23664
23665 if (rs.count < 1) {
23666 WL_ERR(("Failed to get rate count\n"));
23667 return BCME_ERROR;
23668 }
23669
23670 /* Delivers basic rate in the unit of 500kbps to host */
23671 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
23672 if (rs.rates[i] & WLC_RATE_FLAG)
23673 bytes_written += snprintf(command + bytes_written, total_len,
23674 "%d ", rs.rates[i] & RATE_MASK);
23675
23676 /* Remove last space in the command buffer */
23677 if (bytes_written && (bytes_written < total_len)) {
23678 command[bytes_written - 1] = '\0';
23679 bytes_written--;
23680 }
23681
23682 return bytes_written;
23683
23684 }
23685 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
23686
23687 #ifdef SUPPORT_AP_RADIO_PWRSAVE
23688 #define MSEC_PER_MIN (60000L)
23689
23690 static int
23691 _wl_update_ap_rps_params(struct net_device *dev)
23692 {
23693 struct bcm_cfg80211 *cfg = NULL;
23694 rpsnoa_iovar_params_t iovar;
23695 u8 smbuf[WLC_IOCTL_SMLEN];
23696
23697 if (!dev)
23698 return BCME_BADARG;
23699
23700 cfg = wl_get_cfg(dev);
23701
23702 memset(&iovar, 0, sizeof(iovar));
23703 memset(smbuf, 0, sizeof(smbuf));
23704
23705 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
23706 iovar.hdr.subcmd = WL_RPSNOA_CMD_PARAMS;
23707 iovar.hdr.len = sizeof(iovar);
23708 iovar.param->band = WLC_BAND_ALL;
23709 iovar.param->level = cfg->ap_rps_info.level;
23710 iovar.param->stas_assoc_check = cfg->ap_rps_info.sta_assoc_check;
23711 iovar.param->pps = cfg->ap_rps_info.pps;
23712 iovar.param->quiet_time = cfg->ap_rps_info.quiet_time;
23713
23714 if (wldev_iovar_setbuf(dev, "rpsnoa", &iovar, sizeof(iovar),
23715 smbuf, sizeof(smbuf), NULL)) {
23716 WL_ERR(("Failed to set rpsnoa params"));
23717 return BCME_ERROR;
23718 }
23719
23720 return BCME_OK;
23721 }
23722
23723 int
23724 wl_get_ap_rps(struct net_device *dev, char* command, char *ifname, int total_len)
23725 {
23726 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23727 dhd_pub_t *dhdp;
23728 int error = BCME_ERROR;
23729 int bytes_written = 0;
23730 struct net_device *ndev = NULL;
23731 rpsnoa_iovar_status_t iovar;
23732 u8 smbuf[WLC_IOCTL_SMLEN];
23733 u32 chanspec = 0;
23734 u8 idx = 0;
23735 u16 state;
23736 u32 sleep;
23737 u32 time_since_enable;
23738
23739 dhdp = (dhd_pub_t *)(cfg->pub);
23740
23741 if (!dhdp) {
23742 error = BCME_NOTUP;
23743 goto fail;
23744 }
23745
23746 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23747 WL_ERR(("Not Hostapd mode\n"));
23748 error = BCME_NOTAP;
23749 goto fail;
23750 }
23751
23752 ndev = wl_get_ap_netdev(cfg, ifname);
23753
23754 if (ndev == NULL) {
23755 WL_ERR(("No softAP interface named %s\n", ifname));
23756 error = BCME_NOTAP;
23757 goto fail;
23758 }
23759
23760 memset(&iovar, 0, sizeof(iovar));
23761 memset(smbuf, 0, sizeof(smbuf));
23762
23763 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
23764 iovar.hdr.subcmd = WL_RPSNOA_CMD_STATUS;
23765 iovar.hdr.len = sizeof(iovar);
23766 iovar.stats->band = WLC_BAND_ALL;
23767
23768 error = wldev_iovar_getbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
23769 smbuf, sizeof(smbuf), NULL);
23770 if (error < 0) {
23771 WL_ERR(("get ap radio pwrsave failed = %d\n", error));
23772 goto fail;
23773 }
23774
23775 /* RSDB event doesn't seem to be handled correctly.
23776 * So check chanspec of AP directly from the firmware
23777 */
23778 error = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
23779 if (error < 0) {
23780 WL_ERR(("get chanspec from AP failed = %d\n", error));
23781 goto fail;
23782 }
23783
23784 chanspec = wl_chspec_driver_to_host(chanspec);
23785 if (CHSPEC_IS2G(chanspec))
23786 idx = 0;
23787 else if (CHSPEC_IS5G(chanspec))
23788 idx = 1;
23789 else {
23790 error = BCME_BADCHAN;
23791 goto fail;
23792 }
23793
23794 state = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].state;
23795 sleep = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_dur;
23796 time_since_enable = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_avail_dur;
23797
23798 /* Conver ms to minute, round down only */
23799 sleep = DIV_U64_BY_U32(sleep, MSEC_PER_MIN);
23800 time_since_enable = DIV_U64_BY_U32(time_since_enable, MSEC_PER_MIN);
23801
23802 bytes_written += snprintf(command + bytes_written, total_len,
23803 "state=%d sleep=%d time_since_enable=%d", state, sleep, time_since_enable);
23804 error = bytes_written;
23805
23806 fail:
23807 return error;
23808 }
23809
23810 int
23811 wl_set_ap_rps(struct net_device *dev, bool enable, char *ifname)
23812 {
23813 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23814 dhd_pub_t *dhdp;
23815 struct net_device *ndev = NULL;
23816 rpsnoa_iovar_t iovar;
23817 u8 smbuf[WLC_IOCTL_SMLEN];
23818 int ret = BCME_OK;
23819
23820 dhdp = (dhd_pub_t *)(cfg->pub);
23821
23822 if (!dhdp) {
23823 ret = BCME_NOTUP;
23824 goto exit;
23825 }
23826
23827 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23828 WL_ERR(("Not Hostapd mode\n"));
23829 ret = BCME_NOTAP;
23830 goto exit;
23831 }
23832
23833 ndev = wl_get_ap_netdev(cfg, ifname);
23834
23835 if (ndev == NULL) {
23836 WL_ERR(("No softAP interface named %s\n", ifname));
23837 ret = BCME_NOTAP;
23838 goto exit;
23839 }
23840
23841 if (cfg->ap_rps_info.enable != enable) {
23842 cfg->ap_rps_info.enable = enable;
23843 if (enable) {
23844 ret = _wl_update_ap_rps_params(ndev);
23845 if (ret) {
23846 WL_ERR(("Filed to update rpsnoa params\n"));
23847 goto exit;
23848 }
23849 }
23850 memset(&iovar, 0, sizeof(iovar));
23851 memset(smbuf, 0, sizeof(smbuf));
23852
23853 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
23854 iovar.hdr.subcmd = WL_RPSNOA_CMD_ENABLE;
23855 iovar.hdr.len = sizeof(iovar);
23856 iovar.data->band = WLC_BAND_ALL;
23857 iovar.data->value = (int16)enable;
23858
23859 ret = wldev_iovar_setbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
23860 smbuf, sizeof(smbuf), NULL);
23861 if (ret) {
23862 WL_ERR(("Failed to enable AP radio power save"));
23863 goto exit;
23864 }
23865 cfg->ap_rps_info.enable = enable;
23866 }
23867 exit:
23868 return ret;
23869 }
23870
23871 int
23872 wl_update_ap_rps_params(struct net_device *dev, ap_rps_info_t* rps, char *ifname)
23873 {
23874 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23875 dhd_pub_t *dhdp;
23876 struct net_device *ndev = NULL;
23877
23878 dhdp = (dhd_pub_t *)(cfg->pub);
23879
23880 if (!dhdp)
23881 return BCME_NOTUP;
23882
23883 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23884 WL_ERR(("Not Hostapd mode\n"));
23885 return BCME_NOTAP;
23886 }
23887
23888 ndev = wl_get_ap_netdev(cfg, ifname);
23889
23890 if (ndev == NULL) {
23891 WL_ERR(("No softAP interface named %s\n", ifname));
23892 return BCME_NOTAP;
23893 }
23894
23895 if (!rps)
23896 return BCME_BADARG;
23897
23898 if (rps->pps < RADIO_PWRSAVE_PPS_MIN)
23899 return BCME_BADARG;
23900
23901 if (rps->level < RADIO_PWRSAVE_LEVEL_MIN ||
23902 rps->level > RADIO_PWRSAVE_LEVEL_MAX)
23903 return BCME_BADARG;
23904
23905 if (rps->quiet_time < RADIO_PWRSAVE_QUIETTIME_MIN)
23906 return BCME_BADARG;
23907
23908 if (rps->sta_assoc_check > RADIO_PWRSAVE_ASSOCCHECK_MAX ||
23909 rps->sta_assoc_check < RADIO_PWRSAVE_ASSOCCHECK_MIN)
23910 return BCME_BADARG;
23911
23912 cfg->ap_rps_info.pps = rps->pps;
23913 cfg->ap_rps_info.level = rps->level;
23914 cfg->ap_rps_info.quiet_time = rps->quiet_time;
23915 cfg->ap_rps_info.sta_assoc_check = rps->sta_assoc_check;
23916
23917 if (cfg->ap_rps_info.enable) {
23918 if (_wl_update_ap_rps_params(ndev)) {
23919 WL_ERR(("Failed to update rpsnoa params"));
23920 return BCME_ERROR;
23921 }
23922 }
23923
23924 return BCME_OK;
23925 }
23926
23927 void
23928 wl_cfg80211_init_ap_rps(struct bcm_cfg80211 *cfg)
23929 {
23930 cfg->ap_rps_info.enable = FALSE;
23931 cfg->ap_rps_info.sta_assoc_check = RADIO_PWRSAVE_STAS_ASSOC_CHECK;
23932 cfg->ap_rps_info.pps = RADIO_PWRSAVE_PPS;
23933 cfg->ap_rps_info.quiet_time = RADIO_PWRSAVE_QUIET_TIME;
23934 cfg->ap_rps_info.level = RADIO_PWRSAVE_LEVEL;
23935 }
23936 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
23937
23938 int
23939 wl_cfg80211_iface_count(struct net_device *dev)
23940 {
23941 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23942 struct net_info *iter, *next;
23943 int iface_count = 0;
23944
23945 /* Return the count of network interfaces (skip netless p2p discovery
23946 * interface)
23947 */
23948 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23949 #pragma GCC diagnostic push
23950 #pragma GCC diagnostic ignored "-Wcast-qual"
23951 #endif // endif
23952 for_each_ndev(cfg, iter, next) {
23953 if (iter->ndev) {
23954 iface_count++;
23955 }
23956 }
23957 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23958 #pragma GCC diagnostic pop
23959 #endif // endif
23960 return iface_count;
23961 }
23962
23963 #ifdef DHD_ABORT_SCAN_CREATE_INTERFACE
23964 int
23965 wl_abort_scan_and_check(struct bcm_cfg80211 *cfg)
23966 {
23967 int wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
23968 int ret = TRUE;
23969
23970 wl_cfg80211_scan_abort(cfg);
23971 while (wl_get_drv_status_all(cfg, SCANNING) && wait_cnt) {
23972 WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
23973 wait_cnt--;
23974 OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
23975 }
23976
23977 if (!wait_cnt && wl_get_drv_status_all(cfg, SCANNING)) {
23978 WL_ERR(("Failed to abort scan\n"));
23979 ret = FALSE;
23980 }
23981
23982 return ret;
23983 }
23984 #endif /* DHD_ABORT_SCAN_CREATE_INTERFACE */
23985
23986 #ifdef DHD_USE_CHECK_DONGLE_IDLE
23987 #define CHECK_DONGLE_IDLE_TIME 50
23988 #define CHECK_DONGLE_IDLE_CNT 100
23989
23990 int
23991 wl_check_dongle_idle(struct wiphy *wiphy)
23992 {
23993 int error = 0;
23994 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
23995 struct net_device *primary_ndev;
23996 int retry = 0;
23997 struct channel_info ci;
23998
23999 if (!cfg) {
24000 return FALSE;
24001 }
24002
24003 /* Use primary I/F for sending cmds down to firmware */
24004 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
24005
24006 while (retry++ < CHECK_DONGLE_IDLE_CNT) {
24007 memset(&ci, 0, sizeof(ci));
24008 error = wldev_ioctl_get(primary_ndev, WLC_GET_CHANNEL, &ci, sizeof(ci));
24009 if (error != BCME_OK || ci.scan_channel != 0) {
24010 if (error == -ENODEV) {
24011 WL_ERR(("Firmware is not ready, return TRUE\n"));
24012 return TRUE;
24013 }
24014 WL_DBG(("Firmware is busy(err:%d scan channel:%d). wait %dms\n",
24015 error, ci.scan_channel, CHECK_DONGLE_IDLE_TIME));
24016 } else {
24017 break;
24018 }
24019 wl_delay(CHECK_DONGLE_IDLE_TIME);
24020 }
24021 if (retry >= CHECK_DONGLE_IDLE_CNT) {
24022 WL_ERR(("DONGLE is BUSY too long\n"));
24023 return FALSE;
24024 }
24025 WL_DBG(("DONGLE is idle\n"));
24026 return TRUE;
24027 }
24028 #undef CHECK_DONGLE_IDLE_TIME
24029 #undef CHECK_DONGLE_IDLE_CNT
24030 #endif /* DHD_USE_CHECK_DONGLE_IDLE */
24031
24032 #ifdef WES_SUPPORT
24033 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
24034 s32 wl_cfg80211_custom_scan_time(struct net_device *dev,
24035 enum wl_custom_scan_time_type type, int time)
24036 {
24037 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24038
24039 if (cfg == NULL) {
24040 return FALSE;
24041 }
24042
24043 switch (type) {
24044 case WL_CUSTOM_SCAN_CHANNEL_TIME :
24045 WL_ERR(("Scan Channel Time %d\n", time));
24046 cfg->custom_scan_channel_time = time;
24047 break;
24048 case WL_CUSTOM_SCAN_UNASSOC_TIME :
24049 WL_ERR(("Scan Unassoc Time %d\n", time));
24050 cfg->custom_scan_unassoc_time = time;
24051 break;
24052 case WL_CUSTOM_SCAN_PASSIVE_TIME :
24053 WL_ERR(("Scan Passive Time %d\n", time));
24054 cfg->custom_scan_passive_time = time;
24055 break;
24056 case WL_CUSTOM_SCAN_HOME_TIME :
24057 WL_ERR(("Scan Home Time %d\n", time));
24058 cfg->custom_scan_home_time = time;
24059 break;
24060 case WL_CUSTOM_SCAN_HOME_AWAY_TIME :
24061 WL_ERR(("Scan Home Away Time %d\n", time));
24062 cfg->custom_scan_home_away_time = time;
24063 break;
24064 default:
24065 return FALSE;
24066 }
24067 return TRUE;
24068 }
24069 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
24070 #endif /* WES_SUPPORT */
24071 #ifdef WBTEXT
24072 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
24073 {
24074 wl_wbtext_bssid_t *bssid = NULL;
24075 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
24076 #pragma GCC diagnostic push
24077 #pragma GCC diagnostic ignored "-Wcast-qual"
24078 #endif // endif
24079
24080 /* check duplicate */
24081 list_for_each_entry(bssid, &cfg->wbtext_bssid_list, list) {
24082 if (!memcmp(bssid->ea.octet, ea, ETHER_ADDR_LEN)) {
24083 return FALSE;
24084 }
24085 }
24086
24087 return TRUE;
24088 }
24089
24090 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
24091 {
24092 wl_wbtext_bssid_t *bssid = NULL;
24093 char eabuf[ETHER_ADDR_STR_LEN];
24094
24095 bssid = (wl_wbtext_bssid_t *)MALLOC(cfg->osh, sizeof(wl_wbtext_bssid_t));
24096 if (bssid == NULL) {
24097 WL_ERR(("alloc failed\n"));
24098 return FALSE;
24099 }
24100
24101 memcpy(bssid->ea.octet, ea, ETHER_ADDR_LEN);
24102
24103 INIT_LIST_HEAD(&bssid->list);
24104 list_add_tail(&bssid->list, &cfg->wbtext_bssid_list);
24105
24106 WL_DBG(("add wbtext bssid : %s\n", bcm_ether_ntoa(ea, eabuf)));
24107
24108 return TRUE;
24109 }
24110
24111 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg)
24112 {
24113 wl_wbtext_bssid_t *bssid = NULL;
24114 char eabuf[ETHER_ADDR_STR_LEN];
24115
24116 while (!list_empty(&cfg->wbtext_bssid_list)) {
24117 bssid = list_entry(cfg->wbtext_bssid_list.next, wl_wbtext_bssid_t, list);
24118 if (bssid) {
24119 WL_DBG(("clear wbtext bssid : %s\n", bcm_ether_ntoa(&bssid->ea, eabuf)));
24120 list_del(&bssid->list);
24121 MFREE(cfg->osh, bssid, sizeof(wl_wbtext_bssid_t));
24122 }
24123 }
24124 }
24125
24126 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev)
24127 {
24128 struct wl_connect_info *conn_info = wl_to_conn(cfg);
24129 bcm_tlv_t * cap_ie = NULL;
24130 bool req_sent = FALSE;
24131 struct wl_profile *profile;
24132
24133 WL_DBG(("Enter\n"));
24134
24135 profile = wl_get_profile_by_netdev(cfg, dev);
24136 if (!profile) {
24137 WL_ERR(("no profile exists\n"));
24138 return;
24139 }
24140
24141 if (wl_cfg80211_wbtext_check_bssid_list(cfg,
24142 (struct ether_addr *)&profile->bssid) == FALSE) {
24143 WL_DBG(("already updated\n"));
24144 return;
24145 }
24146
24147 /* first, check NBR bit in RRM IE */
24148 if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24149 DOT11_MNG_RRM_CAP_ID)) != NULL) {
24150 if (isset(cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
24151 req_sent = wl_cfg80211_wbtext_send_nbr_req(cfg, dev, profile);
24152 }
24153 }
24154
24155 /* if RRM nbr was not supported, check BTM bit in extend cap. IE */
24156 if (!req_sent) {
24157 if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24158 DOT11_MNG_EXT_CAP_ID)) != NULL) {
24159 if (cap_ie->len >= DOT11_EXTCAP_LEN_BSSTRANS &&
24160 isset(cap_ie->data, DOT11_EXT_CAP_BSSTRANS_MGMT)) {
24161 wl_cfg80211_wbtext_send_btm_query(cfg, dev, profile);
24162 }
24163 }
24164 }
24165 }
24166
24167 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
24168 struct wl_profile *profile)
24169 {
24170 int error = -1;
24171 char *smbuf = NULL;
24172 struct wl_connect_info *conn_info = wl_to_conn(cfg);
24173 bcm_tlv_t * rrm_cap_ie = NULL;
24174 wlc_ssid_t *ssid = NULL;
24175 bool ret = FALSE;
24176
24177 WL_DBG(("Enter\n"));
24178
24179 /* check RRM nbr bit in extend cap. IE of assoc response */
24180 if ((rrm_cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24181 DOT11_MNG_RRM_CAP_ID)) != NULL) {
24182 if (!isset(rrm_cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
24183 WL_DBG(("AP doesn't support neighbor report\n"));
24184 return FALSE;
24185 }
24186 }
24187
24188 smbuf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
24189 if (smbuf == NULL) {
24190 WL_ERR(("failed to allocated memory\n"));
24191 goto nbr_req_out;
24192 }
24193
24194 ssid = (wlc_ssid_t *)MALLOCZ(cfg->osh, sizeof(wlc_ssid_t));
24195 if (ssid == NULL) {
24196 WL_ERR(("failed to allocated memory\n"));
24197 goto nbr_req_out;
24198 }
24199
24200 ssid->SSID_len = MIN(profile->ssid.SSID_len, DOT11_MAX_SSID_LEN);
24201 memcpy(ssid->SSID, profile->ssid.SSID, ssid->SSID_len);
24202
24203 error = wldev_iovar_setbuf(dev, "rrm_nbr_req", ssid,
24204 sizeof(wlc_ssid_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
24205 if (error == BCME_OK) {
24206 ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
24207 (struct ether_addr *)&profile->bssid);
24208 } else {
24209 WL_ERR(("failed to send neighbor report request, error=%d\n", error));
24210 }
24211
24212 nbr_req_out:
24213 if (ssid) {
24214 MFREE(cfg->osh, ssid, sizeof(wlc_ssid_t));
24215 }
24216
24217 if (smbuf) {
24218 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
24219 }
24220 return ret;
24221 }
24222
24223 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
24224 struct wl_profile *profile)
24225
24226 {
24227 int error = -1;
24228 bool ret = FALSE;
24229 wl_bsstrans_query_t btq;
24230
24231 WL_DBG(("Enter\n"));
24232
24233 memset(&btq, 0, sizeof(wl_bsstrans_query_t));
24234
24235 btq.version = WL_BSSTRANS_QUERY_VERSION_1;
24236 error = wldev_iovar_setbuf(dev, "wnm_bsstrans_query", &btq,
24237 sizeof(btq), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
24238 if (error == BCME_OK) {
24239 ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
24240 (struct ether_addr *)&profile->bssid);
24241 } else {
24242 WL_ERR(("%s: failed to set BTM query, error=%d\n", __FUNCTION__, error));
24243 }
24244 return ret;
24245 }
24246
24247 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev)
24248 {
24249 keepalives_max_idle_t keepalive = {0, 0, 0, 0};
24250 s32 bssidx, error;
24251 int wnm_maxidle = 0;
24252 struct wl_connect_info *conn_info = wl_to_conn(cfg);
24253
24254 /* AP supports wnm max idle ? */
24255 if (bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24256 DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID) != NULL) {
24257 error = wldev_iovar_getint(dev, "wnm_maxidle", &wnm_maxidle);
24258 if (error < 0) {
24259 WL_ERR(("failed to get wnm max idle period : %d\n", error));
24260 }
24261 }
24262
24263 WL_DBG(("wnm max idle period : %d\n", wnm_maxidle));
24264
24265 /* if wnm maxidle has valid period, set it as keep alive */
24266 if (wnm_maxidle > 0) {
24267 keepalive.keepalive_count = 1;
24268 }
24269
24270 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) >= 0) {
24271 error = wldev_iovar_setbuf_bsscfg(dev, "wnm_keepalives_max_idle", &keepalive,
24272 sizeof(keepalives_max_idle_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
24273 bssidx, &cfg->ioctl_buf_sync);
24274 if (error < 0) {
24275 WL_ERR(("set wnm_keepalives_max_idle failed : %d\n", error));
24276 }
24277 }
24278 }
24279
24280 static int
24281 wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len)
24282 {
24283 dot11_rm_action_t *rm_rep;
24284 bcm_tlv_t *tlvs;
24285 uint tlv_len;
24286 int i, error;
24287 dot11_neighbor_rep_ie_t *nbr_rep_ie;
24288 chanspec_t ch;
24289 wl_roam_channel_list_t channel_list;
24290 char iobuf[WLC_IOCTL_SMLEN];
24291
24292 if (body_len < DOT11_RM_ACTION_LEN) {
24293 WL_ERR(("Received Neighbor Report frame with incorrect length %d\n",
24294 body_len));
24295 return BCME_ERROR;
24296 }
24297
24298 rm_rep = (dot11_rm_action_t *)body;
24299 WL_DBG(("received neighbor report (token = %d)\n", rm_rep->token));
24300
24301 tlvs = (bcm_tlv_t *)&rm_rep->data[0];
24302
24303 tlv_len = body_len - DOT11_RM_ACTION_LEN;
24304
24305 while (tlvs && tlvs->id == DOT11_MNG_NEIGHBOR_REP_ID) {
24306 nbr_rep_ie = (dot11_neighbor_rep_ie_t *)tlvs;
24307
24308 if (nbr_rep_ie->len < DOT11_NEIGHBOR_REP_IE_FIXED_LEN) {
24309 WL_ERR(("malformed Neighbor Report element with length %d\n",
24310 nbr_rep_ie->len));
24311 tlvs = bcm_next_tlv(tlvs, &tlv_len);
24312 continue;
24313 }
24314
24315 ch = CH20MHZ_CHSPEC(nbr_rep_ie->channel);
24316 WL_DBG(("ch:%d, bssid:"MACDBG"\n",
24317 ch, MAC2STRDBG(nbr_rep_ie->bssid.octet)));
24318
24319 /* get RCC list */
24320 error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0,
24321 (void *)&channel_list, sizeof(channel_list), NULL);
24322 if (error) {
24323 WL_ERR(("Failed to get roamscan channels, error = %d\n", error));
24324 return BCME_ERROR;
24325 }
24326
24327 /* update RCC */
24328 if (channel_list.n < MAX_ROAM_CHANNEL) {
24329 for (i = 0; i < channel_list.n; i++) {
24330 if (channel_list.channels[i] == ch) {
24331 break;
24332 }
24333 }
24334 if (i == channel_list.n) {
24335 channel_list.channels[channel_list.n] = ch;
24336 channel_list.n++;
24337 }
24338 }
24339
24340 /* set RCC list */
24341 error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list,
24342 sizeof(channel_list), iobuf, sizeof(iobuf), NULL);
24343 if (error) {
24344 WL_DBG(("Failed to set roamscan channels, error = %d\n", error));
24345 }
24346
24347 tlvs = bcm_next_tlv(tlvs, &tlv_len);
24348 }
24349
24350 return BCME_OK;
24351 }
24352 #endif /* WBTEXT */
24353
24354 #ifdef DYNAMIC_MUMIMO_CONTROL
24355 void
24356 wl_set_murx_block_eapol_status(struct bcm_cfg80211 *cfg, int enable)
24357 {
24358 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24359
24360 if (dhdp) {
24361 dhdp->murx_block_eapol = enable;
24362 }
24363 }
24364
24365 bool
24366 wl_get_murx_reassoc_status(struct bcm_cfg80211 *cfg)
24367 {
24368 int status = 0;
24369 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24370
24371 if (dhdp) {
24372 status = dhdp->reassoc_mumimo_sw;
24373 }
24374
24375 return status ? TRUE : FALSE;
24376 }
24377
24378 void
24379 wl_set_murx_reassoc_status(struct bcm_cfg80211 *cfg, int enable)
24380 {
24381 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24382
24383 if (dhdp) {
24384 dhdp->reassoc_mumimo_sw = enable;
24385 }
24386 }
24387
24388 int
24389 wl_check_bss_support_mumimo(struct net_device *dev)
24390 {
24391 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24392 struct wiphy *wiphy = NULL;
24393 struct cfg80211_bss *bss = NULL;
24394 struct wlc_ssid *ssid = NULL;
24395 struct wl_bss_info *bi = NULL;
24396 bcm_tlv_t *vht_ie = NULL;
24397 u8 *bssid = NULL;
24398 u8 *ie = NULL;
24399 u32 ie_len = 0;
24400 u16 ie_mu_mimo_cap = 0;
24401
24402 if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
24403 WL_DBG(("Not associated\n"));
24404 return BCME_ERROR;
24405 }
24406
24407 wiphy = bcmcfg_to_wiphy(cfg);
24408 ssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
24409 bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
24410
24411 if (wiphy && ssid && bssid) {
24412 bss = CFG80211_GET_BSS(wiphy, NULL, bssid,
24413 ssid->SSID, ssid->SSID_len);
24414 } else {
24415 WL_DBG(("Could not find the associated AP\n"));
24416 return FALSE;
24417 }
24418
24419 if (bss) {
24420 #if defined(WL_CFG80211_P2P_DEV_IF)
24421 ie = (u8 *)bss->ies->data;
24422 ie_len = bss->ies->len;
24423 #else
24424 ie = bss->information_elements;
24425 ie_len = bss->len_information_elements;
24426 #endif /* WL_CFG80211_P2P_DEV_IF */
24427 bi = (struct wl_bss_info *)(cfg->extra_buf + 4);
24428 if (bi && bi->vht_cap) {
24429 vht_ie = bcm_parse_tlvs(ie, ie_len, DOT11_MNG_VHT_CAP_ID);
24430 if (vht_ie) {
24431 ie_mu_mimo_cap = (vht_ie->data[2] & 0x08) >> 3;
24432 }
24433 }
24434 CFG80211_PUT_BSS(wiphy, bss);
24435 }
24436
24437 return ie_mu_mimo_cap ? TRUE : FALSE;
24438 }
24439
24440 int
24441 wl_get_murx_bfe_cap(struct net_device *dev, int *cap)
24442 {
24443 int err;
24444 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24445
24446 /* Now there is only single interface */
24447 err = wldev_iovar_getbuf_bsscfg(dev, "murx_bfe_cap",
24448 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
24449 if (unlikely(err)) {
24450 WL_ERR(("Failed to get murx_bfe_cap IOVAR, error = %d\n", err));
24451 return err;
24452 }
24453
24454 memcpy(cap, cfg->ioctl_buf, sizeof(*cap));
24455
24456 return err;
24457 }
24458
24459 int
24460 wl_set_murx_bfe_cap(struct net_device *dev, int val, bool reassoc_req)
24461 {
24462 int err;
24463 int cur_val;
24464 int iface_count = wl_cfg80211_iface_count(dev);
24465 struct ether_addr bssid;
24466 wl_reassoc_params_t params;
24467 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24468 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24469
24470 if (iface_count > 1) {
24471 WL_ERR(("murx_bfe_cap change is not allowed when "
24472 "there are multiple interfaces\n"));
24473 return -EINVAL;
24474 }
24475
24476 if (reassoc_req && wl_get_murx_reassoc_status(cfg)) {
24477 WL_ERR(("Reassociation is in progress...\n"));
24478 return BCME_OK;
24479 }
24480
24481 /* Check the current value */
24482 err = wl_get_murx_bfe_cap(dev, &cur_val);
24483 if (err) {
24484 return err;
24485 }
24486
24487 if (cur_val == val) {
24488 /* We don't need to configure the new value. */
24489 WL_DBG(("Already set murx_bfe_cap to %d\n", val));
24490 return BCME_OK;
24491 }
24492
24493 /* Now there is only single interface */
24494 err = wldev_iovar_setbuf_bsscfg(dev, "murx_bfe_cap", (void *)&val,
24495 sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
24496 &cfg->ioctl_buf_sync);
24497 if (unlikely(err)) {
24498 WL_ERR(("Failed to set murx_bfe_cap IOVAR to %d,"
24499 "error %d\n", val, err));
24500 return err;
24501 }
24502
24503 if (reassoc_req) {
24504 DHD_DISABLE_RUNTIME_PM(dhdp);
24505
24506 /* Enable Tx flow control not to send any data frames to dongle
24507 * while reassociation procedure is in progress
24508 */
24509 dhd_txflowcontrol(dhdp, ALL_INTERFACES, ON);
24510
24511 /* If successful intiate a reassoc */
24512 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) {
24513 WL_ERR(("Failed to get bssid, error=%d\n", err));
24514 DHD_ENABLE_RUNTIME_PM(dhdp);
24515 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
24516 return err;
24517 }
24518
24519 bzero(&params, sizeof(wl_reassoc_params_t));
24520 memcpy(&params.bssid, &bssid, ETHER_ADDR_LEN);
24521
24522 if ((err = wldev_ioctl_set(dev, WLC_REASSOC, &params,
24523 sizeof(wl_reassoc_params_t))) < 0) {
24524 WL_ERR(("reassoc failed err:%d\n", err));
24525 DHD_ENABLE_RUNTIME_PM(dhdp);
24526 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
24527 /* configure previous value */
24528 err = wldev_iovar_setbuf_bsscfg(dev, "murx_bfe_cap", (void *)&cur_val,
24529 sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
24530 &cfg->ioctl_buf_sync);
24531 if (unlikely(err)) {
24532 WL_ERR(("Failed to set murx_bfe_cap IOVAR to %d,"
24533 "error %d\n", val, err));
24534 }
24535 wl_set_murx_reassoc_status(cfg, FALSE);
24536 } else {
24537 WL_ERR(("reassoc issued successfully\n"));
24538 wl_set_murx_reassoc_status(cfg, TRUE);
24539 wl_set_murx_block_eapol_status(cfg, TRUE);
24540 }
24541 }
24542
24543 return err;
24544 }
24545 #endif /* DYNAMIC_MUMIMO_CONTROL */
24546
24547 #ifdef SUPPORT_SET_CAC
24548 void
24549 wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable)
24550 {
24551 int ret = 0;
24552 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
24553
24554 #ifdef SUPPORT_CUSTOM_SET_CAC
24555 if (cfg->enable_cac == 0) {
24556 WL_DBG(("enable_cac %d\n", cfg->enable_cac));
24557 enable = 0;
24558 }
24559 #endif /* SUPPORT_CUSTOM_SET_CAC */
24560
24561 WL_DBG(("cac enable %d, op_mode 0x%04x\n", enable, dhd->op_mode));
24562 if (!dhd) {
24563 WL_ERR(("dhd is NULL\n"));
24564 return;
24565 }
24566 if (enable && ((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) ||
24567 (dhd->op_mode & DHD_FLAG_P2P_GC_MODE) ||
24568 (dhd->op_mode & DHD_FLAG_P2P_GO_MODE))) {
24569 WL_ERR(("op_mode 0x%04x\n", dhd->op_mode));
24570 enable = 0;
24571 }
24572 if ((ret = dhd_wl_ioctl_set_intiovar(dhd, "cac", enable,
24573 WLC_SET_VAR, TRUE, 0)) < 0) {
24574 WL_ERR(("Failed set CAC, ret=%d\n", ret));
24575 } else {
24576 WL_DBG(("CAC set successfully\n"));
24577 }
24578 return;
24579 }
24580
24581 int
24582 wl_cfg80211_enable_cac(struct net_device *dev, int enable)
24583 {
24584 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24585
24586 WL_DBG(("enable %d\n", enable));
24587
24588 #ifdef SUPPORT_CUSTOM_SET_CAC
24589 cfg->enable_cac = enable;
24590 #endif /* SUPPORT_CUSTOM_SET_CAC */
24591 wl_cfg80211_set_cac(cfg, enable);
24592 return 0;
24593 }
24594 #endif /* SUPPORT_SET_CAC */
24595
24596 #ifdef SUPPORT_RSSI_SUM_REPORT
24597 int
24598 wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void *param)
24599 {
24600 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24601 wl_rssi_ant_mimo_t *get_param = (wl_rssi_ant_mimo_t *)param;
24602 rssi_ant_param_t *set_param = NULL;
24603 struct net_device *ifdev = NULL;
24604 char iobuf[WLC_IOCTL_SMLEN];
24605 int err = BCME_OK;
24606 int iftype = 0;
24607
24608 memset(iobuf, 0, WLC_IOCTL_SMLEN);
24609
24610 /* Check the interface type */
24611 ifdev = wl_get_netdev_by_name(cfg, ifname);
24612 if (ifdev == NULL) {
24613 WL_ERR(("Could not find net_device for ifname:%s\n", ifname));
24614 err = BCME_BADARG;
24615 goto fail;
24616 }
24617
24618 iftype = ifdev->ieee80211_ptr->iftype;
24619 if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO) {
24620 if (peer_mac) {
24621 set_param = (rssi_ant_param_t *)MALLOCZ(cfg->osh, sizeof(rssi_ant_param_t));
24622 err = wl_cfg80211_ether_atoe(peer_mac, &set_param->ea);
24623 if (!err) {
24624 WL_ERR(("Invalid Peer MAC format\n"));
24625 err = BCME_BADARG;
24626 goto fail;
24627 }
24628 } else {
24629 WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype));
24630 err = BCME_BADARG;
24631 goto fail;
24632 }
24633 }
24634
24635 err = wldev_iovar_getbuf(ifdev, "phy_rssi_ant", peer_mac ?
24636 (void *)&(set_param->ea) : NULL, peer_mac ? ETHER_ADDR_LEN : 0,
24637 (void *)iobuf, sizeof(iobuf), NULL);
24638 if (unlikely(err)) {
24639 WL_ERR(("Failed to get rssi info, err=%d\n", err));
24640 } else {
24641 memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t));
24642 if (get_param->count == 0) {
24643 WL_ERR(("Not supported on this chip\n"));
24644 err = BCME_UNSUPPORTED;
24645 }
24646 }
24647
24648 fail:
24649 if (set_param) {
24650 MFREE(cfg->osh, set_param, sizeof(rssi_ant_param_t));
24651 }
24652
24653 return err;
24654 }
24655
24656 int
24657 wl_get_rssi_logging(struct net_device *dev, void *param)
24658 {
24659 rssilog_get_param_t *get_param = (rssilog_get_param_t *)param;
24660 char iobuf[WLC_IOCTL_SMLEN];
24661 int err = BCME_OK;
24662
24663 memset(iobuf, 0, WLC_IOCTL_SMLEN);
24664 memset(get_param, 0, sizeof(*get_param));
24665 err = wldev_iovar_getbuf(dev, "rssilog", NULL, 0, (void *)iobuf,
24666 sizeof(iobuf), NULL);
24667 if (err) {
24668 WL_ERR(("Failed to get rssi logging info, err=%d\n", err));
24669 } else {
24670 memcpy(get_param, iobuf, sizeof(*get_param));
24671 }
24672
24673 return err;
24674 }
24675
24676 int
24677 wl_set_rssi_logging(struct net_device *dev, void *param)
24678 {
24679 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24680 rssilog_set_param_t *set_param = (rssilog_set_param_t *)param;
24681 int err;
24682
24683 err = wldev_iovar_setbuf(dev, "rssilog", set_param,
24684 sizeof(*set_param), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
24685 &cfg->ioctl_buf_sync);
24686 if (err) {
24687 WL_ERR(("Failed to set rssi logging param, err=%d\n", err));
24688 }
24689
24690 return err;
24691 }
24692 #endif /* SUPPORT_RSSI_SUM_REPORT */
24693
24694 #ifdef APSTA_RESTRICTED_CHANNEL
24695 #define CMD_BLOCK_CH "block_ch"
24696 #define BAND5G_CHANNELS_BLOCK_OP1 999
24697 #define BAND5G_CHANNELS_BLOCK_OP2 -1
24698
24699 bool
24700 wl_cfg80211_check_indoor_channels(struct net_device *ndev, int channel)
24701 {
24702 uint i = 0;
24703 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24704 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24705 wl_block_ch_t *block_ch = NULL;
24706 int data_len = WLC_IOCTL_SMLEN;
24707 bool ret = FALSE;
24708
24709 /* Get operation */
24710 block_ch = (wl_block_ch_t *)MALLOCZ(dhdp->osh, data_len);
24711 if (block_ch == NULL) {
24712 WL_ERR(("Fail to allocate memory\n"));
24713 goto exit;
24714 }
24715
24716 if (wl_cfg80211_read_indoor_channels(ndev, block_ch, data_len) < 0) {
24717 WL_ERR(("Failed to read indoor channels\n"));
24718 goto exit;
24719 }
24720
24721 if (block_ch->channel_num) {
24722 for (i = 0; i < block_ch->channel_num; i++) {
24723 if (channel == block_ch->channel[i]) {
24724 WL_ERR(("channel %d is in the indoor "
24725 "channel list\n", channel));
24726 ret = TRUE;
24727 break;
24728 }
24729 }
24730 }
24731
24732 exit:
24733 if (block_ch) {
24734 MFREE(dhdp->osh, block_ch, data_len);
24735 }
24736
24737 return ret;
24738 }
24739
24740 s32
24741 wl_cfg80211_read_indoor_channels(struct net_device *ndev, void *buf, int buflen)
24742 {
24743 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24744 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24745 wl_block_ch_t *iov_buf = NULL;
24746 wl_block_ch_t *block_ch = NULL;
24747 int data_len = 0;
24748 int err = BCME_OK;
24749
24750 if (!dhdp) {
24751 WL_ERR(("dhdp is NULL\n"));
24752 return BCME_ERROR;
24753 }
24754
24755 if (buflen < WLC_IOCTL_SMLEN) {
24756 WL_ERR(("Buf is too short, buflen=%d\n", buflen));
24757 return BCME_BUFTOOSHORT;
24758 }
24759
24760 data_len = OFFSETOF(wl_block_ch_t, channel);
24761 iov_buf = (wl_block_ch_t *)MALLOCZ(dhdp->osh, data_len);
24762 if (iov_buf == NULL) {
24763 WL_ERR(("Fail to allocate memory\n"));
24764 err = BCME_NOMEM;
24765 goto exit;
24766 }
24767
24768 iov_buf->version = WL_BLOCK_CHANNEL_VER_1;
24769 iov_buf->len = data_len;
24770 iov_buf->band = WF_CHAN_FACTOR_5_G;
24771 iov_buf->channel_num = 0;
24772
24773 err = wldev_iovar_getbuf(ndev, CMD_BLOCK_CH, iov_buf, data_len,
24774 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
24775 if (err < 0) {
24776 WL_ERR(("Setting block_ch failed with err=%d \n", err));
24777 goto exit;
24778 }
24779
24780 block_ch = (wl_block_ch_t *)(cfg->ioctl_buf);
24781 if (block_ch->version != WL_BLOCK_CHANNEL_VER_1) {
24782 WL_ERR(("Version mismatched! actual %d expected: %d\n",
24783 block_ch->version, WL_BLOCK_CHANNEL_VER_1));
24784 err = BCME_ERROR;
24785 } else {
24786 memcpy(buf, cfg->ioctl_buf, WLC_IOCTL_SMLEN);
24787 }
24788
24789 exit:
24790 if (iov_buf) {
24791 MFREE(dhdp->osh, iov_buf, data_len);
24792 }
24793
24794 return err;
24795 }
24796
24797 s32
24798 wl_cfg80211_set_indoor_channels(struct net_device *ndev, char *command, int total_len)
24799 {
24800 uint i = 0, j = 0;
24801 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24802 struct net_device *prmry_ndev = bcmcfg_to_prmry_ndev(cfg);
24803 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24804 wl_block_ch_t *block_ch = NULL;
24805 int block_ch_len = 0;
24806 int err = BCME_OK;
24807 ulong channel_num = 0;
24808 ulong channel = 0;
24809 char *pos, *token;
24810 u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
24811 wl_uint32_list_t *list;
24812 u32 n_valid_chan = 0;
24813 bool band5g_all_ch = FALSE;
24814
24815 BCM_REFERENCE(total_len);
24816
24817 pos = command;
24818 /* drop command */
24819 token = bcmstrtok(&pos, " ", NULL);
24820 /* number of channel */
24821 token = bcmstrtok(&pos, " ", NULL);
24822
24823 if (token == NULL) {
24824 err = BCME_BADARG;
24825 goto exit;
24826 }
24827
24828 channel_num = bcm_strtoul(token, NULL, 0);
24829 if (token == NULL) {
24830 err = BCME_BADARG;
24831 goto exit;
24832 }
24833
24834 if ((channel_num == BAND5G_CHANNELS_BLOCK_OP1) ||
24835 (channel_num == BAND5G_CHANNELS_BLOCK_OP2)) {
24836
24837 band5g_all_ch = TRUE;
24838
24839 if ((err = wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) < 0) {
24840 WL_ERR(("Failed to get valid channels - err %d\n", err));
24841 goto exit;
24842 } else {
24843 list = (wl_uint32_list_t *) chan_buf;
24844 n_valid_chan = dtoh32(list->count);
24845 channel_num = 0;
24846
24847 if (n_valid_chan > WL_NUMCHANNELS) {
24848 WL_ERR(("wrong n_valid_chan:%d\n", n_valid_chan));
24849 err = BCME_OUTOFRANGECHAN;
24850 goto exit;
24851 }
24852
24853 for (i = 0; i < n_valid_chan; i++) {
24854 if (CHANNEL_IS_5G(dtoh32(list->element[i]))) {
24855 channel_num++;
24856 }
24857 }
24858 if (channel_num == 0) {
24859 WL_ERR(("5G channels are not supported\n"));
24860 err = BCME_BADCHAN;
24861 goto exit;
24862 }
24863 }
24864 } else if (channel_num > MAXCHANNEL_NUM) {
24865 WL_ERR(("Out of Range. Max channel number is %d\n", MAXCHANNEL_NUM));
24866 err = BCME_RANGE;
24867 goto exit;
24868 }
24869
24870 block_ch_len = OFFSETOF(wl_block_ch_t, channel) + channel_num;
24871 block_ch = (wl_block_ch_t *)MALLOCZ(dhdp->osh, block_ch_len);
24872
24873 if (unlikely(!block_ch)) {
24874 WL_ERR(("Failed to allocate memory\n"));
24875 err = BCME_NOMEM;
24876 goto exit;
24877 }
24878
24879 block_ch->version = WL_BLOCK_CHANNEL_VER_1;
24880 block_ch->len = block_ch_len;
24881 block_ch->band = WF_CHAN_FACTOR_5_G;
24882 block_ch->channel_num = channel_num;
24883
24884 if (band5g_all_ch) {
24885 for (i = 0; i < n_valid_chan; i++) {
24886 channel = dtoh32(list->element[i]);
24887 if (CHANNEL_IS_5G(channel)) {
24888 block_ch->channel[j] = channel;
24889 j++;
24890 if (j >= channel_num) {
24891 break;
24892 }
24893 }
24894 }
24895 } else {
24896 for (i = 0; i < channel_num; i++) {
24897 token = bcmstrtok(&pos, " ", NULL);
24898 if (token == NULL) {
24899 err = BCME_BADARG;
24900 goto exit;
24901 }
24902 channel = bcm_strtoul(token, NULL, 0);
24903
24904 if (!CHANNEL_IS_5G(channel)) {
24905 WL_ERR(("%d is Invalid Channel!\n", block_ch->channel[i]));
24906 err = BCME_BADCHAN;
24907 goto exit;
24908 }
24909 block_ch->channel[i] = channel;
24910 }
24911 }
24912
24913 /* Abort any association before setting block channel */
24914 if (wl_get_drv_status(cfg, CONNECTING, prmry_ndev)) {
24915 wl_cfg80211_disassoc(prmry_ndev);
24916 }
24917
24918 /* Setting block channel list to fw */
24919 if ((err = wldev_iovar_setbuf(ndev, CMD_BLOCK_CH, block_ch, block_ch->len,
24920 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync))) {
24921 WL_ERR(("Setting block_ch failed with err = %d\n", err));
24922 goto exit;
24923 }
24924 exit:
24925 if (err == BCME_BADARG) {
24926 WL_ERR(("Failed due to Bad Argument!\n"));
24927 }
24928 if (block_ch) {
24929 MFREE(dhdp->osh, block_ch, block_ch_len);
24930 }
24931 return err;
24932 }
24933
24934 s32
24935 wl_cfg80211_get_indoor_channels(struct net_device *ndev, char *command, int total_len)
24936 {
24937 uint i = 0;
24938 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24939 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24940 wl_block_ch_t *block_ch = NULL;
24941 int data_len = WLC_IOCTL_SMLEN;
24942 int err = BCME_OK;
24943 char *pos;
24944
24945 pos = command;
24946
24947 /* Get operation */
24948 block_ch = (wl_block_ch_t *)MALLOCZ(dhdp->osh, data_len);
24949 if (block_ch == NULL) {
24950 WL_ERR(("Fail to allocate memory\n"));
24951 err = BCME_NOMEM;
24952 goto exit;
24953 }
24954
24955 err = wl_cfg80211_read_indoor_channels(ndev, block_ch, data_len);
24956 if (err < 0) {
24957 WL_ERR(("Failed to read indoor channels, err=%d\n", err));
24958 goto exit;
24959 }
24960
24961 if (block_ch->channel_num) {
24962 pos += snprintf(pos, total_len, "%d ", block_ch->channel_num);
24963 for (i = 0; i < block_ch->channel_num; i++) {
24964 pos += snprintf(pos, total_len, "%d ", block_ch->channel[i]);
24965 }
24966 err = (pos - command);
24967 }
24968
24969 exit:
24970 if (block_ch) {
24971 MFREE(dhdp->osh, block_ch, data_len);
24972 }
24973
24974 return err;
24975 }
24976 #endif /* APSTA_RESTRICTED_CHANNEL */
24977
24978 #ifdef DHD_LOG_DUMP
24979 /* Function to flush the FW preserve buffer content
24980 * The buffer content is sent to host in form of events.
24981 */
24982 void
24983 wl_flush_fw_log_buffer(struct net_device *dev, uint32 logset_mask)
24984 {
24985 int i;
24986 int err = 0;
24987 u8 buf[WLC_IOCTL_SMLEN] = {0};
24988 wl_el_set_params_t set_param;
24989
24990 /* Set the size of data to retrieve */
24991 memset(&set_param, 0, sizeof(set_param));
24992 set_param.size = WLC_IOCTL_SMLEN;
24993
24994 for (i = 0; i < WL_MAX_PRESERVE_BUFFER; i++)
24995 {
24996 if ((0x01u << i) & logset_mask) {
24997 set_param.set = i;
24998 err = wldev_iovar_setbuf(dev, "event_log_get", &set_param,
24999 sizeof(struct wl_el_set_params_s), buf, WLC_IOCTL_SMLEN,
25000 NULL);
25001 if (err) {
25002 WL_DBG(("Failed to get fw preserve logs, err=%d\n", err));
25003 }
25004 }
25005 }
25006 }
25007 #endif /* DHD_LOG_DUMP */
25008
25009 s32
25010 wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level)
25011 {
25012 /* configure verbose level for debugging */
25013 if (level) {
25014 /* Enable increased verbose */
25015 wl_dbg_level |= WL_DBG_DBG;
25016 } else {
25017 /* Disable */
25018 wl_dbg_level &= ~WL_DBG_DBG;
25019 }
25020 WL_INFORM(("debug verbose set to %d\n", level));
25021
25022 return BCME_OK;
25023 }
25024
25025 s32
25026 wl_cfg80211_check_for_nan_support(struct bcm_cfg80211 *cfg)
25027 {
25028 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
25029 if (((p2p_is_on(cfg)) && (wl_get_p2p_status(cfg, SCANNING) ||
25030 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1))) ||
25031 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE))
25032 {
25033 WL_ERR(("p2p/softap is enabled, cannot support nan\n"));
25034 return FALSE;
25035 }
25036 return TRUE;
25037 }
25038
25039 uint8 wl_cfg80211_get_bus_state(struct bcm_cfg80211 *cfg)
25040 {
25041 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
25042 WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
25043 dhd->hang_was_sent, dhd->busstate));
25044 return ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent);
25045 }
25046
25047 #ifdef WL_WPS_SYNC
25048 static void wl_wps_reauth_timeout(unsigned long data)
25049 {
25050 struct net_device *ndev = (struct net_device *)data;
25051 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25052 s32 inst;
25053 unsigned long flags;
25054
25055 spin_lock_irqsave(&cfg->wps_sync, flags);
25056 inst = wl_get_wps_inst_match(cfg, ndev);
25057 if (inst >= 0) {
25058 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n",
25059 ndev->name, inst, cfg->wps_session[inst].state));
25060 if (cfg->wps_session[inst].state == WPS_STATE_REAUTH_WAIT) {
25061 /* Session should get deleted from success (linkup) or
25062 * deauth case. Just in case, link reassoc failed, clear
25063 * state here.
25064 */
25065 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n",
25066 ndev->name, inst));
25067 cfg->wps_session[inst].state = WPS_STATE_IDLE;
25068 cfg->wps_session[inst].in_use = false;
25069 }
25070 }
25071 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25072 }
25073
25074 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg)
25075 {
25076 /* Only two instances are supported as of now. one for
25077 * infra STA and other for infra STA/GC.
25078 */
25079 int i = 0;
25080 struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
25081
25082 spin_lock_init(&cfg->wps_sync);
25083 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
25084 /* Init scan_timeout timer */
25085 init_timer(&cfg->wps_session[i].timer);
25086 cfg->wps_session[i].timer.data = (unsigned long) pdev;
25087 cfg->wps_session[i].timer.function = wl_wps_reauth_timeout;
25088 cfg->wps_session[i].in_use = false;
25089 cfg->wps_session[i].state = WPS_STATE_IDLE;
25090 }
25091 }
25092
25093 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg)
25094 {
25095 int i = 0;
25096
25097 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
25098 cfg->wps_session[i].in_use = false;
25099 cfg->wps_session[i].state = WPS_STATE_IDLE;
25100 if (timer_pending(&cfg->wps_session[i].timer)) {
25101 del_timer_sync(&cfg->wps_session[i].timer);
25102 }
25103 }
25104
25105 }
25106
25107 static s32
25108 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg)
25109 {
25110 int i;
25111
25112 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
25113 if (!cfg->wps_session[i].in_use) {
25114 return i;
25115 }
25116 }
25117 return BCME_ERROR;
25118 }
25119
25120 static s32
25121 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev)
25122 {
25123 int i;
25124
25125 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
25126 if ((cfg->wps_session[i].in_use) &&
25127 (ndev == cfg->wps_session[i].ndev)) {
25128 return i;
25129 }
25130 }
25131
25132 return BCME_ERROR;
25133 }
25134
25135 static s32
25136 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *mac_addr)
25137 {
25138 s32 inst;
25139 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25140 unsigned long flags;
25141
25142 spin_lock_irqsave(&cfg->wps_sync, flags);
25143 /* Fetch and initialize a wps instance */
25144 inst = wl_get_free_wps_inst(cfg);
25145 if (inst == BCME_ERROR) {
25146 WL_ERR(("[WPS] No free insance\n"));
25147 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25148 return BCME_ERROR;
25149 }
25150 cfg->wps_session[inst].in_use = true;
25151 cfg->wps_session[inst].state = WPS_STATE_STARTED;
25152 cfg->wps_session[inst].ndev = ndev;
25153 cfg->wps_session[inst].mode = mode;
25154 memcpy(cfg->wps_session[inst].peer_mac, mac_addr, ETH_ALEN);
25155 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25156
25157 WL_INFORM_MEM(("[%s][WPS] session created. Peer: " MACDBG "\n",
25158 ndev->name, MAC2STRDBG(mac_addr)));
25159 return BCME_OK;
25160 }
25161
25162 static void
25163 wl_wps_session_del(struct net_device *ndev)
25164 {
25165 s32 inst;
25166 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25167 unsigned long flags;
25168 u16 cur_state;
25169
25170 spin_lock_irqsave(&cfg->wps_sync, flags);
25171
25172 /* Get current instance for the given ndev */
25173 inst = wl_get_wps_inst_match(cfg, ndev);
25174 if (inst == BCME_ERROR) {
25175 WL_DBG(("[WPS] instance match NOT found\n"));
25176 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25177 return;
25178 }
25179
25180 cur_state = cfg->wps_session[inst].state;
25181 if (cur_state != WPS_STATE_DONE) {
25182 WL_DBG(("[WPS] wrong state:%d\n", cur_state));
25183 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25184 return;
25185 }
25186
25187 /* Mark this as unused */
25188 cfg->wps_session[inst].in_use = false;
25189 cfg->wps_session[inst].state = WPS_STATE_IDLE;
25190 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25191
25192 /* Ensure this API is called from sleepable context. */
25193 if (timer_pending(&cfg->wps_session[inst].timer)) {
25194 del_timer_sync(&cfg->wps_session[inst].timer);
25195 }
25196
25197 WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev->name));
25198 }
25199
25200 static void
25201 wl_wps_handle_ifdel(struct net_device *ndev)
25202 {
25203 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25204 unsigned long flags;
25205 u16 cur_state;
25206 s32 inst;
25207
25208 spin_lock_irqsave(&cfg->wps_sync, flags);
25209 inst = wl_get_wps_inst_match(cfg, ndev);
25210 if (inst == BCME_ERROR) {
25211 WL_DBG(("[WPS] instance match NOT found\n"));
25212 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25213 return;
25214 }
25215 cur_state = cfg->wps_session[inst].state;
25216 cfg->wps_session[inst].state = WPS_STATE_DONE;
25217 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25218
25219 WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev->name, cur_state));
25220 if (cur_state > WPS_STATE_IDLE) {
25221 wl_wps_session_del(ndev);
25222 }
25223 }
25224
25225 static s32
25226 wl_wps_handle_sta_linkdown(struct net_device *ndev, u16 inst)
25227 {
25228 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25229 unsigned long flags;
25230 u16 cur_state;
25231 bool wps_done = false;
25232
25233 spin_lock_irqsave(&cfg->wps_sync, flags);
25234 cur_state = cfg->wps_session[inst].state;
25235 if (cur_state == WPS_STATE_REAUTH_WAIT) {
25236 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25237 wl_clr_drv_status(cfg, CONNECTED, ndev);
25238 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
25239 WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev->name));
25240 /* Drop the link down event while we are waiting for reauth */
25241 return BCME_UNSUPPORTED;
25242 } else if (cur_state == WPS_STATE_STARTED) {
25243 /* Link down before reaching EAP-FAIL. End WPS session */
25244 cfg->wps_session[inst].state = WPS_STATE_DONE;
25245 wps_done = true;
25246 WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev->name));
25247 } else {
25248 WL_DBG(("[%s][WPS] link down in state:%d\n",
25249 ndev->name, cur_state));
25250 }
25251
25252 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25253
25254 if (wps_done) {
25255 wl_wps_session_del(ndev);
25256 }
25257 return BCME_OK;
25258 }
25259
25260 static s32
25261 wl_wps_handle_peersta_linkdown(struct net_device *ndev, u16 inst, const u8 *peer_mac)
25262 {
25263 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25264 unsigned long flags;
25265 u16 cur_state;
25266 s32 ret = BCME_OK;
25267 bool wps_done = false;
25268
25269 spin_lock_irqsave(&cfg->wps_sync, flags);
25270 cur_state = cfg->wps_session[inst].state;
25271
25272 if (!peer_mac) {
25273 WL_ERR(("Invalid arg\n"));
25274 ret = BCME_ERROR;
25275 goto exit;
25276 }
25277
25278 /* AP/GO can have multiple clients. so validate peer_mac addr
25279 * and ensure states are updated only for right peer.
25280 */
25281 if (memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25282 /* Mac addr not matching. Ignore. */
25283 WL_DBG(("[%s][WPS] No active WPS session"
25284 "for the peer:" MACDBG "\n", ndev->name, MAC2STRDBG(peer_mac)));
25285 ret = BCME_OK;
25286 goto exit;
25287 }
25288 if (cur_state == WPS_STATE_REAUTH_WAIT) {
25289 WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
25290 " Peer: " MACDBG "\n",
25291 ndev->name, MAC2STRDBG(peer_mac)));
25292 #ifdef NOT_YET
25293 /* Link down during REAUTH state is expected. However,
25294 * if this is send up, hostapd statemachine issues a
25295 * deauth down and that may pre-empt WPS reauth state
25296 * at GC.
25297 */
25298 WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore."
25299 " for client:" MACDBG "\n",
25300 ndev->name, MAC2STRDBG(peer_mac)));
25301 ret = BCME_UNSUPPORTED;
25302 #endif // endif
25303 } else if (cur_state == WPS_STATE_STARTED) {
25304 /* Link down before reaching REAUTH_WAIT state. WPS
25305 * session ended.
25306 */
25307 cfg->wps_session[inst].state = WPS_STATE_DONE;
25308 WL_INFORM_MEM(("[%s][WPS] link down after wps start"
25309 " client:" MACDBG "\n",
25310 ndev->name, MAC2STRDBG(peer_mac)));
25311 wps_done = true;
25312 /* since we have freed lock above, return from here */
25313 ret = BCME_OK;
25314 } else {
25315 WL_ERR(("[%s][WPS] Unsupported state:%d",
25316 ndev->name, cur_state));
25317 ret = BCME_ERROR;
25318 }
25319 exit:
25320 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25321 if (wps_done) {
25322 wl_wps_session_del(ndev);
25323 }
25324 return ret;
25325 }
25326
25327 static s32
25328 wl_wps_handle_sta_linkup(struct net_device *ndev, u16 inst)
25329 {
25330 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25331 unsigned long flags;
25332 u16 cur_state;
25333 s32 ret = BCME_OK;
25334 bool wps_done = false;
25335
25336 spin_lock_irqsave(&cfg->wps_sync, flags);
25337 cur_state = cfg->wps_session[inst].state;
25338 if (cur_state == WPS_STATE_REAUTH_WAIT) {
25339 /* WPS session succeeded. del session. */
25340 cfg->wps_session[inst].state = WPS_STATE_DONE;
25341 wps_done = true;
25342 WL_INFORM_MEM(("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev->name));
25343 ret = BCME_OK;
25344 } else {
25345 WL_ERR(("[%s][WPS] unexpected link up in state:%d \n",
25346 ndev->name, cur_state));
25347 ret = BCME_ERROR;
25348 }
25349 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25350 if (wps_done) {
25351 wl_wps_session_del(ndev);
25352 }
25353 return ret;
25354 }
25355
25356 static s32
25357 wl_wps_handle_peersta_linkup(struct net_device *ndev, u16 inst, const u8 *peer_mac)
25358 {
25359 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25360 unsigned long flags;
25361 u16 cur_state;
25362 s32 ret = BCME_OK;
25363
25364 spin_lock_irqsave(&cfg->wps_sync, flags);
25365 cur_state = cfg->wps_session[inst].state;
25366
25367 /* For AP case, check whether call came for right peer */
25368 if (!peer_mac ||
25369 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25370 WL_ERR(("[WPS] macaddr mismatch\n"));
25371 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25372 /* Mac addr not matching. Ignore. */
25373 return BCME_ERROR;
25374 }
25375
25376 if (cur_state == WPS_STATE_REAUTH_WAIT) {
25377 WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev->name));
25378 ret = BCME_OK;
25379 } else {
25380 WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
25381 ndev->name, cur_state));
25382 ret = BCME_ERROR;
25383 }
25384
25385 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25386
25387 return ret;
25388 }
25389
25390 static s32
25391 wl_wps_handle_authorize(struct net_device *ndev, u16 inst, const u8 *peer_mac)
25392 {
25393 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25394 unsigned long flags;
25395 u16 cur_state;
25396 bool wps_done = false;
25397 s32 ret = BCME_OK;
25398
25399 spin_lock_irqsave(&cfg->wps_sync, flags);
25400 cur_state = cfg->wps_session[inst].state;
25401
25402 /* For AP case, check whether call came for right peer */
25403 if (!peer_mac ||
25404 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25405 WL_ERR(("[WPS] macaddr mismatch\n"));
25406 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25407 /* Mac addr not matching. Ignore. */
25408 return BCME_ERROR;
25409 }
25410
25411 if (cur_state == WPS_STATE_REAUTH_WAIT) {
25412 /* WPS session succeeded. del session. */
25413 cfg->wps_session[inst].state = WPS_STATE_DONE;
25414 wps_done = true;
25415 WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev->name));
25416 ret = BCME_OK;
25417 } else {
25418 WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
25419 ndev->name, cur_state));
25420 ret = BCME_ERROR;
25421 }
25422
25423 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25424 if (wps_done) {
25425 wl_wps_session_del(ndev);
25426 }
25427 return ret;
25428 }
25429
25430 static s32
25431 wl_wps_handle_reauth(struct net_device *ndev, u16 inst, const u8 *peer_mac)
25432 {
25433 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25434 unsigned long flags;
25435 u16 cur_state;
25436 u16 mode;
25437 s32 ret = BCME_OK;
25438
25439 spin_lock_irqsave(&cfg->wps_sync, flags);
25440 cur_state = cfg->wps_session[inst].state;
25441 mode = cfg->wps_session[inst].mode;
25442
25443 if (cur_state == WPS_STATE_STARTED) {
25444 /* Move to reauth wait */
25445 cfg->wps_session[inst].state = WPS_STATE_REAUTH_WAIT;
25446 /* Use ndev to find the wps instance which fired the timer */
25447 cfg->wps_session[inst].timer.data = (unsigned long) ndev;
25448 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25449 mod_timer(&cfg->wps_session[inst].timer,
25450 jiffies + msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT));
25451 WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG "\n",
25452 ndev->name, mode, MAC2STRDBG(peer_mac)));
25453 return BCME_OK;
25454 } else {
25455 /* 802.1x cases */
25456 WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev->name));
25457 }
25458 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25459 return ret;
25460 }
25461
25462 static s32
25463 wl_wps_handle_disconnect(struct net_device *ndev, u16 inst, const u8 *peer_mac)
25464 {
25465 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25466 unsigned long flags;
25467 u16 cur_state;
25468 s32 ret = BCME_OK;
25469
25470 spin_lock_irqsave(&cfg->wps_sync, flags);
25471 cur_state = cfg->wps_session[inst].state;
25472 /* If Disconnect command comes from user space for STA/GC,
25473 * respond with event without waiting for event from fw as
25474 * it would be dropped by the WPS_SYNC code.
25475 */
25476 if (cur_state == WPS_STATE_REAUTH_WAIT) {
25477 if (ETHER_ISBCAST(peer_mac)) {
25478 WL_DBG(("[WPS] Bcast peer. Do nothing.\n"));
25479 } else {
25480 /* Notify link down */
25481 CFG80211_DISCONNECTED(ndev,
25482 WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
25483 true, GFP_ATOMIC);
25484 }
25485 } else {
25486 WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
25487 ndev->name, cur_state));
25488 ret = BCME_UNSUPPORTED;
25489 }
25490 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25491 return ret;
25492 }
25493
25494 static s32
25495 wl_wps_handle_disconnect_client(struct net_device *ndev, u16 inst, const u8 *peer_mac)
25496 {
25497 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25498 unsigned long flags;
25499 u16 cur_state;
25500 s32 ret = BCME_OK;
25501 bool wps_done = false;
25502
25503 spin_lock_irqsave(&cfg->wps_sync, flags);
25504 cur_state = cfg->wps_session[inst].state;
25505 /* For GO/AP, ignore disconnect client during reauth state */
25506 if (cur_state == WPS_STATE_REAUTH_WAIT) {
25507 if (ETHER_ISBCAST(peer_mac)) {
25508 /* If there is broadcast deauth, then mark wps session as ended */
25509 cfg->wps_session[inst].state = WPS_STATE_DONE;
25510 wps_done = true;
25511 WL_INFORM_MEM(("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev->name));
25512 ret = BCME_OK;
25513 goto exit;
25514 } else if (!(memcmp(cfg->wps_session[inst].peer_mac,
25515 peer_mac, ETH_ALEN))) {
25516 WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev->name));
25517 ret = BCME_UNSUPPORTED;
25518 }
25519 }
25520
25521 exit:
25522 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25523 if (wps_done) {
25524 wl_wps_session_del(ndev);
25525 }
25526 return ret;
25527 }
25528
25529 static s32
25530 wl_wps_handle_connect_fail(struct net_device *ndev, u16 inst)
25531 {
25532 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25533 unsigned long flags;
25534 u16 cur_state;
25535 bool wps_done = false;
25536
25537 spin_lock_irqsave(&cfg->wps_sync, flags);
25538 cur_state = cfg->wps_session[inst].state;
25539 if (cur_state == WPS_STATE_REAUTH_WAIT) {
25540 cfg->wps_session[inst].state = WPS_STATE_DONE;
25541 wps_done = true;
25542 WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n",
25543 ndev->name));
25544 } else {
25545 WL_ERR(("[%s][WPS] Connect fail. state:%d\n",
25546 ndev->name, cur_state));
25547 }
25548 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25549 if (wps_done) {
25550 wl_wps_session_del(ndev);
25551 }
25552 return BCME_OK;
25553 }
25554
25555 static s32
25556 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac)
25557 {
25558 s32 inst;
25559 u16 mode;
25560 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25561 s32 ret = BCME_ERROR;
25562 unsigned long flags;
25563
25564 spin_lock_irqsave(&cfg->wps_sync, flags);
25565 /* Get current instance for the given ndev */
25566 inst = wl_get_wps_inst_match(cfg, ndev);
25567 if (inst == BCME_ERROR) {
25568 /* No active WPS session. Do Nothing. */
25569 WL_DBG(("[%s][WPS] No matching instance.\n", ndev->name));
25570 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25571 return BCME_OK;
25572 }
25573 mode = cfg->wps_session[inst].mode;
25574 spin_unlock_irqrestore(&cfg->wps_sync, flags);
25575
25576 WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG "\n",
25577 ndev->name, state, mode, MAC2STRDBG(peer_mac)));
25578
25579 switch (state) {
25580 case WPS_STATE_M8_RECVD:
25581 {
25582 /* Occasionally, due to race condition between ctrl
25583 * and data path, deauth ind is recvd before EAP-FAIL.
25584 * Ignore deauth ind before EAP-FAIL
25585 * So move to REAUTH WAIT on receiving M8 on GC and
25586 * ignore deauth ind before EAP-FAIL till 'x' timeout.
25587 * Kickoff a timer to monitor reauth status.
25588 */
25589 if (mode == WL_MODE_BSS) {
25590 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
25591 } else {
25592 /* Nothing to be done for AP/GO mode */
25593 ret = BCME_OK;
25594 }
25595 break;
25596 }
25597 case WPS_STATE_EAP_FAIL:
25598 {
25599 /* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
25600 * Kickoff a timer to monitor reauth status
25601 */
25602 if (mode == WL_MODE_AP) {
25603 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
25604 } else {
25605 /* Nothing to be done for STA/GC mode */
25606 ret = BCME_OK;
25607 }
25608 break;
25609 }
25610 case WPS_STATE_LINKDOWN:
25611 {
25612 if (mode == WL_MODE_BSS) {
25613 ret = wl_wps_handle_sta_linkdown(ndev, inst);
25614 } else if (mode == WL_MODE_AP) {
25615 /* Take action only for matching peer mac */
25616 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25617 ret = wl_wps_handle_peersta_linkdown(ndev, inst, peer_mac);
25618 }
25619 }
25620 break;
25621 }
25622 case WPS_STATE_LINKUP:
25623 {
25624 if (mode == WL_MODE_BSS) {
25625 wl_wps_handle_sta_linkup(ndev, inst);
25626 } else if (mode == WL_MODE_AP) {
25627 /* Take action only for matching peer mac */
25628 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25629 wl_wps_handle_peersta_linkup(ndev, inst, peer_mac);
25630 }
25631 }
25632 break;
25633 }
25634 case WPS_STATE_DISCONNECT_CLIENT:
25635 {
25636 /* Disconnect STA/GC command from user space */
25637 if (mode == WL_MODE_AP) {
25638 ret = wl_wps_handle_disconnect_client(ndev, inst, peer_mac);
25639 } else {
25640 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
25641 }
25642 break;
25643 }
25644 case WPS_STATE_DISCONNECT:
25645 {
25646 /* Disconnect command on STA/GC interface */
25647 if (mode == WL_MODE_BSS) {
25648 ret = wl_wps_handle_disconnect(ndev, inst, peer_mac);
25649 }
25650 break;
25651 }
25652 case WPS_STATE_CONNECT_FAIL:
25653 {
25654 if (mode == WL_MODE_BSS) {
25655 ret = wl_wps_handle_connect_fail(ndev, inst);
25656 } else {
25657 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
25658 }
25659 break;
25660 }
25661 case WPS_STATE_AUTHORIZE:
25662 {
25663 if (mode == WL_MODE_AP) {
25664 /* Take action only for matching peer mac */
25665 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25666 wl_wps_handle_authorize(ndev, inst, peer_mac);
25667 } else {
25668 WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
25669 }
25670 }
25671 break;
25672 }
25673
25674 default:
25675 WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state, mode));
25676 ret = BCME_ERROR;
25677 }
25678
25679 return ret;
25680 }
25681
25682 #define EAP_EXP_ATTRIB_DATA_OFFSET 14
25683 void
25684 wl_handle_wps_states(struct net_device *ndev, u8 *pkt, u16 len, bool direction)
25685 {
25686 eapol_header_t *eapol_hdr;
25687 bool tx_packet = direction;
25688 u16 eapol_type;
25689 u16 mode;
25690 u8 *peer_mac;
25691
25692 if (!ndev || !pkt) {
25693 WL_ERR(("[WPS] Invalid arg\n"));
25694 return;
25695 }
25696
25697 if (len < (ETHER_HDR_LEN + EAPOL_HDR_LEN)) {
25698 WL_ERR(("[WPS] Invalid len\n"));
25699 return;
25700 }
25701
25702 eapol_hdr = (eapol_header_t *)pkt;
25703 eapol_type = eapol_hdr->type;
25704
25705 peer_mac = tx_packet ? eapol_hdr->eth.ether_dhost :
25706 eapol_hdr->eth.ether_shost;
25707 /*
25708 * The implementation assumes only one WPS session would be active
25709 * per interface at a time. Even for hostap, the wps_pin session
25710 * is limited to one enrollee/client at a time. A session is marked
25711 * started on WSC_START and gets cleared from below contexts
25712 * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
25713 * b) Link up following EAP-FAIL. (success case)
25714 * c) Link up timeout after EAP-FAIL. (Fail case)
25715 */
25716
25717 if (eapol_type == EAP_PACKET) {
25718 wl_eap_header_t *eap;
25719
25720 if (len > sizeof(*eap)) {
25721 eap = (wl_eap_header_t *)(pkt + ETHER_HDR_LEN + EAPOL_HDR_LEN);
25722 if (eap->type == EAP_EXPANDED_TYPE) {
25723 wl_eap_exp_t *exp = (wl_eap_exp_t *)eap->data;
25724 if (eap->length > EAP_EXP_HDR_MIN_LENGTH) {
25725 /* opcode is at fixed offset */
25726 u8 opcode = exp->opcode;
25727 u16 eap_len = ntoh16(eap->length);
25728
25729 WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
25730 ndev->name, opcode, eap_len));
25731 if (opcode == EAP_WSC_MSG) {
25732 const u8 *msg;
25733 const u8* parse_buf = exp->data;
25734 /* Check if recvd pkt is fragmented */
25735 if ((!tx_packet) &&
25736 (exp->flags &
25737 EAP_EXP_FLAGS_FRAGMENTED_DATA)) {
25738 if ((eap_len - EAP_EXP_ATTRIB_DATA_OFFSET)
25739 > 2) {
25740 parse_buf +=
25741 EAP_EXP_FRAGMENT_LEN_OFFSET;
25742 eap_len -=
25743 EAP_EXP_FRAGMENT_LEN_OFFSET;
25744 WL_DBG(("Rcvd EAP"
25745 " fragmented pkt\n"));
25746 } else {
25747 /* If recvd pkt is fragmented
25748 * and does not have
25749 * length field drop the packet.
25750 */
25751 return;
25752 }
25753 }
25754
25755 msg = wl_find_attribute(parse_buf,
25756 (eap_len - EAP_EXP_ATTRIB_DATA_OFFSET),
25757 EAP_ATTRIB_MSGTYPE);
25758 if (unlikely(!msg)) {
25759 WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
25760 } else if ((*msg == EAP_WSC_MSG_M8) &&
25761 !tx_packet) {
25762 WL_INFORM_MEM(("[%s][WPS] M8\n",
25763 ndev->name));
25764 wl_wps_session_update(ndev,
25765 WPS_STATE_M8_RECVD, peer_mac);
25766 } else {
25767 WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n",
25768 ndev->name, *msg));
25769 }
25770 } else if (opcode == EAP_WSC_START) {
25771 /* WSC session started. WSC_START - Tx from GO/AP.
25772 * Session will be deleted on successful link up or
25773 * on failure (deauth context)
25774 */
25775 mode = tx_packet ? WL_MODE_AP : WL_MODE_BSS;
25776 wl_wps_session_add(ndev, mode, peer_mac);
25777 WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
25778 ndev->name, mode));
25779 } else if (opcode == EAP_WSC_DONE) {
25780 /* WSC session done. TX on STA/GC. RX on GO/AP
25781 * On devices where config file save fails, it may
25782 * return WPS_NAK with config_error:0. But the
25783 * connection would still proceed. Hence don't let
25784 * state machine depend on WSC DONE.
25785 */
25786 WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev->name));
25787 }
25788 }
25789 }
25790
25791 if (eap->code == EAP_CODE_FAILURE) {
25792 /* EAP_FAIL */
25793 WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev->name));
25794 wl_wps_session_update(ndev,
25795 WPS_STATE_EAP_FAIL, peer_mac);
25796 }
25797 }
25798 }
25799 }
25800 #endif /* WL_WPS_SYNC */
25801
25802 const u8 *
25803 wl_find_attribute(const u8 *buf, u16 len, u16 element_id)
25804 {
25805 const u8 *attrib;
25806 u16 attrib_id;
25807 u16 attrib_len;
25808
25809 if (!buf) {
25810 WL_ERR(("buf null\n"));
25811 return NULL;
25812 }
25813
25814 attrib = buf;
25815 while (len >= 4) {
25816 /* attribute id */
25817 attrib_id = *attrib++ << 8;
25818 attrib_id |= *attrib++;
25819 len -= 2;
25820
25821 /* 2-byte little endian */
25822 attrib_len = *attrib++ << 8;
25823 attrib_len |= *attrib++;
25824
25825 len -= 2;
25826 if (attrib_id == element_id) {
25827 /* This will point to start of subelement attrib after
25828 * attribute id & len
25829 */
25830 return attrib;
25831 }
25832 if (len > attrib_len) {
25833 len -= attrib_len; /* for the remaining subelt fields */
25834 WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n",
25835 attrib_id, attrib_len, len));
25836
25837 /* Go to next subelement */
25838 attrib += attrib_len;
25839 } else {
25840 WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n",
25841 attrib_id, attrib_len));
25842 return NULL;
25843 }
25844 }
25845 return NULL;
25846 }
25847
25848 static const u8 *
25849 wl_retrieve_wps_attribute(const u8 *buf, u16 element_id)
25850 {
25851 const wl_wps_ie_t *ie = NULL;
25852 u16 len = 0;
25853 const u8 *attrib;
25854
25855 if (!buf) {
25856 WL_ERR(("WPS IE not present"));
25857 return 0;
25858 }
25859
25860 ie = (const wl_wps_ie_t*) buf;
25861 len = ie->len;
25862
25863 /* Point subel to the P2P IE's subelt field.
25864 * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
25865 */
25866 attrib = ie->attrib;
25867 len -= 4; /* exclude OUI + OUI_TYPE */
25868
25869 /* Search for attrib */
25870 return wl_find_attribute(attrib, len, element_id);
25871 }
25872
25873 #define WPS_ATTR_REQ_TYPE 0x103a
25874 #define WPS_REQ_TYPE_ENROLLEE 0x01
25875 bool
25876 wl_is_wps_enrollee_active(struct net_device *ndev, const u8 *ie_ptr, u16 len)
25877 {
25878 const u8 *ie;
25879 const u8 *attrib;
25880
25881 if ((ie = (const u8 *)wl_cfgp2p_find_wpsie(ie_ptr, len)) == NULL) {
25882 WL_DBG(("WPS IE not present. Do nothing.\n"));
25883 return false;
25884 }
25885
25886 if ((attrib = wl_retrieve_wps_attribute(ie, WPS_ATTR_REQ_TYPE)) == NULL) {
25887 WL_DBG(("WPS_ATTR_REQ_TYPE not found!\n"));
25888 return false;
25889 }
25890
25891 if (*attrib == WPS_REQ_TYPE_ENROLLEE) {
25892 WL_INFORM_MEM(("WPS Enrolle Active\n"));
25893 return true;
25894 } else {
25895 WL_DBG(("WPS_REQ_TYPE:%d\n", *attrib));
25896 }
25897
25898 return false;
25899 }
25900
25901 #ifdef USE_WFA_CERT_CONF
25902 extern int g_frameburst;
25903 #endif /* USE_WFA_CERT_CONF */
25904
25905 int
25906 wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable)
25907 {
25908 int ret = BCME_OK;
25909 int val = enable ? 1 : 0;
25910
25911 #ifdef USE_WFA_CERT_CONF
25912 if (!g_frameburst) {
25913 WL_DBG(("Skip setting frameburst\n"));
25914 return 0;
25915 }
25916 #endif /* USE_WFA_CERT_CONF */
25917
25918 WL_DBG(("Set frameburst %d\n", val));
25919 ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg), WLC_SET_FAKEFRAG, &val, sizeof(val));
25920 if (ret < 0) {
25921 WL_ERR(("Failed set frameburst, ret=%d\n", ret));
25922 } else {
25923 WL_INFORM_MEM(("frameburst is %s\n", enable ? "enabled" : "disabled"));
25924 }
25925
25926 return ret;
25927 }