1 /*
2 * Wifi Virtual Interface implementaion
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Dual:>>
22 */
23 /* */
24
25 #include <typedefs.h>
26 #include <linuxver.h>
27 #include <linux/kernel.h>
28
29 #include <bcmutils.h>
30 #include <bcmstdlib_s.h>
31 #include <bcmwifi_channels.h>
32 #include <bcmendian.h>
33 #include <ethernet.h>
34 #ifdef WL_WPS_SYNC
35 #include <eapol.h>
36 #endif /* WL_WPS_SYNC */
37 #include <802.11.h>
38 #include <bcmiov.h>
39 #include <linux/if_arp.h>
40 #include <asm/uaccess.h>
41
42 #include <ethernet.h>
43 #include <linux/kernel.h>
44 #include <linux/kthread.h>
45 #include <linux/netdevice.h>
46 #include <linux/sched.h>
47 #include <linux/etherdevice.h>
48 #include <linux/wireless.h>
49 #include <linux/ieee80211.h>
50 #include <linux/wait.h>
51 #include <net/cfg80211.h>
52 #include <net/rtnetlink.h>
53
54 #include <wlioctl.h>
55 #include <bcmevent.h>
56 #include <wldev_common.h>
57 #include <wl_cfg80211.h>
58 #include <wl_cfgp2p.h>
59 #include <wl_cfgscan.h>
60 #include <wl_cfgvif.h>
61 #include <bcmdevs.h>
62 #include <bcmdevs_legacy.h>
63 #ifdef WL_FILS
64 #include <fils.h>
65 #include <frag.h>
66 #endif /* WL_FILS */
67
68 #ifdef OEM_ANDROID
69 #include <wl_android.h>
70 #endif
71
72 #if defined(BCMDONGLEHOST)
73 #include <dngl_stats.h>
74 #include <dhd.h>
75 #include <dhd_linux.h>
76 #include <dhd_linux_pktdump.h>
77 #include <dhd_debug.h>
78 #include <dhdioctl.h>
79 #include <wlioctl.h>
80 #include <dhd_cfg80211.h>
81 #include <dhd_bus.h>
82 #include <wl_cfgvendor.h>
83 #endif /* defined(BCMDONGLEHOST) */
84
85 #ifdef WL_NAN
86 #include <wl_cfgnan.h>
87 #endif /* WL_NAN */
88
89 #ifdef BCMPCIE
90 #include <dhd_flowring.h>
91 #endif
92 #if defined(BIGDATA_SOFTAP) || defined(DHD_ENABLE_BIGDATA_LOGGING)
93 #include <wl_bigdata.h>
94 #endif /* BIGDATA_SOFTAP || DHD_ENABLE_BIGDATA_LOGGING */
95 #include <dhd_config.h>
96
97 #define MAX_VIF_OFFSET 15
98 #define MAX_WAIT_TIME 1500
99
100 #if !defined(BCMDONGLEHOST)
101 #ifdef ntoh32
102 #undef ntoh32
103 #endif
104 #ifdef ntoh16
105 #undef ntoh16
106 #endif
107 #ifdef htod32
108 #undef htod32
109 #endif
110 #ifdef htod16
111 #undef htod16
112 #endif
113 #define ntoh32(i) (i)
114 #define ntoh16(i) (i)
115 #define htod32(i) (i)
116 #define htod16(i) (i)
117 #define DNGL_FUNC(func, parameters)
118 #else
119 #define DNGL_FUNC(func, parameters) func parameters
120 #define COEX_DHCP
121
122 #endif /* defined(BCMDONGLEHOST) */
123
124 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
125 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
126 _Pragma("GCC diagnostic pop")
127 #endif
128
129 /* SoftAP related parameters */
130 #define DEFAULT_2G_SOFTAP_CHANNEL 1
131 #define DEFAULT_2G_SOFTAP_CHANSPEC 0x1006
132 #define DEFAULT_5G_SOFTAP_CHANNEL 149
133
134 #define MAX_VNDR_OUI_STR_LEN 256u
135 #define VNDR_OUI_STR_LEN 10u
136 #define DOT11_DISCONNECT_RC 2u
137
138 #if defined(WL_FW_OCE_AP_SELECT)
139 static bool
140 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
141
142 /* Check whether the given IE looks like WFA OCE IE. */
143 #define wl_cfgoce_is_oce_ie(ie, tlvs, len) wl_cfgoce_has_ie(ie, tlvs, len, \
144 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_MBO_OCE)
145
146 /* Is any of the tlvs the expected entry? If
147 * not update the tlvs buffer pointer/length.
148 */
149 static bool
wl_cfgoce_has_ie(const u8 * ie,const u8 ** tlvs,u32 * tlvs_len,const u8 * oui,u32 oui_len,u8 type)150 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
151 {
152 /* If the contents match the OUI and the type */
153 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
154 !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
155 type == ie[TLV_BODY_OFF + oui_len]) {
156 return TRUE;
157 }
158
159 return FALSE;
160 }
161 #endif /* WL_FW_OCE_AP_SELECT */
162
163 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
164
165 #ifdef SUPPORT_AP_BWCTRL
166 static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ,
167 WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ };
168 #endif /* SUPPORT_AP_BWCTRL */
169
170 #if !defined(BCMDONGLEHOST)
171 /* Wake lock are used in Android only, which is dongle based as of now */
172 #define DHD_OS_WAKE_LOCK(pub)
173 #define DHD_OS_WAKE_UNLOCK(pub)
174 #define DHD_EVENT_WAKE_LOCK(pub)
175 #define DHD_EVENT_WAKE_UNLOCK(pub)
176 #define DHD_OS_WAKE_LOCK_TIMEOUT(pub)
177 #endif /* defined(BCMDONGLEHOST) */
178
179 #define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
180 (akm) == RSN_AKM_UNSPECIFIED || \
181 (akm) == RSN_AKM_PSK)
182
183 #ifdef SUPPORT_AP_BWCTRL
184 static void
185 wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg, struct net_device *ndev, chanspec_t chanspec);
186 #endif /* SUPPORT_AP_BWCTRL */
187
188 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, 0)))
189 struct chan_info {
190 int freq;
191 int chan_type;
192 };
193 #endif
194
195 #if defined(WL_FW_OCE_AP_SELECT)
wl_cfg80211_is_oce_ap(struct wiphy * wiphy,const u8 * bssid_hint)196 bool wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint)
197 {
198 const u8 *parse = NULL;
199 bcm_tlv_t *ie;
200 const struct cfg80211_bss_ies *ies;
201 u32 len;
202 struct cfg80211_bss *bss;
203
204 bss = CFG80211_GET_BSS(wiphy, NULL, bssid_hint, 0, 0);
205 if (!bss) {
206 WL_ERR(("Unable to find AP in the cache"));
207 return false;
208 }
209
210 if (rcu_access_pointer(bss->ies)) {
211 ies = rcu_access_pointer(bss->ies);
212 parse = ies->data;
213 len = ies->len;
214 } else {
215 WL_ERR(("ies is NULL"));
216 return false;
217 }
218
219 while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_VS_ID))) {
220 if (wl_cfgoce_is_oce_ie((const uint8*)ie, (u8 const **)&parse, &len) == TRUE) {
221 return true;
222 } else {
223 ie = bcm_next_tlv((const bcm_tlv_t*) ie, &len);
224 if (!ie) {
225 return false;
226 }
227 parse = (uint8 *)ie;
228 WL_DBG(("NON OCE IE. next ie ptr:%p", parse));
229 }
230 }
231 WL_DBG(("OCE IE NOT found"));
232 return false;
233 }
234 #endif /* WL_FW_OCE_AP_SELECT */
235
236 /* Dump the contents of the encoded wps ie buffer and get pbc value */
237 void
wl_validate_wps_ie(const char * wps_ie,s32 wps_ie_len,bool * pbc)238 wl_validate_wps_ie(const char *wps_ie, s32 wps_ie_len, bool *pbc)
239 {
240 #define WPS_IE_FIXED_LEN 6
241 s16 len;
242 const u8 *subel = NULL;
243 u16 subelt_id;
244 u16 subelt_len;
245 u16 val;
246 u8 *valptr = (uint8*) &val;
247 if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
248 WL_ERR(("invalid argument : NULL\n"));
249 return;
250 }
251 len = (s16)wps_ie[TLV_LEN_OFF];
252
253 if (len > wps_ie_len) {
254 WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
255 return;
256 }
257 WL_DBG(("wps_ie len=%d\n", len));
258 len -= 4; /* for the WPS IE's OUI, oui_type fields */
259 subel = wps_ie + WPS_IE_FIXED_LEN;
260 while (len >= 4) { /* must have attr id, attr len fields */
261 valptr[0] = *subel++;
262 valptr[1] = *subel++;
263 subelt_id = HTON16(val);
264
265 valptr[0] = *subel++;
266 valptr[1] = *subel++;
267 subelt_len = HTON16(val);
268
269 len -= 4; /* for the attr id, attr len fields */
270 len -= (s16)subelt_len; /* for the remaining fields in this attribute */
271 if (len < 0) {
272 break;
273 }
274 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
275 subel, subelt_id, subelt_len));
276
277 if (subelt_id == WPS_ID_VERSION) {
278 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
279 } else if (subelt_id == WPS_ID_REQ_TYPE) {
280 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
281 } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
282 valptr[0] = *subel;
283 valptr[1] = *(subel + 1);
284 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
285 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
286 char devname[33];
287 int namelen = MIN(subelt_len, (sizeof(devname) - 1));
288
289 if (namelen) {
290 memcpy(devname, subel, namelen);
291 devname[namelen] = '\0';
292 /* Printing len as rx'ed in the IE */
293 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
294 devname, subelt_len));
295 }
296 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
297 valptr[0] = *subel;
298 valptr[1] = *(subel + 1);
299 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
300 *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
301 } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
302 valptr[0] = *subel;
303 valptr[1] = *(subel + 1);
304 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
305 valptr[0] = *(subel + 6);
306 valptr[1] = *(subel + 7);
307 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
308 } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
309 valptr[0] = *subel;
310 valptr[1] = *(subel + 1);
311 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
312 valptr[0] = *(subel + 6);
313 valptr[1] = *(subel + 7);
314 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
315 } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
316 valptr[0] = *subel;
317 valptr[1] = *(subel + 1);
318 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
319 ": cat=%u\n", HTON16(val)));
320 } else {
321 WL_DBG((" unknown attr 0x%x\n", subelt_id));
322 }
323
324 subel += subelt_len;
325 }
326 }
327
328 bool
wl_cfg80211_check_vif_in_use(struct net_device * ndev)329 wl_cfg80211_check_vif_in_use(struct net_device *ndev)
330 {
331 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
332 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
333 bool nan_enabled = FALSE;
334
335 #ifdef WL_NAN
336 nan_enabled = wl_cfgnan_is_enabled(cfg);
337 #endif /* WL_NAN */
338
339 if (nan_enabled || (wl_cfgp2p_vif_created(cfg)) ||
340 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
341 WL_MEM(("%s: Virtual interfaces in use. NAN %d P2P %d softAP %d\n",
342 __FUNCTION__, nan_enabled, wl_cfgp2p_vif_created(cfg),
343 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)));
344 return TRUE;
345 }
346
347 return FALSE;
348 }
349
350 #ifdef WL_IFACE_MGMT_CONF
351 #ifdef WL_IFACE_MGMT
352 static s32
wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 * cfg)353 wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 *cfg)
354 {
355 s32 ret = BCME_OK;
356 wl_iftype_t active_sec_iface = WL_IFACE_NOT_PRESENT;
357 bool p2p_disc_on = false;
358 bool sta_assoc_state = false;
359 bool nan_init_state = false;
360
361 mutex_lock(&cfg->if_sync);
362
363 sta_assoc_state = (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) ||
364 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg)));
365 active_sec_iface = wl_cfg80211_get_sec_iface(cfg);
366 p2p_disc_on = wl_get_p2p_status(cfg, SCANNING);
367
368 #ifdef WL_NAN
369 if (cfg->nancfg) {
370 nan_init_state = cfg->nancfg->nan_init_state;
371 }
372 #endif
373
374 if ((sta_assoc_state == TRUE) || (p2p_disc_on == TRUE) ||
375 (nan_init_state == TRUE) ||
376 (active_sec_iface != WL_IFACE_NOT_PRESENT)) {
377 WL_INFORM_MEM(("Active iface matrix: sta_assoc_state = %d,"
378 " p2p_disc = %d, nan_disc = %d, active iface = %s\n",
379 sta_assoc_state, p2p_disc_on, nan_init_state,
380 wl_iftype_to_str(active_sec_iface)));
381 ret = BCME_BUSY;
382 }
383 mutex_unlock(&cfg->if_sync);
384 return ret;
385 }
386 #endif /* WL_IFACE_MGMT */
387 #ifdef WL_NANP2P
388 int
wl_cfg80211_set_iface_conc_disc(struct net_device * ndev,uint8 arg_val)389 wl_cfg80211_set_iface_conc_disc(struct net_device *ndev,
390 uint8 arg_val)
391 {
392 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
393 if (!cfg) {
394 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
395 return BCME_ERROR;
396 }
397
398 if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
399 WL_ERR(("Cant allow iface management modifications\n"));
400 return BCME_BUSY;
401 }
402
403 if (arg_val) {
404 cfg->conc_disc |= arg_val;
405 } else {
406 cfg->conc_disc &= ~arg_val;
407 }
408 return BCME_OK;
409 }
410
411 uint8
wl_cfg80211_get_iface_conc_disc(struct net_device * ndev)412 wl_cfg80211_get_iface_conc_disc(struct net_device *ndev)
413 {
414 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
415 if (!cfg) {
416 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
417 return BCME_ERROR;
418 }
419 return cfg->conc_disc;
420 }
421 #endif /* WL_NANP2P */
422 #ifdef WL_IFACE_MGMT
423 int
wl_cfg80211_set_iface_policy(struct net_device * ndev,char * arg,int len)424 wl_cfg80211_set_iface_policy(struct net_device *ndev,
425 char *arg, int len)
426 {
427 int ret = BCME_OK;
428 uint8 i = 0;
429 iface_mgmt_data_t *iface_data = NULL;
430
431 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
432 if (!cfg) {
433 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
434 return BCME_ERROR;
435 }
436
437 if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
438 WL_ERR(("Cant allow iface management modifications\n"));
439 return BCME_BUSY;
440 }
441
442 if (!arg || len <= 0 || len > sizeof(iface_mgmt_data_t)) {
443 return BCME_BADARG;
444 }
445
446 iface_data = (iface_mgmt_data_t *)arg;
447 if (iface_data->policy >= WL_IF_POLICY_INVALID) {
448 WL_ERR(("Unexpected value of policy = %d\n",
449 iface_data->policy));
450 return BCME_BADARG;
451 }
452
453 bzero(&cfg->iface_data, sizeof(iface_mgmt_data_t));
454 ret = memcpy_s(&cfg->iface_data, sizeof(iface_mgmt_data_t), arg, len);
455 if (ret != BCME_OK) {
456 WL_ERR(("Failed to copy iface data, src len = %d\n", len));
457 return ret;
458 }
459
460 if (cfg->iface_data.policy == WL_IF_POLICY_ROLE_PRIORITY) {
461 for (i = 0; i < WL_IF_TYPE_MAX; i++) {
462 WL_DBG(("iface = %s, priority[i] = %d\n",
463 wl_iftype_to_str(i), cfg->iface_data.priority[i]));
464 }
465 }
466
467 return ret;
468 }
469
470 uint8
wl_cfg80211_get_iface_policy(struct net_device * ndev)471 wl_cfg80211_get_iface_policy(struct net_device *ndev)
472
473 {
474 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
475 if (!cfg) {
476 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
477 return BCME_ERROR;
478 }
479
480 return cfg->iface_data.policy;
481 }
482 #endif /* WL_IFACE_MGMT */
483 #endif /* WL_IFACE_MGMT_CONF */
484
485 #ifdef WL_IFACE_MGMT
486 /* Get active secondary data iface type */
487 wl_iftype_t
wl_cfg80211_get_sec_iface(struct bcm_cfg80211 * cfg)488 wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg)
489 {
490 #ifndef WL_STATIC_IF
491 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
492 #endif /* !WL_STATIC_IF */
493 struct net_device *p2p_ndev = NULL;
494
495 p2p_ndev = wl_to_p2p_bss_ndev(cfg,
496 P2PAPI_BSSCFG_CONNECTION1);
497
498 #ifdef WL_STATIC_IF
499 if (IS_CFG80211_STATIC_IF_ACTIVE(cfg)) {
500 if (IS_AP_IFACE(cfg->static_ndev->ieee80211_ptr)) {
501 return WL_IF_TYPE_AP;
502 }
503 }
504 #else
505 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
506 return WL_IF_TYPE_AP;
507 }
508 #endif /* WL_STATIC_IF */
509
510 if (p2p_ndev && p2p_ndev->ieee80211_ptr) {
511 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
512 return WL_IF_TYPE_P2P_GO;
513 }
514
515 /* Set role to GC when cfg80211 layer downgrades P2P
516 * role to station type while bringing down the interface
517 */
518 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) {
519 WL_DBG_MEM(("%s, Change to GC base role\n", __FUNCTION__));
520 return WL_IF_TYPE_P2P_GC;
521 }
522
523 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
524 return WL_IF_TYPE_P2P_GC;
525 }
526 }
527
528 #ifdef WL_NAN
529 if (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg))) {
530 return WL_IF_TYPE_NAN;
531 }
532 #endif /* WL_NAN */
533 return WL_IFACE_NOT_PRESENT;
534 }
535
536 /*
537 * Handle incoming data interface request based on policy.
538 * If there is any conflicting interface, that will be
539 * deleted.
540 */
541 static s32
wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)542 wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 *cfg,
543 wl_iftype_t new_wl_iftype)
544 {
545 s32 ret = BCME_OK;
546 bool del_iface = false;
547 wl_iftype_t sec_wl_if_type = wl_cfg80211_get_sec_iface(cfg);
548
549 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
550 new_wl_iftype == WL_IF_TYPE_NAN) {
551 /* Multi NDP is allowed irrespective of Policy */
552 return BCME_OK;
553 }
554
555 if (sec_wl_if_type == WL_IFACE_NOT_PRESENT) {
556 /*
557 * If there is no active secondary I/F, there
558 * is no interface conflict. Do nothing.
559 */
560 return BCME_OK;
561 }
562
563 /* Handle secondary data link case */
564 switch (cfg->iface_data.policy) {
565 case WL_IF_POLICY_CUSTOM:
566 case WL_IF_POLICY_DEFAULT: {
567 WL_INFORM_MEM(("%s, Delete any existing iface\n", __FUNCTION__));
568 del_iface = true;
569 break;
570 }
571 case WL_IF_POLICY_FCFS: {
572 WL_INFORM_MEM(("Found active iface = %s, can't support new iface = %s\n",
573 wl_iftype_to_str(sec_wl_if_type), wl_iftype_to_str(new_wl_iftype)));
574 ret = BCME_ERROR;
575 break;
576 }
577 case WL_IF_POLICY_LP: {
578 WL_INFORM_MEM(("Remove active sec data interface, allow incoming iface\n"));
579 /* Delete existing data iface and allow incoming sec iface */
580 del_iface = true;
581 break;
582 }
583 case WL_IF_POLICY_ROLE_PRIORITY: {
584 WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
585 wl_iftype_to_str(sec_wl_if_type),
586 cfg->iface_data.priority[sec_wl_if_type],
587 wl_iftype_to_str(new_wl_iftype),
588 cfg->iface_data.priority[new_wl_iftype]));
589 if (cfg->iface_data.priority[new_wl_iftype] >
590 cfg->iface_data.priority[sec_wl_if_type]) {
591 del_iface = true;
592 } else {
593 WL_ERR(("Can't support new iface = %s\n",
594 wl_iftype_to_str(new_wl_iftype)));
595 ret = BCME_ERROR;
596 }
597 break;
598 }
599 default: {
600 WL_ERR(("Unsupported interface policy = %d\n",
601 cfg->iface_data.policy));
602 return BCME_ERROR;
603 }
604 }
605 if (del_iface) {
606 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
607 }
608 return ret;
609 }
610
611 /* Handle discovery ifaces based on policy */
612 static s32
wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype,bool * disable_nan,bool * disable_p2p)613 wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 *cfg,
614 wl_iftype_t new_wl_iftype, bool *disable_nan, bool *disable_p2p)
615 {
616 s32 ret = BCME_OK;
617 wl_iftype_t sec_wl_if_type =
618 wl_cfg80211_get_sec_iface(cfg);
619 *disable_p2p = false;
620 *disable_nan = false;
621
622 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
623 new_wl_iftype == WL_IF_TYPE_NAN) {
624 /* Multi NDP is allowed irrespective of Policy */
625 return BCME_OK;
626 }
627
628 /*
629 * Check for any policy conflicts with active secondary
630 * interface for incoming discovery iface
631 */
632 if ((sec_wl_if_type != WL_IFACE_NOT_PRESENT) &&
633 (is_discovery_iface(new_wl_iftype))) {
634 switch (cfg->iface_data.policy) {
635 case WL_IF_POLICY_CUSTOM: {
636 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
637 new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
638 WL_INFORM_MEM(("Allow P2P Discovery with active NDP\n"));
639 /* No further checks are required. */
640 return BCME_OK;
641 }
642 /*
643 * Intentional fall through to default policy
644 * as for AP and associated ifaces, both are same
645 */
646 }
647 case WL_IF_POLICY_DEFAULT: {
648 if (sec_wl_if_type == WL_IF_TYPE_AP) {
649 WL_INFORM_MEM(("AP is active, cant support new iface\n"));
650 ret = BCME_ERROR;
651 } else if (sec_wl_if_type == WL_IF_TYPE_P2P_GC ||
652 sec_wl_if_type == WL_IF_TYPE_P2P_GO) {
653 if (new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
654 /*
655 * Associated discovery case,
656 * Fall through
657 */
658 } else {
659 /* Active iface is present, returning error */
660 WL_INFORM_MEM(("P2P group is active,"
661 " cant support new iface\n"));
662 ret = BCME_ERROR;
663 }
664 } else if (sec_wl_if_type == WL_IF_TYPE_NAN) {
665 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
666 }
667 break;
668 }
669 case WL_IF_POLICY_FCFS: {
670 WL_INFORM_MEM(("Can't support new iface = %s\n",
671 wl_iftype_to_str(new_wl_iftype)));
672 ret = BCME_ERROR;
673 break;
674 }
675 case WL_IF_POLICY_LP: {
676 /* Delete existing data iface n allow incoming sec iface */
677 WL_INFORM_MEM(("Remove active sec data interface = %s\n",
678 wl_iftype_to_str(sec_wl_if_type)));
679 ret = wl_cfg80211_delete_iface(cfg,
680 sec_wl_if_type);
681 break;
682 }
683 case WL_IF_POLICY_ROLE_PRIORITY: {
684 WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
685 wl_iftype_to_str(sec_wl_if_type),
686 cfg->iface_data.priority[sec_wl_if_type],
687 wl_iftype_to_str(new_wl_iftype),
688 cfg->iface_data.priority[new_wl_iftype]));
689 if (cfg->iface_data.priority[new_wl_iftype] >
690 cfg->iface_data.priority[sec_wl_if_type]) {
691 WL_INFORM_MEM(("Remove active sec data iface\n"));
692 ret = wl_cfg80211_delete_iface(cfg,
693 sec_wl_if_type);
694 } else {
695 WL_ERR(("Can't support new iface = %s"
696 " due to low priority\n",
697 wl_iftype_to_str(new_wl_iftype)));
698 ret = BCME_ERROR;
699 }
700 break;
701 }
702 default: {
703 WL_ERR(("Unsupported policy\n"));
704 return BCME_ERROR;
705 }
706 }
707 } else {
708 /*
709 * Handle incoming new secondary iface request,
710 * irrespective of existing discovery ifaces
711 */
712 if ((cfg->iface_data.policy == WL_IF_POLICY_CUSTOM) &&
713 (new_wl_iftype == WL_IF_TYPE_NAN)) {
714 WL_INFORM_MEM(("Allow NAN Data Path\n"));
715 /* No further checks are required. */
716 return BCME_OK;
717 }
718 }
719
720 /* Check for any conflicting discovery iface */
721 switch (new_wl_iftype) {
722 case WL_IF_TYPE_P2P_DISC:
723 case WL_IF_TYPE_P2P_GO:
724 case WL_IF_TYPE_P2P_GC: {
725 *disable_nan = true;
726 break;
727 }
728 case WL_IF_TYPE_NAN_NMI:
729 case WL_IF_TYPE_NAN: {
730 *disable_p2p = true;
731 break;
732 }
733 case WL_IF_TYPE_STA:
734 case WL_IF_TYPE_AP: {
735 *disable_nan = true;
736 *disable_p2p = true;
737 break;
738 }
739 default: {
740 WL_ERR(("Unsupported\n"));
741 return BCME_ERROR;
742 }
743 }
744 return ret;
745 }
746
747 static bool
wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)748 wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 *cfg,
749 wl_iftype_t new_wl_iftype)
750 {
751 struct net_device *p2p_ndev = NULL;
752 p2p_ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
753
754 if (new_wl_iftype == WL_IF_TYPE_P2P_DISC && p2p_ndev &&
755 p2p_ndev->ieee80211_ptr &&
756 is_p2p_group_iface(p2p_ndev->ieee80211_ptr)) {
757 return true;
758 }
759 #ifdef WL_NAN
760 else if ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) &&
761 (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg)))) {
762 return true;
763 }
764 #endif /* WL_NAN */
765 return false;
766 }
767
768 /* Handle incoming discovery iface request */
769 static s32
wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)770 wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 *cfg,
771 wl_iftype_t new_wl_iftype)
772 {
773 s32 ret = BCME_OK;
774 bool disable_p2p = false;
775 bool disable_nan = false;
776
777 wl_iftype_t active_sec_iface =
778 wl_cfg80211_get_sec_iface(cfg);
779
780 if (is_discovery_iface(new_wl_iftype) &&
781 (active_sec_iface != WL_IFACE_NOT_PRESENT)) {
782 if (wl_cfg80211_is_associated_discovery(cfg,
783 new_wl_iftype) == TRUE) {
784 WL_DBG(("Associate iface request is allowed= %s\n",
785 wl_iftype_to_str(new_wl_iftype)));
786 return ret;
787 }
788 }
789
790 ret = wl_cfg80211_disc_if_mgmt(cfg, new_wl_iftype,
791 &disable_nan, &disable_p2p);
792 if (ret != BCME_OK) {
793 WL_ERR(("Failed at disc iface mgmt, ret = %d\n", ret));
794 return ret;
795 }
796 #ifdef WL_NANP2P
797 if (((new_wl_iftype == WL_IF_TYPE_P2P_DISC) && disable_nan) ||
798 ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) && disable_p2p)) {
799 if ((cfg->nan_p2p_supported == TRUE) &&
800 (cfg->conc_disc == WL_NANP2P_CONC_SUPPORT)) {
801 WL_INFORM_MEM(("P2P + NAN conc is supported\n"));
802 disable_p2p = false;
803 disable_nan = false;
804 }
805 }
806 #endif /* WL_NANP2P */
807
808 if (disable_nan) {
809 #ifdef WL_NAN
810 /* Disable nan to avoid conflict with p2p */
811 ret = wl_cfgnan_check_nan_disable_pending(cfg, true, true);
812 if (ret != BCME_OK) {
813 WL_ERR(("failed to disable nan, error[%d]\n", ret));
814 return ret;
815 }
816 #endif /* WL_NAN */
817 }
818
819 if (disable_p2p) {
820 /* Disable p2p discovery */
821 ret = wl_cfg80211_deinit_p2p_discovery(cfg);
822 if (ret != BCME_OK) {
823 /* Should we fail nan enab here */
824 WL_ERR(("Failed to disable p2p_disc for allowing nan\n"));
825 return ret;
826 }
827 }
828 return ret;
829 }
830
831 /*
832 * Check for any conflicting iface before adding iface.
833 * Based on policy, either conflicting iface is removed
834 * or new iface add request is blocked.
835 */
836 s32
wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)837 wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg,
838 wl_iftype_t new_wl_iftype)
839 {
840 s32 ret = BCME_OK;
841
842 WL_INFORM_MEM(("Incoming iface = %s\n", wl_iftype_to_str(new_wl_iftype)));
843
844 if (!is_discovery_iface(new_wl_iftype)) {
845 /* Incoming data interface request */
846 if (wl_cfg80211_get_sec_iface(cfg) != WL_IFACE_NOT_PRESENT) {
847 /* active interface present - Apply interface data policy */
848 ret = wl_cfg80211_data_if_mgmt(cfg, new_wl_iftype);
849 if (ret != BCME_OK) {
850 WL_ERR(("if_mgmt fail:%d\n", ret));
851 return ret;
852 }
853 }
854 }
855 /* Apply discovery config */
856 ret = wl_cfg80211_handle_discovery_config(cfg, new_wl_iftype);
857 return ret;
858 }
859 #endif /* WL_IFACE_MGMT */
860
861 s32
wl_release_vif_macaddr(struct bcm_cfg80211 * cfg,u8 * mac_addr,u16 wl_iftype)862 wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype)
863 {
864 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
865 u16 org_toggle_bytes;
866 u16 cur_toggle_bytes;
867 u16 toggled_bit;
868
869 if (!ndev || !mac_addr || ETHER_ISNULLADDR(mac_addr)) {
870 return -EINVAL;
871 }
872 WL_DBG(("%s:Mac addr" MACDBG "\n",
873 __FUNCTION__, MAC2STRDBG(mac_addr)));
874
875 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_AP) ||
876 (wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
877 /* Avoid invoking release mac addr code for interfaces using
878 * fixed mac addr.
879 */
880 return BCME_OK;
881 }
882
883 /* Fetch last two bytes of mac address */
884 org_toggle_bytes = ntoh16(*((u16 *)&ndev->dev_addr[4]));
885 cur_toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
886
887 toggled_bit = (org_toggle_bytes ^ cur_toggle_bytes);
888 WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n",
889 org_toggle_bytes, cur_toggle_bytes));
890 if (toggled_bit & cfg->vif_macaddr_mask) {
891 /* This toggled_bit is marked in the used mac addr
892 * mask. Clear it.
893 */
894 cfg->vif_macaddr_mask &= ~toggled_bit;
895 WL_INFORM(("MAC address - " MACDBG " released. toggled_bit:%04X vif_mask:%04X\n",
896 MAC2STRDBG(mac_addr), toggled_bit, cfg->vif_macaddr_mask));
897 } else {
898 WL_ERR(("MAC address - " MACDBG " not found in the used list."
899 " toggled_bit:%04x vif_mask:%04x\n", MAC2STRDBG(mac_addr),
900 toggled_bit, cfg->vif_macaddr_mask));
901 return -EINVAL;
902 }
903
904 return BCME_OK;
905 }
906
907 s32
wl_get_vif_macaddr(struct bcm_cfg80211 * cfg,u16 wl_iftype,u8 * mac_addr)908 wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr)
909 {
910 struct ether_addr *p2p_dev_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE);
911 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
912 u16 toggle_mask;
913 u16 toggle_bit;
914 u16 toggle_bytes;
915 u16 used;
916 u32 offset = 0;
917 /* Toggle mask starts from MSB of second last byte */
918 u16 mask = 0x8000;
919 if (!mac_addr) {
920 return -EINVAL;
921 }
922 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) && p2p_dev_addr &&
923 ETHER_IS_LOCALADDR(p2p_dev_addr)) {
924 /* If mac address is already generated return the mac */
925 (void)memcpy_s(mac_addr, ETH_ALEN, p2p_dev_addr->octet, ETH_ALEN);
926 return 0;
927 }
928 (void)memcpy_s(mac_addr, ETH_ALEN, ndev->perm_addr, ETH_ALEN);
929 /*
930 * VIF MAC address managment
931 * P2P Device addres: Primary MAC with locally admin. bit set
932 * P2P Group address/NAN NMI/Softap/NAN DPI: Primary MAC addr
933 * with local admin bit set and one additional bit toggled.
934 * cfg->vif_macaddr_mask will hold the info regarding the mac address
935 * released. Ensure to call wl_release_vif_macaddress to free up
936 * the mac address.
937 */
938 #if defined (SPECIFIC_MAC_GEN_SCHEME)
939 if (wl_iftype == WL_IF_TYPE_P2P_DISC || wl_iftype == WL_IF_TYPE_AP) {
940 mac_addr[0] |= 0x02;
941 } else if ((wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
942 mac_addr[0] |= 0x02;
943 mac_addr[4] ^= 0x80;
944 }
945 #else
946 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
947 mac_addr[0] |= 0x02;
948 }
949 #endif /* SEPCIFIC_MAC_GEN_SCHEME */
950 else {
951 /* For locally administered mac addresses, we keep the
952 * OUI part constant and just work on the last two bytes.
953 */
954 mac_addr[0] |= 0x02;
955 toggle_mask = cfg->vif_macaddr_mask;
956 toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
957 do {
958 used = toggle_mask & mask;
959 if (!used) {
960 /* Use this bit position */
961 toggle_bit = mask >> offset;
962 toggle_bytes ^= toggle_bit;
963 cfg->vif_macaddr_mask |= toggle_bit;
964 WL_DBG(("toggle_bit:%04X toggle_bytes:%04X toggle_mask:%04X\n",
965 toggle_bit, toggle_bytes, cfg->vif_macaddr_mask));
966 /* Macaddress are stored in network order */
967 mac_addr[5] = *((u8 *)&toggle_bytes);
968 mac_addr[4] = *(((u8 *)&toggle_bytes + 1));
969 break;
970 }
971
972 /* Shift by one */
973 toggle_mask = toggle_mask << 0x1;
974 offset++;
975 if (offset > MAX_VIF_OFFSET) {
976 /* We have used up all macaddresses. Something wrong! */
977 WL_ERR(("Entire range of macaddress used up.\n"));
978 ASSERT(0);
979 break;
980 }
981 } while (true);
982 }
983 WL_INFORM_MEM(("Get virtual I/F mac addr: "MACDBG"\n", MAC2STRDBG(mac_addr)));
984 return 0;
985 }
986
987 bcm_struct_cfgdev *
wl_cfg80211_add_virtual_iface(struct wiphy * wiphy,const char * name,unsigned char name_assign_type,enum nl80211_iftype type,u32 * flags,struct vif_params * params)988 wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
989 #if defined(WL_CFG80211_P2P_DEV_IF)
990 const char *name,
991 #else
992 char *name,
993 #endif /* WL_CFG80211_P2P_DEV_IF */
994 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
995 unsigned char name_assign_type,
996 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
997 enum nl80211_iftype type,
998 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
999 u32 *flags,
1000 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
1001 struct vif_params *params)
1002 {
1003 u16 wl_iftype;
1004 u16 wl_mode;
1005 struct net_device *primary_ndev;
1006 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1007 struct wireless_dev *wdev;
1008
1009 WL_DBG(("Enter iftype: %d\n", type));
1010 if (!cfg) {
1011 return ERR_PTR(-EINVAL);
1012 }
1013
1014 /* Use primary I/F for sending cmds down to firmware */
1015 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1016 if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
1017 WL_ERR(("device is not ready\n"));
1018 return ERR_PTR(-ENODEV);
1019 }
1020
1021 if (!name) {
1022 WL_ERR(("Interface name not provided \n"));
1023 return ERR_PTR(-EINVAL);
1024 }
1025
1026 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
1027 return ERR_PTR(-EINVAL);
1028 }
1029
1030 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, name, NULL);
1031 if (unlikely(!wdev)) {
1032 return ERR_PTR(-ENODEV);
1033 }
1034 return wdev_to_cfgdev(wdev);
1035 }
1036
1037 s32
wl_cfg80211_del_virtual_iface(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev)1038 wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
1039 {
1040 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1041 struct wireless_dev *wdev = cfgdev_to_wdev(cfgdev);
1042 int ret = BCME_OK;
1043 u16 wl_iftype;
1044 u16 wl_mode;
1045 struct net_device *primary_ndev;
1046
1047 if (!cfg) {
1048 return -EINVAL;
1049 }
1050
1051 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1052 wdev = cfgdev_to_wdev(cfgdev);
1053 if (!wdev) {
1054 WL_ERR(("wdev null"));
1055 return -ENODEV;
1056 }
1057
1058 WL_DBG(("Enter wdev:%p iftype: %d\n", wdev, wdev->iftype));
1059 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
1060 WL_ERR(("Wrong iftype: %d\n", wdev->iftype));
1061 return -ENODEV;
1062 }
1063
1064 if ((ret = wl_cfg80211_del_if(cfg, primary_ndev,
1065 wdev, NULL)) < 0) {
1066 WL_ERR(("IF del failed\n"));
1067 }
1068
1069 return ret;
1070 }
1071
1072 static s32
wl_cfg80211_change_p2prole(struct wiphy * wiphy,struct net_device * ndev,enum nl80211_iftype type)1073 wl_cfg80211_change_p2prole(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type)
1074 {
1075 s32 wlif_type;
1076 s32 mode = 0;
1077 s32 index;
1078 s32 err;
1079 s32 conn_idx = -1;
1080 chanspec_t chspec;
1081 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1082 struct ether_addr p2p_dev_addr = {{0, 0, 0, 0, 0, 0}};
1083 #ifdef BCMDONGLEHOST
1084 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
1085 #endif /* BCMDONGLEHOST */
1086
1087 WL_INFORM_MEM(("Enter. current_role:%d new_role:%d \n", ndev->ieee80211_ptr->iftype, type));
1088
1089 (void)memcpy_s(p2p_dev_addr.octet, ETHER_ADDR_LEN,
1090 ndev->dev_addr, ETHER_ADDR_LEN);
1091
1092 if (!cfg->p2p || !wl_cfgp2p_vif_created(cfg)) {
1093 WL_ERR(("P2P not initialized \n"));
1094 return -EINVAL;
1095 }
1096
1097 if (!is_p2p_group_iface(ndev->ieee80211_ptr)) {
1098 WL_ERR(("Wrong if type \n"));
1099 return -EINVAL;
1100 }
1101
1102 /* Abort any on-going scans to avoid race condition issues */
1103 wl_cfgscan_cancel_scan(cfg);
1104
1105 index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
1106 if (index < 0) {
1107 WL_ERR(("Find bsscfg index from ndev(%p) failed\n", ndev));
1108 return BCME_ERROR;
1109 }
1110 if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK) {
1111 return BCME_ERROR;
1112 }
1113
1114 /* In concurrency case, STA may be already associated in a particular
1115 * channel. so retrieve the current channel of primary interface and
1116 * then start the virtual interface on that.
1117 */
1118 chspec = wl_cfg80211_get_shared_freq(wiphy);
1119 if (type == NL80211_IFTYPE_P2P_GO) {
1120 /* Dual p2p doesn't support multiple P2PGO interfaces,
1121 * p2p_go_count is the counter for GO creation
1122 * requests.
1123 */
1124 if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
1125 WL_ERR(("FW does not support multiple GO\n"));
1126 return BCME_ERROR;
1127 }
1128 mode = WL_MODE_AP;
1129 wlif_type = WL_P2P_IF_GO;
1130 #ifdef BCMDONGLEHOST
1131 dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
1132 dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
1133 #endif /* BCMDONGLEHOST */
1134 } else {
1135 wlif_type = WL_P2P_IF_CLIENT;
1136 /* for GO */
1137 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
1138 WL_INFORM_MEM(("Downgrading P2P GO to cfg_iftype:%d \n", type));
1139 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
1140 cfg->p2p->p2p_go_count--;
1141 /* disable interface before bsscfg free */
1142 err = wl_cfgp2p_ifdisable(cfg, &p2p_dev_addr);
1143 /* if fw doesn't support "ifdis",
1144 * do not wait for link down of ap mode
1145 */
1146 if (err == 0) {
1147 WL_DBG(("Wait for Link Down event for GO !!!\n"));
1148 wait_for_completion_timeout(&cfg->iface_disable,
1149 msecs_to_jiffies(500));
1150 } else if (err != BCME_UNSUPPORTED) {
1151 msleep(300);
1152 }
1153 }
1154 }
1155
1156 wl_set_p2p_status(cfg, IF_CHANGING);
1157 wl_clr_p2p_status(cfg, IF_CHANGED);
1158 wl_cfgp2p_ifchange(cfg, &p2p_dev_addr,
1159 htod32(wlif_type), chspec, conn_idx);
1160 wait_event_interruptible_timeout(cfg->netif_change_event,
1161 (wl_get_p2p_status(cfg, IF_CHANGED) == true),
1162 msecs_to_jiffies(MAX_WAIT_TIME));
1163
1164 wl_clr_p2p_status(cfg, IF_CHANGING);
1165 wl_clr_p2p_status(cfg, IF_CHANGED);
1166
1167 if (mode == WL_MODE_AP) {
1168 wl_set_drv_status(cfg, CONNECTED, ndev);
1169 #ifdef SUPPORT_AP_POWERSAVE
1170 dhd_set_ap_powersave(dhd, 0, TRUE);
1171 #endif /* SUPPORT_AP_POWERSAVE */
1172 }
1173
1174 return BCME_OK;
1175 }
1176
1177 s32
wl_cfg80211_change_virtual_iface(struct wiphy * wiphy,struct net_device * ndev,enum nl80211_iftype type,u32 * flags,struct vif_params * params)1178 wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
1179 enum nl80211_iftype type,
1180 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
1181 u32 *flags,
1182 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
1183 struct vif_params *params)
1184 {
1185 s32 infra = 1;
1186 s32 err = BCME_OK;
1187 u16 wl_iftype;
1188 u16 wl_mode;
1189 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1190 struct net_info *netinfo = NULL;
1191 #ifdef BCMDONGLEHOST
1192 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
1193 #endif /* BCMDONGLEHOST */
1194 struct net_device *primary_ndev;
1195
1196 #ifdef BCMDONGLEHOST
1197 if (!dhd)
1198 return -EINVAL;
1199 #endif /* BCMDONGLEHOST */
1200
1201 WL_INFORM_MEM(("[%s] Enter. current cfg_iftype:%d new cfg_iftype:%d \n",
1202 ndev->name, ndev->ieee80211_ptr->iftype, type));
1203 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1204
1205 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
1206 WL_ERR(("Unknown role \n"));
1207 return -EINVAL;
1208 }
1209
1210 mutex_lock(&cfg->if_sync);
1211 netinfo = wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
1212 if (unlikely(!netinfo)) {
1213 #ifdef WL_STATIC_IF
1214 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
1215 /* Incase of static interfaces, the netinfo will be
1216 * allocated only when FW interface is initialized. So
1217 * store the value and use it during initialization.
1218 */
1219 WL_INFORM_MEM(("skip change vif for static if\n"));
1220 ndev->ieee80211_ptr->iftype = type;
1221 err = BCME_OK;
1222 } else
1223 #endif /* WL_STATIC_IF */
1224 {
1225 WL_ERR(("netinfo not found \n"));
1226 err = -ENODEV;
1227 }
1228 goto fail;
1229 }
1230
1231 if ((primary_ndev == ndev) && !(ndev->flags & IFF_UP)) {
1232 /*
1233 * If interface is not initialized, store the role and
1234 * return. The role will be initilized after interface
1235 * up
1236 */
1237 WL_INFORM_MEM(("skip change role before dev up\n"));
1238 ndev->ieee80211_ptr->iftype = type;
1239 err = BCME_OK;
1240 goto fail;
1241 }
1242
1243 /* perform pre-if-change tasks */
1244 wl_cfg80211_iface_state_ops(ndev->ieee80211_ptr,
1245 WL_IF_CHANGE_REQ, wl_iftype, wl_mode);
1246
1247 switch (type) {
1248 case NL80211_IFTYPE_ADHOC:
1249 infra = 0;
1250 break;
1251 case NL80211_IFTYPE_STATION:
1252 /* Supplicant sets iftype to STATION while removing p2p GO */
1253 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
1254 /* Downgrading P2P GO */
1255 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
1256 if (unlikely(err)) {
1257 WL_ERR(("P2P downgrade failed \n"));
1258 }
1259 } else if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
1260 /* Downgrade role from AP to STA */
1261 if ((err = wl_cfg80211_add_del_bss(cfg, ndev,
1262 netinfo->bssidx, wl_iftype, 0, NULL)) < 0) {
1263 WL_ERR(("AP-STA Downgrade failed \n"));
1264 goto fail;
1265 }
1266 }
1267 break;
1268 case NL80211_IFTYPE_AP:
1269 /* intentional fall through */
1270 case NL80211_IFTYPE_AP_VLAN:
1271 {
1272 if (!wl_get_drv_status(cfg, AP_CREATED, ndev) &&
1273 wl_get_drv_status(cfg, READY, ndev)) {
1274 #if defined(BCMDONGLEHOST) && !defined(OEM_ANDROID)
1275 dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
1276 #endif /* BCMDONGLEHOST */
1277 err = wl_cfg80211_set_ap_role(cfg, ndev);
1278 if (unlikely(err)) {
1279 WL_ERR(("set ap role failed!\n"));
1280 goto fail;
1281 }
1282 } else {
1283 WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
1284 }
1285 break;
1286 }
1287 case NL80211_IFTYPE_P2P_GO:
1288 /* Intentional fall through */
1289 case NL80211_IFTYPE_P2P_CLIENT:
1290 infra = 1;
1291 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
1292 break;
1293 case NL80211_IFTYPE_MONITOR:
1294 case NL80211_IFTYPE_WDS:
1295 case NL80211_IFTYPE_MESH_POINT:
1296 /* Intentional fall through */
1297 default:
1298 WL_ERR(("Unsupported type:%d \n", type));
1299 err = -EINVAL;
1300 goto fail;
1301 }
1302
1303 if (wl_get_drv_status(cfg, READY, ndev)) {
1304 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(s32));
1305 if (err < 0) {
1306 WL_ERR(("SET INFRA/IBSS error %d\n", err));
1307 goto fail;
1308 }
1309 }
1310
1311 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
1312 WL_IF_CHANGE_DONE, wl_iftype, wl_mode);
1313
1314 /* Update new iftype in relevant structures */
1315 if (is_p2p_group_iface(ndev->ieee80211_ptr) && (type == NL80211_IFTYPE_STATION)) {
1316 /* For role downgrade cases, we keep interface role as GC */
1317 netinfo->iftype = WL_IF_TYPE_P2P_GC;
1318 WL_DBG_MEM(("[%s] Set base role to GC, current role"
1319 "ndev->ieee80211_ptr->iftype = %d\n",
1320 __FUNCTION__, ndev->ieee80211_ptr->iftype));
1321 } else {
1322 netinfo->iftype = wl_iftype;
1323 }
1324
1325 ndev->ieee80211_ptr->iftype = type;
1326
1327 WL_INFORM_MEM(("[%s] cfg_iftype changed to %d\n", ndev->name, type));
1328 #ifdef WL_EXT_IAPSTA
1329 wl_ext_iapsta_update_iftype(ndev, netinfo->ifidx, wl_iftype);
1330 #endif
1331
1332 fail:
1333 if (err) {
1334 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
1335 }
1336 mutex_unlock(&cfg->if_sync);
1337 return err;
1338 }
1339
1340 #ifdef SUPPORT_AP_BWCTRL
1341 static chanspec_t
wl_channel_to_chanspec(struct wiphy * wiphy,struct net_device * dev,u32 channel,u32 bw_cap)1342 wl_channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap)
1343 {
1344 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1345 u8 *buf = NULL;
1346 wl_uint32_list_t *list;
1347 int err = BCME_OK;
1348 chanspec_t c = 0, ret_c = 0;
1349 int bw = 0, tmp_bw = 0;
1350 int i;
1351 u32 tmp_c;
1352
1353 #define LOCAL_BUF_SIZE 1024
1354 buf = (u8 *)MALLOC(cfg->osh, LOCAL_BUF_SIZE);
1355 if (!buf) {
1356 WL_ERR(("buf memory alloc failed\n"));
1357 goto exit;
1358 }
1359
1360 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
1361 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync);
1362 if (err != BCME_OK) {
1363 WL_ERR(("get chanspecs failed with %d\n", err));
1364 goto exit;
1365 }
1366
1367 list = (wl_uint32_list_t *)(void *)buf;
1368 for (i = 0; i < dtoh32(list->count); i++) {
1369 c = dtoh32(list->element[i]);
1370 if (channel <= CH_MAX_2G_CHANNEL) {
1371 if (!CHSPEC_IS20(c))
1372 continue;
1373 if (channel == CHSPEC_CHANNEL(c)) {
1374 ret_c = c;
1375 bw = 20;
1376 goto exit;
1377 }
1378 }
1379 tmp_c = wf_chspec_ctlchan(c);
1380 tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT];
1381 if (tmp_c != channel)
1382 continue;
1383
1384 if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) {
1385 bw = tmp_bw;
1386 ret_c = c;
1387 if (bw == bw_cap)
1388 goto exit;
1389 }
1390 }
1391 exit:
1392 if (buf) {
1393 MFREE(cfg->osh, buf, LOCAL_BUF_SIZE);
1394 }
1395 #undef LOCAL_BUF_SIZE
1396 WL_DBG(("return chanspec %x %d\n", ret_c, bw));
1397 return ret_c;
1398 }
1399 #endif /* SUPPORT_AP_BWCTRL */
1400
1401 void
wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 * cfg,bool rtnl_lock_reqd)1402 wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 *cfg, bool rtnl_lock_reqd)
1403 {
1404 struct net_info *iter, *next;
1405 struct net_device *primary_ndev;
1406
1407 /* Note: This function will clean up only the network interface and host
1408 * data structures. The firmware interface clean up will happen in the
1409 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
1410 * context for the module case).
1411 */
1412 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1413 WL_DBG(("Enter\n"));
1414 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1415 for_each_ndev(cfg, iter, next) {
1416 GCC_DIAGNOSTIC_POP();
1417 if (iter->ndev && (iter->ndev != primary_ndev)) {
1418 /* Ensure interfaces are down before deleting */
1419 #ifdef WL_STATIC_IF
1420 /* Avoiding cleaning static ifaces */
1421 if (!IS_CFG80211_STATIC_IF(cfg, iter->ndev))
1422 #endif /* WL_STATIC_IF */
1423 {
1424 dev_close(iter->ndev);
1425 WL_DBG(("Cleaning up iface:%s \n", iter->ndev->name));
1426 wl_cfg80211_post_ifdel(iter->ndev, rtnl_lock_reqd, 0);
1427 }
1428 }
1429 }
1430 }
1431
1432 int
wl_get_bandwidth_cap(struct net_device * ndev,uint32 band,uint32 * bandwidth)1433 wl_get_bandwidth_cap(struct net_device *ndev, uint32 band, uint32 *bandwidth)
1434 {
1435 u32 bw = WL_CHANSPEC_BW_20;
1436 s32 err = BCME_OK;
1437 s32 bw_cap = 0;
1438 struct {
1439 u32 band;
1440 u32 bw_cap;
1441 } param = {0, 0};
1442 u8 ioctl_buf[WLC_IOCTL_SMLEN];
1443
1444 if (band == WL_CHANSPEC_BAND_5G) {
1445 param.band = WLC_BAND_5G;
1446 }
1447 #ifdef WL_6G_BAND
1448 else if (band == WL_CHANSPEC_BAND_6G) {
1449 param.band = WLC_BAND_6G;
1450 }
1451 #endif
1452 if (param.band) {
1453 /* bw_cap is newly defined iovar for checking bandwith
1454 * capability of the band in Aardvark_branch_tob
1455 */
1456 err = wldev_iovar_getbuf(ndev, "bw_cap", ¶m, sizeof(param),
1457 ioctl_buf, sizeof(ioctl_buf), NULL);
1458 if (err) {
1459 if (err != BCME_UNSUPPORTED) {
1460 WL_ERR(("bw_cap failed, %d\n", err));
1461 return err;
1462 } else {
1463 /* if firmware doesn't support bw_cap iovar,
1464 * we have to use mimo_bw_cap
1465 */
1466 err = wldev_iovar_getint(ndev, "mimo_bw_cap", &bw_cap);
1467 if (err) {
1468 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
1469 }
1470 if (bw_cap != WLC_N_BW_20ALL) {
1471 bw = WL_CHANSPEC_BW_40;
1472 }
1473 }
1474 } else {
1475 if (WL_BW_CAP_160MHZ(ioctl_buf[0])) {
1476 bw = WL_CHANSPEC_BW_160;
1477 } else if (WL_BW_CAP_80MHZ(ioctl_buf[0])) {
1478 bw = WL_CHANSPEC_BW_80;
1479 } else if (WL_BW_CAP_40MHZ(ioctl_buf[0])) {
1480 bw = WL_CHANSPEC_BW_40;
1481 } else {
1482 bw = WL_CHANSPEC_BW_20;
1483 }
1484 }
1485 } else if (band == WL_CHANSPEC_BAND_2G) {
1486 bw = WL_CHANSPEC_BW_20;
1487 }
1488
1489 *bandwidth = bw;
1490
1491 return err;
1492 }
1493
1494 s32
wl_get_nl80211_band(u32 wl_band)1495 wl_get_nl80211_band(u32 wl_band)
1496 {
1497 s32 err = BCME_ERROR;
1498
1499 switch (wl_band) {
1500 case WL_CHANSPEC_BAND_2G:
1501 return IEEE80211_BAND_2GHZ;
1502 case WL_CHANSPEC_BAND_5G:
1503 return IEEE80211_BAND_5GHZ;
1504 #ifdef WL_BAND_6G
1505 case WL_CHANSPEC_BAND_6G:
1506 /* current kernels doesn't support seperate
1507 * band for 6GHz. so till patch is available
1508 * map it under 5GHz
1509 */
1510 return IEEE80211_BAND_5GHZ;
1511 #endif /* WL_BAND_6G */
1512 default:
1513 WL_ERR(("unsupported Band. %d\n", wl_band));
1514 }
1515
1516 return err;
1517 }
1518
1519 s32
wl_cfg80211_set_channel(struct wiphy * wiphy,struct net_device * dev,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type)1520 wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
1521 struct ieee80211_channel *chan,
1522 enum nl80211_channel_type channel_type)
1523 {
1524 chanspec_t chspec = INVCHANSPEC;
1525 chanspec_t cur_chspec = INVCHANSPEC;
1526 u32 bw = WL_CHANSPEC_BW_20;
1527 s32 err = BCME_OK;
1528 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1529 #if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL) || defined(WL_EXT_IAPSTA)
1530 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
1531 enum nl80211_band band;
1532 s32 _chan;
1533 #endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
1534 u16 center_freq = chan->center_freq;
1535
1536 dev = ndev_to_wlc_ndev(dev, cfg);
1537 #ifdef WL_EXT_IAPSTA
1538 _chan = ieee80211_frequency_to_channel(chan->center_freq);
1539 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
1540 wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev), WL_IF_TYPE_AP);
1541 _chan = wl_ext_iapsta_update_channel(dhd, dev, _chan);
1542 }
1543 if (CHANNEL_IS_5G(_chan))
1544 band = NL80211_BAND_5GHZ;
1545 else
1546 band = NL80211_BAND_2GHZ;
1547 center_freq = ieee80211_channel_to_frequency(_chan, band);
1548 #endif
1549 chspec = wl_freq_to_chanspec(center_freq);
1550
1551 WL_MSG(dev->name, "netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
1552 dev->ifindex, channel_type, CHSPEC_CHANNEL(chspec));
1553
1554 #ifdef WL_P2P_6G
1555 if (!(cfg->p2p_6g_enabled)) {
1556 #endif /* WL_P2P_6G */
1557 if (IS_P2P_GO(dev->ieee80211_ptr) && (CHSPEC_IS6G(chspec))) {
1558 WL_ERR(("P2P GO not allowed on 6G\n"));
1559 return -ENOTSUPP;
1560 }
1561 #ifdef WL_P2P_6G
1562 }
1563 #endif /* WL_P2P_6G */
1564
1565 #ifdef NOT_YET
1566 switch (channel_type) {
1567 case NL80211_CHAN_HT40MINUS:
1568 /* secondary channel is below the control channel */
1569 chspec = CH40MHZ_CHSPEC(CHSPEC_CHANNEL(chspec), WL_CHANSPEC_CTL_SB_UPPER);
1570 break;
1571 case NL80211_CHAN_HT40PLUS:
1572 /* secondary channel is above the control channel */
1573 chspec = CH40MHZ_CHSPEC(CHSPEC_CHANNEL(chspec), WL_CHANSPEC_CTL_SB_LOWER);
1574 break;
1575 default:
1576 chspec = CH20MHZ_CHSPEC(CHSPEC_CHANNEL(chspec));
1577
1578 }
1579 #endif /* NOT_YET */
1580
1581 #if defined(APSTA_RESTRICTED_CHANNEL)
1582 /* Some customer platform used limited number of channels
1583 * for SoftAP interface on STA/SoftAP concurrent mode.
1584 * - 2.4GHz Channel: CH1 - CH13
1585 * - 5GHz Channel: CH149 (it depends on the country code)
1586 * If the Android framework sent invaild channel configuration
1587 * to DHD, driver should change the channel which is sutible for
1588 * STA/SoftAP concurrent mode.
1589 * - Set operating channel to CH1 (default 2.4GHz channel for
1590 * restricted APSTA mode) if STA interface was associated to
1591 * 5GHz APs except for CH149.
1592 * - Otherwise, set the channel to the same channel as existing AP.
1593 */
1594 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
1595 DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
1596 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
1597 u32 *sta_chanspec = (u32 *)wl_read_prof(cfg,
1598 bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN);
1599 if (chan->band == wl_get_nl80211_band(CHSPEC_BAND(*sta_chanspec))) {
1600 /* Do not try SCC in 5GHz if channel is not CH149 */
1601 chspec = (
1602 #ifdef WL_6G_BAND
1603 CHSPEC_IS6G(*sta_chanspec) ||
1604 #endif /* WL_6G_BAND */
1605 (CHSPEC_IS5G(*sta_chanspec) &&
1606 wf_chspec_primary20_chan(*sta_chanspec) !=
1607 DEFAULT_5G_SOFTAP_CHANNEL)) ?
1608 DEFAULT_2G_SOFTAP_CHANSPEC: *sta_chanspec;
1609 WL_ERR(("target chanspec will be changed to %x\n", chspec));
1610 if (CHSPEC_IS2G(chspec)) {
1611 bw = WL_CHANSPEC_BW_20;
1612 goto set_channel;
1613 }
1614 }
1615 }
1616 #endif /* APSTA_RESTRICTED_CHANNEL */
1617
1618 err = wl_get_bandwidth_cap(dev, CHSPEC_BAND(chspec), &bw);
1619 if (err < 0) {
1620 WL_ERR(("Failed to get bandwidth information, err=%d\n", err));
1621 return err;
1622 }
1623
1624 /* In case of 5G downgrade BW to 80MHz as 160MHz channels falls in DFS */
1625 if (CHSPEC_IS5G(chspec) && (bw == WL_CHANSPEC_BW_160)) {
1626 bw = WL_CHANSPEC_BW_80;
1627 }
1628 set_channel:
1629 cur_chspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chspec),
1630 bw, CHSPEC_BAND(chspec));
1631 #ifdef WL_6G_BAND
1632 if (cfg->acs_chspec &&
1633 CHSPEC_IS6G(cfg->acs_chspec) &&
1634 (wf_chspec_ctlchspec(cfg->acs_chspec) == wf_chspec_ctlchspec(cur_chspec))) {
1635 WL_DBG(("using acs_chanspec %x\n", cfg->acs_chspec));
1636 cur_chspec = cfg->acs_chspec;
1637 cfg->acs_chspec = 0;
1638 }
1639 #endif /* WL_6G_BAND */
1640 if (wf_chspec_valid(cur_chspec)) {
1641 /* convert 802.11 ac chanspec to current fw chanspec type */
1642 cur_chspec = wl_chspec_host_to_driver(cur_chspec);
1643 if (cur_chspec != INVCHANSPEC) {
1644 if ((err = wldev_iovar_setint(dev, "chanspec",
1645 cur_chspec)) == BCME_BADCHAN) {
1646 u32 local_channel = CHSPEC_CHANNEL(chspec);
1647 if ((bw == WL_CHANSPEC_BW_80) || (bw == WL_CHANSPEC_BW_160))
1648 goto change_bw;
1649 err = wldev_ioctl_set(dev, WLC_SET_CHANNEL,
1650 &local_channel, sizeof(local_channel));
1651 if (err < 0) {
1652 WL_ERR(("WLC_SET_CHANNEL error %d"
1653 "chip may not be supporting this channel\n", err));
1654 }
1655 } else if (err) {
1656 WL_ERR(("failed to set chanspec error %d\n", err));
1657 }
1658 #ifdef BCMDONGLEHOST
1659 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
1660 else {
1661 /* Disable Frameburst only for stand-alone 2GHz SoftAP */
1662 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
1663 DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
1664 (CHSPEC_IS2G(chspec)) &&
1665 !wl_get_drv_status(cfg, CONNECTED,
1666 bcmcfg_to_prmry_ndev(cfg))) {
1667 WL_DBG(("Disabling frameburst on "
1668 "stand-alone 2GHz SoftAP\n"));
1669 wl_cfg80211_set_frameburst(cfg, FALSE);
1670 }
1671 }
1672 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
1673 #endif /* BCMDONGLEHOST */
1674 } else {
1675 WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
1676 err = BCME_ERROR;
1677 }
1678 } else {
1679 change_bw:
1680 if (bw == WL_CHANSPEC_BW_160) {
1681 bw = WL_CHANSPEC_BW_80;
1682 } else if (bw == WL_CHANSPEC_BW_80) {
1683 bw = WL_CHANSPEC_BW_40;
1684 } else if (bw == WL_CHANSPEC_BW_40) {
1685 bw = WL_CHANSPEC_BW_20;
1686 } else {
1687 bw = 0;
1688 }
1689 if (bw)
1690 goto set_channel;
1691 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
1692 err = BCME_ERROR;
1693 }
1694 #ifdef CUSTOM_SET_CPUCORE
1695 if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
1696 WL_DBG(("SoftAP mode do not need to set cpucore\n"));
1697 } else if (chspec & WL_CHANSPEC_BW_80) {
1698 /* SoftAp only mode do not need to set cpucore */
1699 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
1700 dev != bcmcfg_to_prmry_ndev(cfg)) {
1701 /* Soft AP on virtual Iface (AP+STA case) */
1702 dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
1703 dhd_set_cpucore(dhd, TRUE);
1704 } else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
1705 /* If P2P IF is vht80 */
1706 dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
1707 dhd_set_cpucore(dhd, TRUE);
1708 }
1709 }
1710 #endif /* CUSTOM_SET_CPUCORE */
1711 if (!err && (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
1712 /* Update AP/GO operating chanspec */
1713 cfg->ap_oper_channel = wl_freq_to_chanspec(center_freq);
1714 }
1715 if (err) {
1716 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
1717 FW_LOGSET_MASK_ALL);
1718 } else {
1719 WL_DBG(("Setting chanspec %x for GO/AP \n", chspec));
1720 }
1721 return err;
1722 }
1723
1724 static s32
wl_validate_opensecurity(struct net_device * dev,s32 bssidx,bool privacy)1725 wl_validate_opensecurity(struct net_device *dev, s32 bssidx, bool privacy)
1726 {
1727 s32 err = BCME_OK;
1728 u32 wpa_val;
1729 s32 wsec = 0;
1730
1731 /* set auth */
1732 err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
1733 if (err < 0) {
1734 WL_ERR(("auth error %d\n", err));
1735 return BCME_ERROR;
1736 }
1737
1738 if (privacy) {
1739 /* If privacy bit is set in open mode, then WEP would be enabled */
1740 wsec = WEP_ENABLED;
1741 WL_DBG(("Setting wsec to %d for WEP \n", wsec));
1742 }
1743
1744 /* set wsec */
1745 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
1746 if (err < 0) {
1747 WL_ERR(("wsec error %d\n", err));
1748 return BCME_ERROR;
1749 }
1750
1751 /* set upper-layer auth */
1752 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC)
1753 wpa_val = WPA_AUTH_NONE;
1754 else
1755 wpa_val = WPA_AUTH_DISABLED;
1756 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_val, bssidx);
1757 if (err < 0) {
1758 WL_ERR(("wpa_auth error %d\n", err));
1759 return BCME_ERROR;
1760 }
1761
1762 return 0;
1763 }
1764
1765 #define MAX_FILS_IND_IE_LEN 1024u
1766 static s32
wl_validate_fils_ind_ie(struct net_device * dev,const bcm_tlv_t * filsindie,s32 bssidx)1767 wl_validate_fils_ind_ie(struct net_device *dev, const bcm_tlv_t *filsindie, s32 bssidx)
1768 {
1769 s32 err = BCME_OK;
1770 struct bcm_cfg80211 *cfg = NULL;
1771 bcm_iov_buf_t *iov_buf = NULL;
1772 bcm_xtlv_t* pxtlv;
1773 int iov_buf_size = 0;
1774
1775 if (!dev || !filsindie) {
1776 WL_ERR(("%s: dev/filsidie is null\n", __FUNCTION__));
1777 goto exit;
1778 }
1779
1780 cfg = wl_get_cfg(dev);
1781 if (!cfg) {
1782 WL_ERR(("%s: cfg is null\n", __FUNCTION__));
1783 goto exit;
1784 }
1785
1786 iov_buf_size = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) + filsindie->len - 1;
1787 iov_buf = MALLOCZ(cfg->osh, iov_buf_size);
1788 if (!iov_buf) {
1789 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, iov_buf_size));
1790 err = BCME_NOMEM;
1791 goto exit;
1792 }
1793 iov_buf->version = WL_FILS_IOV_VERSION;
1794 iov_buf->id = WL_FILS_CMD_ADD_IND_IE;
1795 iov_buf->len = sizeof(bcm_xtlv_t) + filsindie->len - 1;
1796 pxtlv = (bcm_xtlv_t*)&iov_buf->data[0];
1797 pxtlv->id = WL_FILS_XTLV_IND_IE;
1798 pxtlv->len = filsindie->len;
1799 /* memcpy_s return check not required as buffer is allocated based on ie
1800 * len
1801 */
1802 (void)memcpy_s(pxtlv->data, filsindie->len, filsindie->data, filsindie->len);
1803
1804 err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf_size,
1805 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
1806 if (unlikely(err)) {
1807 WL_ERR(("fils indication ioctl error (%d)\n", err));
1808 goto exit;
1809 }
1810
1811 exit:
1812 if (err < 0) {
1813 WL_ERR(("FILS Ind setting error %d\n", err));
1814 }
1815
1816 if (iov_buf) {
1817 MFREE(cfg->osh, iov_buf, iov_buf_size);
1818 }
1819 return err;
1820 }
1821
1822 #ifdef MFP
1823 static int
wl_get_mfp_capability(u8 rsn_cap,u32 * wpa_auth,u32 * mfp_val)1824 wl_get_mfp_capability(u8 rsn_cap, u32 *wpa_auth, u32 *mfp_val)
1825 {
1826 u32 mfp = 0;
1827 if (rsn_cap & RSN_CAP_MFPR) {
1828 WL_DBG(("MFP Required \n"));
1829 mfp = WL_MFP_REQUIRED;
1830 /* Our firmware has requirement that WPA2_AUTH_PSK/WPA2_AUTH_UNSPECIFIED
1831 * be set, if SHA256 OUI is to be included in the rsn ie.
1832 */
1833 if (*wpa_auth & WPA2_AUTH_PSK_SHA256) {
1834 *wpa_auth |= WPA2_AUTH_PSK;
1835 } else if (*wpa_auth & WPA2_AUTH_1X_SHA256) {
1836 *wpa_auth |= WPA2_AUTH_UNSPECIFIED;
1837 }
1838 } else if (rsn_cap & RSN_CAP_MFPC) {
1839 WL_DBG(("MFP Capable \n"));
1840 mfp = WL_MFP_CAPABLE;
1841 }
1842
1843 /* Validate MFP */
1844 if ((*wpa_auth == WPA3_AUTH_SAE_PSK) && (mfp != WL_MFP_REQUIRED)) {
1845 WL_ERR(("MFPR should be set for SAE PSK. mfp:%d\n", mfp));
1846 return BCME_ERROR;
1847 } else if ((*wpa_auth == (WPA3_AUTH_SAE_PSK | WPA2_AUTH_PSK)) &&
1848 (mfp != WL_MFP_CAPABLE)) {
1849 WL_ERR(("mfp(%d) should be set to capable(%d) for SAE transition mode\n",
1850 mfp, WL_MFP_CAPABLE));
1851 return BCME_ERROR;
1852 }
1853
1854 *mfp_val = mfp;
1855 return BCME_OK;
1856 }
1857 #endif /* MFP */
1858
1859 static s32
wl_validate_wpa2ie(struct net_device * dev,const bcm_tlv_t * wpa2ie,s32 bssidx)1860 wl_validate_wpa2ie(struct net_device *dev, const bcm_tlv_t *wpa2ie, s32 bssidx)
1861 {
1862 s32 len = 0;
1863 s32 err = BCME_OK;
1864 u16 auth = 0; /* d11 open authentication */
1865 u32 wsec;
1866 u32 pval = 0;
1867 u32 gval = 0;
1868 u32 wpa_auth = 0;
1869 const wpa_suite_mcast_t *mcast;
1870 const wpa_suite_ucast_t *ucast;
1871 const wpa_suite_auth_key_mgmt_t *mgmt;
1872 const wpa_pmkid_list_t *pmkid;
1873 int cnt = 0;
1874 #ifdef MFP
1875 u32 mfp = 0;
1876 #endif /* MFP */
1877 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1878 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
1879
1880 u16 suite_count;
1881 u8 rsn_cap[2];
1882 u32 wme_bss_disable;
1883
1884 if (wpa2ie == NULL)
1885 goto exit;
1886
1887 WL_DBG(("Enter \n"));
1888 len = wpa2ie->len - WPA2_VERSION_LEN;
1889 /* check the mcast cipher */
1890 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
1891 switch (mcast->type) {
1892 case WPA_CIPHER_NONE:
1893 gval = 0;
1894 break;
1895 case WPA_CIPHER_WEP_40:
1896 case WPA_CIPHER_WEP_104:
1897 gval = WEP_ENABLED;
1898 break;
1899 case WPA_CIPHER_TKIP:
1900 gval = TKIP_ENABLED;
1901 break;
1902 case WPA_CIPHER_AES_CCM:
1903 gval = AES_ENABLED;
1904 break;
1905
1906 #ifdef BCMWAPI_WPI
1907 case WAPI_CIPHER_SMS4:
1908 gval = SMS4_ENABLED;
1909 break;
1910 #endif
1911
1912 default:
1913 WL_ERR(("No Security Info\n"));
1914 break;
1915 }
1916 if ((len -= WPA_SUITE_LEN) <= 0)
1917 return BCME_BADLEN;
1918
1919 /* check the unicast cipher */
1920 ucast = (const wpa_suite_ucast_t *)&mcast[1];
1921 suite_count = ltoh16_ua(&ucast->count);
1922 switch (ucast->list[0].type) {
1923 case WPA_CIPHER_NONE:
1924 pval = 0;
1925 break;
1926 case WPA_CIPHER_WEP_40:
1927 case WPA_CIPHER_WEP_104:
1928 pval = WEP_ENABLED;
1929 break;
1930 case WPA_CIPHER_TKIP:
1931 pval = TKIP_ENABLED;
1932 break;
1933 case WPA_CIPHER_AES_CCM:
1934 pval = AES_ENABLED;
1935 break;
1936
1937 #ifdef BCMWAPI_WPI
1938 case WAPI_CIPHER_SMS4:
1939 pval = SMS4_ENABLED;
1940 break;
1941 #endif
1942
1943 default:
1944 WL_ERR(("No Security Info\n"));
1945 }
1946 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
1947 return BCME_BADLEN;
1948
1949 /* FOR WPS , set SEC_OW_ENABLED */
1950 wsec = (pval | gval | SES_OW_ENABLED);
1951 /* check the AKM */
1952 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
1953 suite_count = cnt = ltoh16_ua(&mgmt->count);
1954 while (cnt--) {
1955 if (bcmp(mgmt->list[cnt].oui, WFA_OUI, WFA_OUI_LEN) == 0) {
1956 switch (mgmt->list[cnt].type) {
1957 case RSN_AKM_DPP:
1958 wpa_auth |= WPA3_AUTH_DPP_AKM;
1959 break;
1960 default:
1961 WL_ERR(("No Key Mgmt Info in WFA_OUI\n"));
1962 }
1963 } else {
1964 switch (mgmt->list[cnt].type) {
1965 case RSN_AKM_NONE:
1966 wpa_auth |= WPA_AUTH_NONE;
1967 break;
1968 case RSN_AKM_UNSPECIFIED:
1969 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
1970 break;
1971 case RSN_AKM_PSK:
1972 wpa_auth |= WPA2_AUTH_PSK;
1973 break;
1974 #ifdef MFP
1975 case RSN_AKM_MFP_PSK:
1976 wpa_auth |= WPA2_AUTH_PSK_SHA256;
1977 break;
1978 case RSN_AKM_MFP_1X:
1979 wpa_auth |= WPA2_AUTH_1X_SHA256;
1980 break;
1981 case RSN_AKM_FILS_SHA256:
1982 wpa_auth |= WPA2_AUTH_FILS_SHA256;
1983 break;
1984 case RSN_AKM_FILS_SHA384:
1985 wpa_auth |= WPA2_AUTH_FILS_SHA384;
1986 break;
1987 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
1988 case RSN_AKM_SAE_PSK:
1989 wpa_auth |= WPA3_AUTH_SAE_PSK;
1990 break;
1991 #endif /* WL_SAE || WL_CLIENT_SAE */
1992 #endif /* MFP */
1993 default:
1994 WL_ERR(("No Key Mgmt Info\n"));
1995 }
1996 }
1997 }
1998 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
1999 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
2000 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
2001
2002 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
2003 wme_bss_disable = 0;
2004 } else {
2005 wme_bss_disable = 1;
2006 }
2007
2008 #ifdef MFP
2009 if (wl_get_mfp_capability(rsn_cap[0], &wpa_auth, &mfp) != BCME_OK) {
2010 WL_ERR(("mfp configuration invalid. rsn_cap:0x%x\n", rsn_cap[0]));
2011 return BCME_ERROR;
2012 }
2013 #endif /* MFP */
2014
2015 /* set wme_bss_disable to sync RSN Capabilities */
2016 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
2017 if (err < 0) {
2018 WL_ERR(("wme_bss_disable error %d\n", err));
2019 return BCME_ERROR;
2020 }
2021 } else {
2022 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
2023 }
2024
2025 len -= RSN_CAP_LEN;
2026 if (len >= WPA2_PMKID_COUNT_LEN) {
2027 pmkid = (const wpa_pmkid_list_t *)
2028 ((const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
2029 cnt = ltoh16_ua(&pmkid->count);
2030 if (cnt != 0) {
2031 WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
2032 return BCME_ERROR;
2033 }
2034 /* since PMKID cnt is known to be 0 for AP, */
2035 /* so don't bother to send down this info to firmware */
2036 }
2037
2038 #ifdef MFP
2039 len -= WPA2_PMKID_COUNT_LEN;
2040 if (len >= WPA_SUITE_LEN) {
2041 cfg->bip_pos =
2042 (const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN;
2043 } else {
2044 cfg->bip_pos = NULL;
2045 }
2046 #endif
2047
2048 /* set auth */
2049 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
2050 if (err < 0) {
2051 WL_ERR(("auth error %d\n", err));
2052 return BCME_ERROR;
2053 }
2054
2055 /* set wsec */
2056 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
2057 if (err < 0) {
2058 WL_ERR(("wsec error %d\n", err));
2059 return BCME_ERROR;
2060 }
2061
2062 #ifdef MFP
2063 cfg->mfp_mode = mfp;
2064 #endif /* MFP */
2065
2066 /* set upper-layer auth */
2067 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
2068 if (err < 0) {
2069 WL_ERR(("wpa_auth error %d\n", err));
2070 return BCME_ERROR;
2071 }
2072
2073 if (sec) {
2074 /* store applied sec settings */
2075 sec->fw_wpa_auth = wpa_auth;
2076 sec->fw_wsec = wsec;
2077 sec->fw_auth = auth;
2078 #ifdef MFP
2079 sec->fw_mfp = mfp;
2080 #endif /* mfp */
2081 }
2082 exit:
2083 return 0;
2084 }
2085
2086 static s32
wl_validate_wpaie(struct net_device * dev,const wpa_ie_fixed_t * wpaie,s32 bssidx)2087 wl_validate_wpaie(struct net_device *dev, const wpa_ie_fixed_t *wpaie, s32 bssidx)
2088 {
2089 const wpa_suite_mcast_t *mcast;
2090 const wpa_suite_ucast_t *ucast;
2091 const wpa_suite_auth_key_mgmt_t *mgmt;
2092 u16 auth = 0; /* d11 open authentication */
2093 u16 count;
2094 s32 err = BCME_OK;
2095 s32 len = 0;
2096 u32 i;
2097 u32 wsec;
2098 u32 pval = 0;
2099 u32 gval = 0;
2100 u32 wpa_auth = 0;
2101 u32 tmp = 0;
2102 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2103 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
2104
2105 if (wpaie == NULL)
2106 goto exit;
2107 WL_DBG(("Enter \n"));
2108 len = wpaie->length; /* value length */
2109 len -= WPA_IE_TAG_FIXED_LEN;
2110 /* check for multicast cipher suite */
2111 if (len < WPA_SUITE_LEN) {
2112 WL_INFORM_MEM(("no multicast cipher suite\n"));
2113 goto exit;
2114 }
2115
2116 /* pick up multicast cipher */
2117 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
2118 len -= WPA_SUITE_LEN;
2119 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
2120 if (IS_WPA_CIPHER(mcast->type)) {
2121 tmp = 0;
2122 switch (mcast->type) {
2123 case WPA_CIPHER_NONE:
2124 tmp = 0;
2125 break;
2126 case WPA_CIPHER_WEP_40:
2127 case WPA_CIPHER_WEP_104:
2128 tmp = WEP_ENABLED;
2129 break;
2130 case WPA_CIPHER_TKIP:
2131 tmp = TKIP_ENABLED;
2132 break;
2133 case WPA_CIPHER_AES_CCM:
2134 tmp = AES_ENABLED;
2135 break;
2136 default:
2137 WL_ERR(("No Security Info\n"));
2138 }
2139 gval |= tmp;
2140 }
2141 }
2142 /* Check for unicast suite(s) */
2143 if (len < WPA_IE_SUITE_COUNT_LEN) {
2144 WL_INFORM_MEM(("no unicast suite\n"));
2145 goto exit;
2146 }
2147 /* walk thru unicast cipher list and pick up what we recognize */
2148 ucast = (const wpa_suite_ucast_t *)&mcast[1];
2149 count = ltoh16_ua(&ucast->count);
2150 len -= WPA_IE_SUITE_COUNT_LEN;
2151 for (i = 0; i < count && len >= WPA_SUITE_LEN;
2152 i++, len -= WPA_SUITE_LEN) {
2153 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
2154 if (IS_WPA_CIPHER(ucast->list[i].type)) {
2155 tmp = 0;
2156 switch (ucast->list[i].type) {
2157 case WPA_CIPHER_NONE:
2158 tmp = 0;
2159 break;
2160 case WPA_CIPHER_WEP_40:
2161 case WPA_CIPHER_WEP_104:
2162 tmp = WEP_ENABLED;
2163 break;
2164 case WPA_CIPHER_TKIP:
2165 tmp = TKIP_ENABLED;
2166 break;
2167 case WPA_CIPHER_AES_CCM:
2168 tmp = AES_ENABLED;
2169 break;
2170 default:
2171 WL_ERR(("No Security Info\n"));
2172 }
2173 pval |= tmp;
2174 }
2175 }
2176 }
2177 len -= (count - i) * WPA_SUITE_LEN;
2178 /* Check for auth key management suite(s) */
2179 if (len < WPA_IE_SUITE_COUNT_LEN) {
2180 WL_INFORM_MEM((" no auth key mgmt suite\n"));
2181 goto exit;
2182 }
2183 /* walk thru auth management suite list and pick up what we recognize */
2184 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
2185 count = ltoh16_ua(&mgmt->count);
2186 len -= WPA_IE_SUITE_COUNT_LEN;
2187 for (i = 0; i < count && len >= WPA_SUITE_LEN;
2188 i++, len -= WPA_SUITE_LEN) {
2189 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
2190 if (IS_WPA_AKM(mgmt->list[i].type)) {
2191 tmp = 0;
2192 switch (mgmt->list[i].type) {
2193 case RSN_AKM_NONE:
2194 tmp = WPA_AUTH_NONE;
2195 break;
2196 case RSN_AKM_UNSPECIFIED:
2197 tmp = WPA_AUTH_UNSPECIFIED;
2198 break;
2199 case RSN_AKM_PSK:
2200 tmp = WPA_AUTH_PSK;
2201 break;
2202 default:
2203 WL_ERR(("No Key Mgmt Info\n"));
2204 }
2205 wpa_auth |= tmp;
2206 }
2207 }
2208
2209 }
2210 /* FOR WPS , set SEC_OW_ENABLED */
2211 wsec = (pval | gval | SES_OW_ENABLED);
2212 /* set auth */
2213 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
2214 if (err < 0) {
2215 WL_ERR(("auth error %d\n", err));
2216 return BCME_ERROR;
2217 }
2218 /* set wsec */
2219 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
2220 if (err < 0) {
2221 WL_ERR(("wsec error %d\n", err));
2222 return BCME_ERROR;
2223 }
2224 /* set upper-layer auth */
2225 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
2226 if (err < 0) {
2227 WL_ERR(("wpa_auth error %d\n", err));
2228 return BCME_ERROR;
2229 }
2230
2231 if (sec) {
2232 /* store applied sec settings */
2233 sec->fw_wpa_auth = wpa_auth;
2234 sec->fw_wsec = wsec;
2235 sec->fw_auth = auth;
2236 }
2237
2238 exit:
2239 return 0;
2240 }
2241
2242 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
wl_get_cipher_type(uint8 type)2243 static u32 wl_get_cipher_type(uint8 type)
2244 {
2245 u32 ret = 0;
2246 switch (type) {
2247 case WPA_CIPHER_NONE:
2248 ret = 0;
2249 break;
2250 case WPA_CIPHER_WEP_40:
2251 case WPA_CIPHER_WEP_104:
2252 ret = WEP_ENABLED;
2253 break;
2254 case WPA_CIPHER_TKIP:
2255 ret = TKIP_ENABLED;
2256 break;
2257 case WPA_CIPHER_AES_CCM:
2258 ret = AES_ENABLED;
2259 break;
2260
2261 #ifdef BCMWAPI_WPI
2262 case WAPI_CIPHER_SMS4:
2263 ret = SMS4_ENABLED;
2264 break;
2265 #endif
2266
2267 default:
2268 WL_ERR(("No Security Info\n"));
2269 }
2270 return ret;
2271 }
2272
wl_get_suite_auth_key_mgmt_type(uint8 type,const wpa_suite_mcast_t * mcast)2273 static u32 wl_get_suite_auth_key_mgmt_type(uint8 type, const wpa_suite_mcast_t *mcast)
2274 {
2275 u32 ret = 0;
2276 u32 is_wpa2 = 0;
2277
2278 if (!bcmp(mcast->oui, WPA2_OUI, WPA2_OUI_LEN)) {
2279 is_wpa2 = 1;
2280 }
2281
2282 WL_INFORM_MEM(("%s, type = %d\n", is_wpa2 ? "WPA2":"WPA", type));
2283 if (bcmp(mcast->oui, WFA_OUI, WFA_OUI_LEN) == 0) {
2284 switch (type) {
2285 case RSN_AKM_DPP:
2286 ret = WPA3_AUTH_DPP_AKM;
2287 break;
2288 default:
2289 WL_ERR(("No Key Mgmt Info in WFA_OUI\n"));
2290 }
2291 } else {
2292 switch (type) {
2293 case RSN_AKM_NONE:
2294 /* For WPA and WPA2, AUTH_NONE is common */
2295 ret = WPA_AUTH_NONE;
2296 break;
2297 case RSN_AKM_UNSPECIFIED:
2298 if (is_wpa2) {
2299 ret = WPA2_AUTH_UNSPECIFIED;
2300 } else {
2301 ret = WPA_AUTH_UNSPECIFIED;
2302 }
2303 break;
2304 case RSN_AKM_PSK:
2305 if (is_wpa2) {
2306 ret = WPA2_AUTH_PSK;
2307 } else {
2308 ret = WPA_AUTH_PSK;
2309 }
2310 break;
2311 #ifdef WL_SAE
2312 case RSN_AKM_SAE_PSK:
2313 ret = WPA3_AUTH_SAE_PSK;
2314 break;
2315 #endif /* WL_SAE */
2316 default:
2317 WL_ERR(("No Key Mgmt Info\n"));
2318 }
2319 }
2320 return ret;
2321 }
2322
2323 static s32
wl_validate_wpaie_wpa2ie(struct net_device * dev,const wpa_ie_fixed_t * wpaie,const bcm_tlv_t * wpa2ie,s32 bssidx)2324 wl_validate_wpaie_wpa2ie(struct net_device *dev, const wpa_ie_fixed_t *wpaie,
2325 const bcm_tlv_t *wpa2ie, s32 bssidx)
2326 {
2327 const wpa_suite_mcast_t *mcast;
2328 const wpa_suite_ucast_t *ucast;
2329 const wpa_suite_auth_key_mgmt_t *mgmt;
2330 u16 auth = 0; /* d11 open authentication */
2331 u16 count;
2332 s32 err = BCME_OK;
2333 u32 wme_bss_disable;
2334 u16 suite_count;
2335 u8 rsn_cap[2];
2336 s32 len = 0;
2337 u32 i;
2338 u32 wsec1, wsec2, wsec;
2339 u32 pval = 0;
2340 u32 gval = 0;
2341 u32 wpa_auth = 0;
2342 u32 wpa_auth1 = 0;
2343 u32 wpa_auth2 = 0;
2344 #ifdef MFP
2345 u32 mfp = 0;
2346 #endif /* MFP */
2347
2348 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2349 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
2350
2351 if (wpaie == NULL || wpa2ie == NULL)
2352 goto exit;
2353
2354 WL_DBG(("Enter \n"));
2355 len = wpaie->length; /* value length */
2356 len -= WPA_IE_TAG_FIXED_LEN;
2357 /* check for multicast cipher suite */
2358 if (len < WPA_SUITE_LEN) {
2359 WL_INFORM_MEM(("no multicast cipher suite\n"));
2360 goto exit;
2361 }
2362
2363 /* pick up multicast cipher */
2364 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
2365 len -= WPA_SUITE_LEN;
2366 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
2367 if (IS_WPA_CIPHER(mcast->type)) {
2368 gval |= wl_get_cipher_type(mcast->type);
2369 }
2370 }
2371 WL_DBG(("\nwpa ie validate\n"));
2372 WL_DBG(("wpa ie mcast cipher = 0x%X\n", gval));
2373
2374 /* Check for unicast suite(s) */
2375 if (len < WPA_IE_SUITE_COUNT_LEN) {
2376 WL_INFORM_MEM(("no unicast suite\n"));
2377 goto exit;
2378 }
2379
2380 /* walk thru unicast cipher list and pick up what we recognize */
2381 ucast = (const wpa_suite_ucast_t *)&mcast[1];
2382 count = ltoh16_ua(&ucast->count);
2383 len -= WPA_IE_SUITE_COUNT_LEN;
2384 for (i = 0; i < count && len >= WPA_SUITE_LEN;
2385 i++, len -= WPA_SUITE_LEN) {
2386 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
2387 if (IS_WPA_CIPHER(ucast->list[i].type)) {
2388 pval |= wl_get_cipher_type(ucast->list[i].type);
2389 }
2390 }
2391 }
2392 WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count, pval));
2393
2394 /* FOR WPS , set SEC_OW_ENABLED */
2395 wsec1 = (pval | gval | SES_OW_ENABLED);
2396 WL_ERR(("wpa ie wsec = 0x%X\n", wsec1));
2397
2398 len -= (count - i) * WPA_SUITE_LEN;
2399 /* Check for auth key management suite(s) */
2400 if (len < WPA_IE_SUITE_COUNT_LEN) {
2401 WL_INFORM_MEM((" no auth key mgmt suite\n"));
2402 goto exit;
2403 }
2404 /* walk thru auth management suite list and pick up what we recognize */
2405 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
2406 count = ltoh16_ua(&mgmt->count);
2407 len -= WPA_IE_SUITE_COUNT_LEN;
2408 for (i = 0; i < count && len >= WPA_SUITE_LEN;
2409 i++, len -= WPA_SUITE_LEN) {
2410 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
2411 if (IS_WPA_AKM(mgmt->list[i].type)) {
2412 wpa_auth1 |=
2413 wl_get_suite_auth_key_mgmt_type(mgmt->list[i].type, mcast);
2414 }
2415 }
2416
2417 }
2418 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth1));
2419 WL_ERR(("\nwpa2 ie validate\n"));
2420
2421 pval = 0;
2422 gval = 0;
2423 len = wpa2ie->len;
2424 /* check the mcast cipher */
2425 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
2426 gval = wl_get_cipher_type(mcast->type);
2427
2428 WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval));
2429 if ((len -= WPA_SUITE_LEN) <= 0)
2430 {
2431 WL_ERR(("P:wpa2 ie len[%d]", len));
2432 return BCME_BADLEN;
2433 }
2434
2435 /* check the unicast cipher */
2436 ucast = (const wpa_suite_ucast_t *)&mcast[1];
2437 suite_count = ltoh16_ua(&ucast->count);
2438 WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count));
2439 pval |= wl_get_cipher_type(ucast->list[0].type);
2440
2441 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
2442 return BCME_BADLEN;
2443
2444 WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval));
2445
2446 /* FOR WPS , set SEC_OW_ENABLED */
2447 wsec2 = (pval | gval | SES_OW_ENABLED);
2448 WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2));
2449
2450 /* check the AKM */
2451 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
2452 suite_count = ltoh16_ua(&mgmt->count);
2453 wpa_auth2 = wl_get_suite_auth_key_mgmt_type(mgmt->list[0].type, mcast);
2454 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth2));
2455
2456 wsec = (wsec1 | wsec2);
2457 wpa_auth = (wpa_auth1 | wpa_auth2);
2458 WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec, wpa_auth));
2459
2460 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
2461 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
2462 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
2463 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
2464 wme_bss_disable = 0;
2465 } else {
2466 wme_bss_disable = 1;
2467 }
2468 WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap[0], wme_bss_disable));
2469
2470 #ifdef MFP
2471 if (wl_get_mfp_capability(rsn_cap[0], &wpa_auth, &mfp) != BCME_OK) {
2472 WL_ERR(("mfp configuration invalid. rsn_cap:0x%x\n", rsn_cap[0]));
2473 return BCME_ERROR;
2474 }
2475 cfg->mfp_mode = mfp;
2476 #endif /* MFP */
2477
2478 /* set wme_bss_disable to sync RSN Capabilities */
2479 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
2480 if (err < 0) {
2481 WL_ERR(("wme_bss_disable error %d\n", err));
2482 return BCME_ERROR;
2483 }
2484 } else {
2485 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
2486 }
2487
2488 /* set auth */
2489 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
2490 if (err < 0) {
2491 WL_ERR(("auth error %d\n", err));
2492 return BCME_ERROR;
2493 }
2494 /* set wsec */
2495 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
2496 if (err < 0) {
2497 WL_ERR(("wsec error %d\n", err));
2498 return BCME_ERROR;
2499 }
2500 /* set upper-layer auth */
2501 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
2502 if (err < 0) {
2503 WL_ERR(("wpa_auth error %d\n", err));
2504 return BCME_ERROR;
2505 }
2506
2507 if (sec) {
2508 sec->fw_wpa_auth = wpa_auth;
2509 sec->fw_auth = auth;
2510 sec->fw_wsec = wsec;
2511 }
2512
2513 exit:
2514 return 0;
2515 }
2516 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
2517
2518 static s32
wl_cfg80211_bcn_validate_sec(struct net_device * dev,struct parsed_ies * ies,u32 dev_role,s32 bssidx,bool privacy)2519 wl_cfg80211_bcn_validate_sec(
2520 struct net_device *dev,
2521 struct parsed_ies *ies,
2522 u32 dev_role,
2523 s32 bssidx,
2524 bool privacy)
2525 {
2526 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2527 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
2528 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
2529
2530 if (!bss) {
2531 WL_ERR(("cfgbss is NULL \n"));
2532 return BCME_ERROR;
2533 }
2534
2535 if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
2536 /* For P2P GO, the sec type is WPA2-PSK */
2537 WL_DBG(("P2P GO: validating wpa2_ie"));
2538 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0)
2539 return BCME_ERROR;
2540
2541 } else if (dev_role == NL80211_IFTYPE_AP) {
2542
2543 WL_DBG(("SoftAP: validating security"));
2544 /* If wpa2_ie or wpa_ie is present validate it */
2545
2546 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
2547 if ((ies->wpa_ie != NULL && ies->wpa2_ie != NULL)) {
2548 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie, ies->wpa2_ie, bssidx) < 0) {
2549 bss->security_mode = false;
2550 return BCME_ERROR;
2551 }
2552 }
2553 else {
2554 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
2555 if ((ies->wpa2_ie || ies->wpa_ie) &&
2556 ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
2557 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
2558 bss->security_mode = false;
2559 return BCME_ERROR;
2560 }
2561
2562 if (ies->fils_ind_ie &&
2563 (wl_validate_fils_ind_ie(dev, ies->fils_ind_ie, bssidx) < 0)) {
2564 bss->security_mode = false;
2565 return BCME_ERROR;
2566 }
2567
2568 bss->security_mode = true;
2569 if (bss->rsn_ie) {
2570 MFREE(cfg->osh, bss->rsn_ie, bss->rsn_ie[1]
2571 + WPA_RSN_IE_TAG_FIXED_LEN);
2572 bss->rsn_ie = NULL;
2573 }
2574 if (bss->wpa_ie) {
2575 MFREE(cfg->osh, bss->wpa_ie, bss->wpa_ie[1]
2576 + WPA_RSN_IE_TAG_FIXED_LEN);
2577 bss->wpa_ie = NULL;
2578 }
2579 if (bss->wps_ie) {
2580 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
2581 bss->wps_ie = NULL;
2582 }
2583 if (bss->fils_ind_ie) {
2584 MFREE(cfg->osh, bss->fils_ind_ie, bss->fils_ind_ie[1]
2585 + FILS_INDICATION_IE_TAG_FIXED_LEN);
2586 bss->fils_ind_ie = NULL;
2587 }
2588 if (ies->wpa_ie != NULL) {
2589 /* WPAIE */
2590 bss->rsn_ie = NULL;
2591 bss->wpa_ie = MALLOCZ(cfg->osh,
2592 ies->wpa_ie->length
2593 + WPA_RSN_IE_TAG_FIXED_LEN);
2594 if (bss->wpa_ie) {
2595 memcpy(bss->wpa_ie, ies->wpa_ie,
2596 ies->wpa_ie->length
2597 + WPA_RSN_IE_TAG_FIXED_LEN);
2598 }
2599 } else if (ies->wpa2_ie != NULL) {
2600 /* RSNIE */
2601 bss->wpa_ie = NULL;
2602 bss->rsn_ie = MALLOCZ(cfg->osh,
2603 ies->wpa2_ie->len
2604 + WPA_RSN_IE_TAG_FIXED_LEN);
2605 if (bss->rsn_ie) {
2606 memcpy(bss->rsn_ie, ies->wpa2_ie,
2607 ies->wpa2_ie->len
2608 + WPA_RSN_IE_TAG_FIXED_LEN);
2609 }
2610 }
2611 #ifdef WL_FILS
2612 if (ies->fils_ind_ie) {
2613 bss->fils_ind_ie = MALLOCZ(cfg->osh,
2614 ies->fils_ind_ie->len
2615 + FILS_INDICATION_IE_TAG_FIXED_LEN);
2616 if (bss->fils_ind_ie) {
2617 memcpy(bss->fils_ind_ie, ies->fils_ind_ie,
2618 ies->fils_ind_ie->len
2619 + FILS_INDICATION_IE_TAG_FIXED_LEN);
2620 }
2621 }
2622 #endif /* WL_FILS */
2623 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
2624 }
2625 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
2626 if (!ies->wpa2_ie && !ies->wpa_ie) {
2627 wl_validate_opensecurity(dev, bssidx, privacy);
2628 bss->security_mode = false;
2629 }
2630
2631 if (ies->wps_ie) {
2632 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
2633 if (bss->wps_ie) {
2634 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
2635 }
2636 }
2637 }
2638
2639 WL_INFORM_MEM(("[%s] wpa_auth:0x%x auth:0x%x wsec:0x%x mfp:0x%x\n",
2640 dev->name, sec->fw_wpa_auth, sec->fw_auth, sec->fw_wsec, sec->fw_mfp));
2641 return 0;
2642
2643 }
2644
2645 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
2646 defined(WL_COMPAT_WIRELESS)
wl_cfg80211_bcn_set_params(struct cfg80211_ap_settings * info,struct net_device * dev,u32 dev_role,s32 bssidx)2647 static s32 wl_cfg80211_bcn_set_params(
2648 struct cfg80211_ap_settings *info,
2649 struct net_device *dev,
2650 u32 dev_role, s32 bssidx)
2651 {
2652 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2653 s32 err = BCME_OK;
2654
2655 WL_DBG(("interval (%d) \ndtim_period (%d) \n",
2656 info->beacon_interval, info->dtim_period));
2657
2658 if (info->beacon_interval) {
2659 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
2660 &info->beacon_interval, sizeof(s32))) < 0) {
2661 WL_ERR(("Beacon Interval Set Error, %d\n", err));
2662 return err;
2663 }
2664 }
2665
2666 if (info->dtim_period) {
2667 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
2668 &info->dtim_period, sizeof(s32))) < 0) {
2669 WL_ERR(("DTIM Interval Set Error, %d\n", err));
2670 return err;
2671 }
2672 }
2673
2674 if ((info->ssid) && (info->ssid_len > 0) &&
2675 (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
2676 WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
2677 if (dev_role == NL80211_IFTYPE_AP) {
2678 /* Store the hostapd SSID */
2679 bzero(cfg->hostapd_ssid.SSID, DOT11_MAX_SSID_LEN);
2680 memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
2681 cfg->hostapd_ssid.SSID_len = (uint32)info->ssid_len;
2682 } else {
2683 /* P2P GO */
2684 bzero(cfg->p2p->ssid.SSID, DOT11_MAX_SSID_LEN);
2685 memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
2686 cfg->p2p->ssid.SSID_len = (uint32)info->ssid_len;
2687 }
2688 }
2689
2690 return err;
2691 }
2692 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
2693
2694 s32
wl_cfg80211_parse_ies(const u8 * ptr,u32 len,struct parsed_ies * ies)2695 wl_cfg80211_parse_ies(const u8 *ptr, u32 len, struct parsed_ies *ies)
2696 {
2697 s32 err = BCME_OK;
2698
2699 bzero(ies, sizeof(struct parsed_ies));
2700
2701 /* find the WPSIE */
2702 if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
2703 WL_DBG(("WPSIE in beacon \n"));
2704 ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
2705 } else {
2706 WL_DBG(("No WPSIE in beacon \n"));
2707 }
2708
2709 /* find the RSN_IE */
2710 if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len,
2711 DOT11_MNG_RSN_ID)) != NULL) {
2712 WL_DBG((" WPA2 IE found\n"));
2713 ies->wpa2_ie_len = ies->wpa2_ie->len;
2714 }
2715
2716 /* find the FILS_IND_IE */
2717 if ((ies->fils_ind_ie = bcm_parse_tlvs(ptr, len,
2718 DOT11_MNG_FILS_IND_ID)) != NULL) {
2719 WL_DBG((" FILS IND IE found\n"));
2720 ies->fils_ind_ie_len = ies->fils_ind_ie->len;
2721 }
2722
2723 /* find the WPA_IE */
2724 if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
2725 WL_DBG((" WPA found\n"));
2726 ies->wpa_ie_len = ies->wpa_ie->length;
2727 }
2728
2729 return err;
2730
2731 }
2732
2733 s32
wl_cfg80211_set_ap_role(struct bcm_cfg80211 * cfg,struct net_device * dev)2734 wl_cfg80211_set_ap_role(
2735 struct bcm_cfg80211 *cfg,
2736 struct net_device *dev)
2737 {
2738 s32 err = BCME_OK;
2739 s32 infra = 1;
2740 s32 ap = 0;
2741 s32 pm;
2742 s32 bssidx;
2743 s32 apsta = 0;
2744 bool new_chip;
2745 #ifdef WLEASYMESH
2746 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2747 #endif /* WLEASYMESH */
2748
2749 new_chip = wl_new_chip_check(dev);
2750
2751 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
2752 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
2753 return -EINVAL;
2754 }
2755
2756 WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n", dev->name, bssidx));
2757
2758 if (bssidx != 0 || new_chip) {
2759 if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
2760 WL_IF_TYPE_AP, 0, NULL)) < 0) {
2761 WL_ERR(("wl add_del_bss returned error:%d\n", err));
2762 return err;
2763 }
2764 }
2765
2766 /*
2767 * For older chips, "bss" iovar does not support
2768 * bsscfg role change/upgradation, and still
2769 * return BCME_OK on attempt
2770 * Hence, below traditional way to handle the same
2771 */
2772
2773 if ((err = wldev_ioctl_get(dev,
2774 WLC_GET_AP, &ap, sizeof(s32))) < 0) {
2775 WL_ERR(("Getting AP mode failed %d \n", err));
2776 return err;
2777 }
2778 #ifdef WLEASYMESH
2779 else if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
2780 WL_MSG(dev->name, "Getting AP mode ok, set map and dwds");
2781 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
2782 if (err < 0) {
2783 WL_ERR(("WLC_DOWN error %d\n", err));
2784 return err;
2785 }
2786 //For FrontHaulAP
2787 err = wldev_iovar_setint(dev, "map", 2);
2788 if (err < 0) {
2789 WL_ERR(("wl map 2 error %d\n", err));
2790 return err;
2791 }
2792 err = wldev_iovar_setint(dev, "dwds", 1);
2793 if (err < 0) {
2794 WL_ERR(("wl dwds 1 error %d\n", err));
2795 return err;
2796 }
2797 WL_MSG(dev->name, "Get AP %d", (int)ap);
2798 }
2799 #endif /* WLEASYMESH*/
2800
2801 if (!ap) {
2802 /* AP mode switch not supported. Try setting up AP explicitly */
2803 err = wldev_iovar_getint(dev, "apsta", (s32 *)&apsta);
2804 if (unlikely(err)) {
2805 WL_ERR(("Could not get apsta %d\n", err));
2806 return err;
2807 }
2808 if (apsta == 0) {
2809 /* If apsta is not set, set it */
2810
2811 /* Check for any connected interfaces before wl down */
2812 if (wl_get_drv_status_all(cfg, CONNECTED) > 0) {
2813 #ifdef WLEASYMESH
2814 if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
2815 WL_MSG(dev->name, "do wl down");
2816 } else {
2817 #endif /* WLEASYMESH */
2818 WL_ERR(("Concurrent i/f operational. can't do wl down"));
2819 return BCME_ERROR;
2820 #ifdef WLEASYMESH
2821 }
2822 #endif /* WLEASYMESH */
2823 }
2824 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
2825 if (err < 0) {
2826 WL_ERR(("WLC_DOWN error %d\n", err));
2827 return err;
2828 }
2829 #ifdef WLEASYMESH
2830 if (dhd->conf->fw_type == FW_TYPE_EZMESH)
2831 err = wldev_iovar_setint(dev, "apsta", 1);
2832 else
2833 #endif /* WLEASYMESH */
2834 err = wldev_iovar_setint(dev, "apsta", 0);
2835 if (err < 0) {
2836 WL_ERR(("wl apsta 0 error %d\n", err));
2837 return err;
2838 }
2839 ap = 1;
2840 if ((err = wldev_ioctl_set(dev,
2841 WLC_SET_AP, &ap, sizeof(s32))) < 0) {
2842 WL_ERR(("setting AP mode failed %d \n", err));
2843 return err;
2844 }
2845 #ifdef WLEASYMESH
2846 //For FrontHaulAP
2847 if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
2848 WL_MSG(dev->name, "wl map 2");
2849 err = wldev_iovar_setint(dev, "map", 2);
2850 if (err < 0) {
2851 WL_ERR(("wl map 2 error %d\n", err));
2852 return err;
2853 }
2854 err = wldev_iovar_setint(dev, "dwds", 1);
2855 if (err < 0) {
2856 WL_ERR(("wl dwds 1 error %d\n", err));
2857 return err;
2858 }
2859 }
2860 #endif /* WLEASYMESH */
2861 }
2862 }
2863 else if (bssidx == 0 && !new_chip
2864 #ifdef WL_EXT_IAPSTA
2865 && !wl_ext_iapsta_other_if_enabled(dev)
2866 #endif
2867 ) {
2868 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
2869 if (err < 0) {
2870 WL_ERR(("WLC_DOWN error %d\n", err));
2871 return err;
2872 }
2873 err = wldev_iovar_setint(dev, "apsta", 0);
2874 if (err < 0) {
2875 WL_ERR(("wl apsta 0 error %d\n", err));
2876 return err;
2877 }
2878 ap = 1;
2879 if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) < 0) {
2880 WL_ERR(("setting AP mode failed %d \n", err));
2881 return err;
2882 }
2883 }
2884
2885 if (bssidx == 0) {
2886 pm = 0;
2887 if ((err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm))) != 0) {
2888 WL_ERR(("wl PM 0 returned error:%d\n", err));
2889 /* Ignore error, if any */
2890 err = BCME_OK;
2891 }
2892 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
2893 if (err < 0) {
2894 WL_ERR(("SET INFRA error %d\n", err));
2895 return err;
2896 }
2897 }
2898
2899 /* On success, mark AP creation in progress. */
2900 wl_set_drv_status(cfg, AP_CREATING, dev);
2901 return 0;
2902 }
2903
2904 void
wl_cfg80211_ap_timeout_work(struct work_struct * work)2905 wl_cfg80211_ap_timeout_work(struct work_struct *work)
2906 {
2907 #if defined (BCMDONGLEHOST)
2908 struct bcm_cfg80211 *cfg = NULL;
2909 dhd_pub_t *dhdp = NULL;
2910 BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, ap_work.work);
2911
2912 WL_ERR(("** AP LINK UP TIMEOUT **\n"));
2913 dhdp = (dhd_pub_t *)(cfg->pub);
2914 if (dhd_query_bus_erros(dhdp)) {
2915 return;
2916 }
2917 #ifdef DHD_PCIE_RUNTIMEPM
2918 dhdpcie_runtime_bus_wake(dhdp, CAN_SLEEP(), __builtin_return_address(0));
2919 #endif /* DHD_PCIE_RUNTIMEPM */
2920 dhdp->iface_op_failed = TRUE;
2921
2922 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
2923 if (dhdp->memdump_enabled) {
2924 dhdp->memdump_type = DUMP_TYPE_AP_LINKUP_FAILURE;
2925 dhd_bus_mem_dump(dhdp);
2926 }
2927 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
2928
2929 #if defined(OEM_ANDROID)
2930 WL_ERR(("Notify hang event to upper layer \n"));
2931 dhdp->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
2932 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2933 #endif /* OEM_ANDROID */
2934 #endif /* BCMDONGLEHOST */
2935 }
2936
2937 /* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
2938 #define MAX_AP_LINK_WAIT_TIME 10000
2939 static s32
wl_cfg80211_bcn_bringup_ap(struct net_device * dev,struct parsed_ies * ies,u32 dev_role,s32 bssidx)2940 wl_cfg80211_bcn_bringup_ap(
2941 struct net_device *dev,
2942 struct parsed_ies *ies,
2943 u32 dev_role, s32 bssidx)
2944 {
2945 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2946 struct wl_join_params join_params;
2947 bool is_bssup = false;
2948 s32 infra = 1;
2949 s32 join_params_size = 0;
2950 s32 ap = 1;
2951 s32 wsec;
2952 #ifdef DISABLE_11H_SOFTAP
2953 s32 spect = 0;
2954 #endif /* DISABLE_11H_SOFTAP */
2955 #ifdef SOFTAP_UAPSD_OFF
2956 uint32 wme_apsd = 0;
2957 #endif /* SOFTAP_UAPSD_OFF */
2958 s32 err = BCME_OK;
2959 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2960 s32 is_rsdb_supported = BCME_ERROR;
2961 char sec[32];
2962
2963 #if defined (BCMDONGLEHOST)
2964 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
2965 if (is_rsdb_supported < 0)
2966 return (-ENODEV);
2967 #endif /* BCMDONGLEHOST */
2968
2969 WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role, bssidx, dev->name));
2970
2971 /* Common code for SoftAP and P2P GO */
2972 wl_clr_drv_status(cfg, AP_CREATED, dev);
2973
2974 /* Make sure INFRA is set for AP/GO */
2975 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
2976 if (err < 0) {
2977 WL_ERR(("SET INFRA error %d\n", err));
2978 goto exit;
2979 }
2980
2981 /* Do abort scan before creating GO */
2982 wl_cfgscan_cancel_scan(cfg);
2983
2984 /* Schedule delayed work to handle link time out. schedule
2985 * before ssid iovar. Sometimes before iovar context should
2986 * resume, the event may come and get processed.
2987 */
2988 if (schedule_delayed_work(&cfg->ap_work,
2989 msecs_to_jiffies((const unsigned int)MAX_AP_LINK_WAIT_TIME))) {
2990 WL_DBG(("ap timeout work scheduled\n"));
2991 }
2992
2993 if (dev_role == NL80211_IFTYPE_P2P_GO) {
2994 wl_ext_get_sec(dev, 0, sec, sizeof(sec), TRUE);
2995 WL_MSG(dev->name, "Creating GO with sec=%s\n", sec);
2996 is_bssup = wl_cfg80211_bss_isup(dev, bssidx);
2997 if (!is_bssup && (ies->wpa2_ie != NULL)) {
2998
2999 err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid,
3000 sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
3001 bssidx, &cfg->ioctl_buf_sync);
3002 if (err < 0) {
3003 WL_ERR(("GO SSID setting error %d\n", err));
3004 goto exit;
3005 }
3006
3007 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
3008 WL_ERR(("GO Bring up error %d\n", err));
3009 goto exit;
3010 }
3011 wl_clr_drv_status(cfg, AP_CREATING, dev);
3012 } else
3013 WL_DBG(("Bss is already up\n"));
3014 } else if (dev_role == NL80211_IFTYPE_AP) {
3015
3016 // if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
3017 /* Make sure fw is in proper state */
3018 err = wl_cfg80211_set_ap_role(cfg, dev);
3019 if (unlikely(err)) {
3020 WL_ERR(("set ap role failed!\n"));
3021 goto exit;
3022 }
3023 // }
3024
3025 /* Device role SoftAP */
3026 WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
3027 /* Clear the status bit after use */
3028 wl_clr_drv_status(cfg, AP_CREATING, dev);
3029
3030 #ifdef DISABLE_11H_SOFTAP
3031 /* Some old WLAN card (e.g. Intel PRO/Wireless 2200BG)
3032 * does not try to connect SoftAP because they cannot detect
3033 * 11h IEs. For this reason, we disable 11h feature in case
3034 * of SoftAP mode. (Related CSP case number: 661635)
3035 */
3036 if (is_rsdb_supported == 0) {
3037 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
3038 if (err < 0) {
3039 WL_ERR(("WLC_DOWN error %d\n", err));
3040 goto exit;
3041 }
3042 }
3043 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT,
3044 &spect, sizeof(s32));
3045 if (err < 0) {
3046 WL_ERR(("SET SPECT_MANAGMENT error %d\n", err));
3047 goto exit;
3048 }
3049 #endif /* DISABLE_11H_SOFTAP */
3050
3051 #ifdef WL_DISABLE_HE_SOFTAP
3052 err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, FALSE);
3053 if (err < 0) {
3054 WL_ERR(("failed to set he features, error=%d\n", err));
3055 }
3056 #endif /* WL_DISABLE_HE_SOFTAP */
3057
3058 #ifdef SOFTAP_UAPSD_OFF
3059 err = wldev_iovar_setbuf_bsscfg(dev, "wme_apsd", &wme_apsd, sizeof(wme_apsd),
3060 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
3061 if (err < 0) {
3062 WL_ERR(("failed to disable uapsd, error=%d\n", err));
3063 }
3064 #endif /* SOFTAP_UAPSD_OFF */
3065
3066 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
3067 if (unlikely(err)) {
3068 WL_ERR(("WLC_UP error (%d)\n", err));
3069 goto exit;
3070 }
3071
3072 #ifdef MFP
3073 if (cfg->bip_pos) {
3074 err = wldev_iovar_setbuf_bsscfg(dev, "bip",
3075 (const void *)(cfg->bip_pos), WPA_SUITE_LEN, cfg->ioctl_buf,
3076 WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
3077 if (err < 0) {
3078 WL_ERR(("bip set error %d\n", err));
3079
3080 #ifdef CUSTOMER_HW6
3081 if (wl_customer6_legacy_chip_check(cfg,
3082 bcmcfg_to_prmry_ndev(cfg))) {
3083 /* Ignore bip error: Some older firmwares doesn't
3084 * support bip iovar/ return BCME_NOTUP while trying
3085 * to set bip from AP bring up context. These firmares
3086 * include bip in RSNIE by default. So its okay to ignore
3087 * the error.
3088 */
3089 err = BCME_OK;
3090 } else
3091 #endif /* CUSTOMER_HW6 */
3092
3093 {
3094 goto exit;
3095 }
3096 }
3097 }
3098 #endif /* MFP */
3099
3100 err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec);
3101 if (unlikely(err)) {
3102 WL_ERR(("Could not get wsec %d\n", err));
3103 goto exit;
3104 }
3105 if (dhd->conf->chip == BCM43430_CHIP_ID && bssidx > 0 &&
3106 (wsec & (TKIP_ENABLED|AES_ENABLED))) {
3107 wsec |= WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround
3108 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
3109 if (err < 0) {
3110 WL_ERR(("wsec error %d\n", err));
3111 goto exit;
3112 }
3113 }
3114 if ((wsec == WEP_ENABLED) && cfg->wep_key.len) {
3115 WL_DBG(("Applying buffered WEP KEY \n"));
3116 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &cfg->wep_key,
3117 sizeof(struct wl_wsec_key), cfg->ioctl_buf,
3118 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
3119 /* clear the key after use */
3120 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
3121 if (unlikely(err)) {
3122 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
3123 goto exit;
3124 }
3125 }
3126
3127 #ifdef MFP
3128 if (cfg->mfp_mode) {
3129 /* This needs to go after wsec otherwise the wsec command will
3130 * overwrite the values set by MFP
3131 */
3132 err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx);
3133 if (err < 0) {
3134 WL_ERR(("MFP Setting failed. ret = %d \n", err));
3135 /* If fw doesn't support mfp, Ignore the error */
3136 if (err != BCME_UNSUPPORTED) {
3137 goto exit;
3138 }
3139 }
3140 }
3141 #endif /* MFP */
3142
3143 bzero(&join_params, sizeof(join_params));
3144 /* join parameters starts with ssid */
3145 join_params_size = sizeof(join_params.ssid);
3146 join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
3147 (uint32)DOT11_MAX_SSID_LEN);
3148 memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
3149 join_params.ssid.SSID_len);
3150 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
3151
3152 wl_ext_get_sec(dev, 0, sec, sizeof(sec), TRUE);
3153 WL_MSG(dev->name, "Creating AP with sec=%s\n", sec);
3154 /* create softap */
3155 if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
3156 join_params_size)) != 0) {
3157 WL_ERR(("SoftAP/GO set ssid failed! \n"));
3158 goto exit;
3159 } else {
3160 WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
3161 }
3162
3163 if (bssidx != 0) {
3164 /* AP on Virtual Interface */
3165 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
3166 WL_ERR(("AP Bring up error %d\n", err));
3167 goto exit;
3168 }
3169 }
3170
3171 } else {
3172 WL_ERR(("Wrong interface type %d\n", dev_role));
3173 goto exit;
3174 }
3175
3176 SUPP_LOG(("AP/GO UP\n"));
3177
3178 exit:
3179 if (cfg->wep_key.len) {
3180 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
3181 }
3182
3183 #ifdef MFP
3184 if (cfg->mfp_mode) {
3185 cfg->mfp_mode = 0;
3186 }
3187
3188 if (cfg->bip_pos) {
3189 cfg->bip_pos = NULL;
3190 }
3191 #endif /* MFP */
3192
3193 if (err) {
3194 SUPP_LOG(("AP/GO bring up fail. err:%d\n", err));
3195 /* Cancel work if scheduled */
3196 if (delayed_work_pending(&cfg->ap_work)) {
3197 cancel_delayed_work_sync(&cfg->ap_work);
3198 WL_DBG(("cancelled ap_work\n"));
3199 }
3200 }
3201 return err;
3202 }
3203
3204 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
3205 defined(WL_COMPAT_WIRELESS)
3206 s32
wl_cfg80211_parse_ap_ies(struct net_device * dev,struct cfg80211_beacon_data * info,struct parsed_ies * ies)3207 wl_cfg80211_parse_ap_ies(
3208 struct net_device *dev,
3209 struct cfg80211_beacon_data *info,
3210 struct parsed_ies *ies)
3211 {
3212 struct parsed_ies prb_ies;
3213 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3214 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3215 const u8 *vndr = NULL;
3216 u32 vndr_ie_len = 0;
3217 s32 err = BCME_OK;
3218
3219 /* Parse Beacon IEs */
3220 if (wl_cfg80211_parse_ies((const u8 *)info->tail,
3221 info->tail_len, ies) < 0) {
3222 WL_ERR(("Beacon get IEs failed \n"));
3223 err = -EINVAL;
3224 goto fail;
3225 }
3226
3227 if ((err = wl_cfg80211_config_rsnxe_ie(cfg, dev,
3228 (const u8 *)info->tail, info->tail_len)) < 0) {
3229 WL_ERR(("Failed to configure rsnxe ie: %d\n", err));
3230 err = -EINVAL;
3231 goto fail;
3232 }
3233
3234 vndr = (const u8 *)info->proberesp_ies;
3235 vndr_ie_len = (uint32)info->proberesp_ies_len;
3236
3237 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
3238 /* SoftAP mode */
3239 const struct ieee80211_mgmt *mgmt;
3240 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
3241 if (mgmt != NULL) {
3242 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
3243 vndr_ie_len = (uint32)(info->probe_resp_len -
3244 offsetof(const struct ieee80211_mgmt, u.probe_resp.variable));
3245 }
3246 }
3247 /* Parse Probe Response IEs */
3248 if (wl_cfg80211_parse_ies((const u8 *)vndr, vndr_ie_len, &prb_ies) < 0) {
3249 WL_ERR(("PROBE RESP get IEs failed \n"));
3250 err = -EINVAL;
3251 }
3252 fail:
3253
3254 return err;
3255 }
3256
3257 s32
wl_cfg80211_set_ies(struct net_device * dev,struct cfg80211_beacon_data * info,s32 bssidx)3258 wl_cfg80211_set_ies(
3259 struct net_device *dev,
3260 struct cfg80211_beacon_data *info,
3261 s32 bssidx)
3262 {
3263 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3264 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3265 const u8 *vndr = NULL;
3266 u32 vndr_ie_len = 0;
3267 s32 err = BCME_OK;
3268
3269 /* Set Beacon IEs to FW */
3270 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
3271 VNDR_IE_BEACON_FLAG, (const u8 *)info->tail,
3272 info->tail_len)) < 0) {
3273 WL_ERR(("Set Beacon IE Failed \n"));
3274 } else {
3275 WL_DBG(("Applied Vndr IEs for Beacon \n"));
3276 }
3277
3278 vndr = (const u8 *)info->proberesp_ies;
3279 vndr_ie_len = (uint32)info->proberesp_ies_len;
3280
3281 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
3282 /* SoftAP mode */
3283 const struct ieee80211_mgmt *mgmt;
3284 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
3285 if (mgmt != NULL) {
3286 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
3287 vndr_ie_len = (uint32)(info->probe_resp_len -
3288 offsetof(struct ieee80211_mgmt, u.probe_resp.variable));
3289 }
3290 }
3291
3292 /* Set Probe Response IEs to FW */
3293 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
3294 VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
3295 WL_ERR(("Set Probe Resp IE Failed \n"));
3296 } else {
3297 WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
3298 }
3299
3300 return err;
3301 }
3302 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
3303
wl_cfg80211_hostapd_sec(struct net_device * dev,struct parsed_ies * ies,s32 bssidx)3304 static s32 wl_cfg80211_hostapd_sec(
3305 struct net_device *dev,
3306 struct parsed_ies *ies,
3307 s32 bssidx)
3308 {
3309 bool update_bss = 0;
3310 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3311 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
3312
3313 if (!bss) {
3314 WL_ERR(("cfgbss is NULL \n"));
3315 return -EINVAL;
3316 }
3317
3318 if (ies->wps_ie) {
3319 /* Remove after verification.
3320 * Setting IE part moved to set_ies func
3321 */
3322 if (bss->wps_ie &&
3323 memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
3324 WL_DBG((" WPS IE is changed\n"));
3325 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
3326 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
3327 if (bss->wps_ie) {
3328 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
3329 }
3330 } else if (bss->wps_ie == NULL) {
3331 WL_DBG((" WPS IE is added\n"));
3332 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
3333 if (bss->wps_ie) {
3334 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
3335 }
3336 }
3337
3338 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
3339 if (ies->wpa_ie != NULL && ies->wpa2_ie != NULL) {
3340 WL_ERR(("update bss - wpa_ie and wpa2_ie is not null\n"));
3341 if (!bss->security_mode) {
3342 /* change from open mode to security mode */
3343 update_bss = true;
3344 bss->wpa_ie = MALLOCZ(cfg->osh,
3345 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
3346 if (bss->wpa_ie) {
3347 memcpy(bss->wpa_ie, ies->wpa_ie,
3348 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
3349 }
3350 bss->rsn_ie = MALLOCZ(cfg->osh,
3351 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
3352 if (bss->rsn_ie) {
3353 memcpy(bss->rsn_ie, ies->wpa2_ie,
3354 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
3355 }
3356 } else {
3357 /* change from (WPA or WPA2 or WPA/WPA2) to WPA/WPA2 mixed mode */
3358 if (bss->wpa_ie) {
3359 if (memcmp(bss->wpa_ie,
3360 ies->wpa_ie, ies->wpa_ie->length +
3361 WPA_RSN_IE_TAG_FIXED_LEN)) {
3362 MFREE(cfg->osh, bss->wpa_ie,
3363 bss->wpa_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
3364 update_bss = true;
3365 bss->wpa_ie = MALLOCZ(cfg->osh,
3366 ies->wpa_ie->length
3367 + WPA_RSN_IE_TAG_FIXED_LEN);
3368 if (bss->wpa_ie) {
3369 memcpy(bss->wpa_ie, ies->wpa_ie,
3370 ies->wpa_ie->length
3371 + WPA_RSN_IE_TAG_FIXED_LEN);
3372 }
3373 }
3374 }
3375 else {
3376 update_bss = true;
3377 bss->wpa_ie = MALLOCZ(cfg->osh,
3378 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
3379 if (bss->wpa_ie) {
3380 memcpy(bss->wpa_ie, ies->wpa_ie,
3381 ies->wpa_ie->length
3382 + WPA_RSN_IE_TAG_FIXED_LEN);
3383 }
3384 }
3385 if (bss->rsn_ie) {
3386 if (memcmp(bss->rsn_ie,
3387 ies->wpa2_ie,
3388 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
3389 update_bss = true;
3390 MFREE(cfg->osh, bss->rsn_ie,
3391 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
3392 bss->rsn_ie = MALLOCZ(cfg->osh,
3393 ies->wpa2_ie->len
3394 + WPA_RSN_IE_TAG_FIXED_LEN);
3395 if (bss->rsn_ie) {
3396 memcpy(bss->rsn_ie, ies->wpa2_ie,
3397 ies->wpa2_ie->len
3398 + WPA_RSN_IE_TAG_FIXED_LEN);
3399 }
3400 }
3401 }
3402 else {
3403 update_bss = true;
3404 bss->rsn_ie = MALLOCZ(cfg->osh,
3405 ies->wpa2_ie->len
3406 + WPA_RSN_IE_TAG_FIXED_LEN);
3407 if (bss->rsn_ie) {
3408 memcpy(bss->rsn_ie, ies->wpa2_ie,
3409 ies->wpa2_ie->len
3410 + WPA_RSN_IE_TAG_FIXED_LEN);
3411 }
3412 }
3413 }
3414 WL_ERR(("update_bss=%d\n", update_bss));
3415 if (update_bss) {
3416 bss->security_mode = true;
3417 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
3418 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie,
3419 ies->wpa2_ie, bssidx) < 0) {
3420 return BCME_ERROR;
3421 }
3422 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
3423 }
3424
3425 }
3426 else
3427 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
3428 if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
3429 if (!bss->security_mode) {
3430 /* change from open mode to security mode */
3431 update_bss = true;
3432 if (ies->wpa_ie != NULL) {
3433 bss->wpa_ie = MALLOCZ(cfg->osh,
3434 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
3435 if (bss->wpa_ie) {
3436 memcpy(bss->wpa_ie,
3437 ies->wpa_ie,
3438 ies->wpa_ie->length
3439 + WPA_RSN_IE_TAG_FIXED_LEN);
3440 }
3441 } else {
3442 bss->rsn_ie = MALLOCZ(cfg->osh,
3443 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
3444 if (bss->rsn_ie) {
3445 memcpy(bss->rsn_ie,
3446 ies->wpa2_ie,
3447 ies->wpa2_ie->len
3448 + WPA_RSN_IE_TAG_FIXED_LEN);
3449 }
3450 }
3451 } else if (bss->wpa_ie) {
3452 /* change from WPA2 mode to WPA mode */
3453 if (ies->wpa_ie != NULL) {
3454 update_bss = true;
3455 MFREE(cfg->osh, bss->rsn_ie,
3456 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
3457 bss->rsn_ie = NULL;
3458 bss->wpa_ie = MALLOCZ(cfg->osh,
3459 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
3460 if (bss->wpa_ie) {
3461 memcpy(bss->wpa_ie,
3462 ies->wpa_ie,
3463 ies->wpa_ie->length
3464 + WPA_RSN_IE_TAG_FIXED_LEN);
3465 }
3466 } else if (memcmp(bss->rsn_ie,
3467 ies->wpa2_ie, ies->wpa2_ie->len
3468 + WPA_RSN_IE_TAG_FIXED_LEN)) {
3469 update_bss = true;
3470 MFREE(cfg->osh, bss->rsn_ie,
3471 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
3472 bss->rsn_ie = MALLOCZ(cfg->osh,
3473 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
3474 if (bss->rsn_ie) {
3475 memcpy(bss->rsn_ie,
3476 ies->wpa2_ie,
3477 ies->wpa2_ie->len
3478 + WPA_RSN_IE_TAG_FIXED_LEN);
3479 }
3480 bss->wpa_ie = NULL;
3481 }
3482 }
3483 if (update_bss) {
3484 bss->security_mode = true;
3485 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
3486 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
3487 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
3488 return BCME_ERROR;
3489 }
3490 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
3491 }
3492 }
3493 } else {
3494 WL_ERR(("No WPSIE in beacon \n"));
3495 }
3496 return 0;
3497 }
3498
3499 static s32
wl_cfg80211_set_scb_timings(struct bcm_cfg80211 * cfg,struct net_device * dev)3500 wl_cfg80211_set_scb_timings(
3501 struct bcm_cfg80211 *cfg,
3502 struct net_device *dev)
3503 {
3504 int err;
3505 u32 ps_pretend;
3506 wl_scb_probe_t scb_probe;
3507 u32 ps_pretend_retries;
3508
3509 bzero(&scb_probe, sizeof(wl_scb_probe_t));
3510 scb_probe.scb_timeout = WL_SCB_TIMEOUT;
3511 scb_probe.scb_activity_time = WL_SCB_ACTIVITY_TIME;
3512 scb_probe.scb_max_probe = WL_SCB_MAX_PROBE;
3513 err = wldev_iovar_setbuf(dev, "scb_probe", (void *)&scb_probe,
3514 sizeof(wl_scb_probe_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
3515 &cfg->ioctl_buf_sync);
3516 if (unlikely(err)) {
3517 WL_ERR(("set 'scb_probe' failed, error = %d\n", err));
3518 return err;
3519 }
3520
3521 ps_pretend_retries = WL_PSPRETEND_RETRY_LIMIT;
3522 err = wldev_iovar_setint(dev, "pspretend_retry_limit", ps_pretend_retries);
3523 if (unlikely(err)) {
3524 if (err == BCME_UNSUPPORTED) {
3525 /* Ignore error if fw doesn't support the iovar */
3526 WL_DBG(("set 'pspretend_retry_limit %d' failed, error = %d\n",
3527 ps_pretend_retries, err));
3528 } else {
3529 WL_ERR(("set 'pspretend_retry_limit %d' failed, error = %d\n",
3530 ps_pretend_retries, err));
3531 return err;
3532 }
3533 }
3534
3535 ps_pretend = MAX(WL_SCB_MAX_PROBE / 2, WL_MIN_PSPRETEND_THRESHOLD);
3536 err = wldev_iovar_setint(dev, "pspretend_threshold", ps_pretend);
3537 if (unlikely(err)) {
3538 if (err == BCME_UNSUPPORTED) {
3539 /* Ignore error if fw doesn't support the iovar */
3540 WL_DBG(("wl pspretend_threshold %d set error %d\n",
3541 ps_pretend, err));
3542 } else {
3543 WL_ERR(("wl pspretend_threshold %d set error %d\n",
3544 ps_pretend, err));
3545 return err;
3546 }
3547 }
3548
3549 return 0;
3550 }
3551
3552 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
3553 defined(WL_COMPAT_WIRELESS)
3554 s32
wl_cfg80211_start_ap(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ap_settings * info)3555 wl_cfg80211_start_ap(
3556 struct wiphy *wiphy,
3557 struct net_device *dev,
3558 struct cfg80211_ap_settings *info)
3559 {
3560 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3561 s32 err = BCME_OK;
3562 struct parsed_ies ies;
3563 s32 bssidx = 0;
3564 u32 dev_role = 0;
3565 #ifdef BCMDONGLEHOST
3566 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3567 #endif /* BCMDONGLEHOST */
3568
3569 WL_DBG(("Enter \n"));
3570
3571 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3572 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
3573 return BCME_ERROR;
3574 }
3575
3576 if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
3577 dev_role = NL80211_IFTYPE_P2P_GO;
3578 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
3579
3580 if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
3581 /* Make sure fw is in proper state */
3582 err = wl_cfg80211_set_ap_role(cfg, dev);
3583 if (unlikely(err)) {
3584 WL_ERR(("set ap role failed!\n"));
3585 return BCME_ERROR;
3586 }
3587 }
3588 dev_role = NL80211_IFTYPE_AP;
3589 #ifdef BCMDONGLEHOST
3590 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
3591 err = dhd_ndo_enable(dhd, FALSE);
3592 WL_DBG(("Disabling NDO on Hostapd mode %d\n", err));
3593 if (err) {
3594 WL_ERR(("Disabling NDO Failed %d\n", err));
3595 }
3596 #ifdef WL_EXT_IAPSTA
3597 wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev), WL_IF_TYPE_AP);
3598 #endif /* WL_EXT_IAPSTA */
3599 #ifdef PKT_FILTER_SUPPORT
3600 /* Disable packet filter */
3601 if (dhd->early_suspended) {
3602 WL_ERR(("Disable pkt_filter\n"));
3603 dhd_enable_packet_filter(0, dhd);
3604 #ifdef APF
3605 dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd));
3606 #endif /* APF */
3607 }
3608 #endif /* PKT_FILTER_SUPPORT */
3609 #endif /* BCMDONGLEHOST */
3610 } else {
3611 /* only AP or GO role need to be handled here. */
3612 err = -EINVAL;
3613 goto fail;
3614 }
3615
3616 /* disable TDLS */
3617 #ifdef WLTDLS
3618 if (bssidx == 0) {
3619 /* Disable TDLS for primary Iface. For virtual interface,
3620 * tdls disable will happen from interface create context
3621 */
3622 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_CREATE, false);
3623 }
3624 #endif /* WLTDLS */
3625
3626 if (!check_dev_role_integrity(cfg, dev_role)) {
3627 err = -EINVAL;
3628 goto fail;
3629 }
3630
3631 /*
3632 * TODO:
3633 * Check whether 802.11ac-160MHz bandwidth channel setting has to use the
3634 * center frequencies present in 'preset_chandef' instead of using the
3635 * hardcoded values in 'wl_cfg80211_set_channel()'.
3636 */
3637 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
3638 if (!dev->ieee80211_ptr->preset_chandef.chan) {
3639 WL_ERR(("chan is NULL\n"));
3640 err = -EINVAL;
3641 goto fail;
3642 }
3643 if ((err = wl_cfg80211_set_channel(wiphy, dev,
3644 dev->ieee80211_ptr->preset_chandef.chan,
3645 NL80211_CHAN_HT20) < 0)) {
3646 WL_ERR(("Set channel failed \n"));
3647 goto fail;
3648 }
3649 #endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
3650
3651 if ((err = wl_cfg80211_bcn_set_params(info, dev,
3652 dev_role, bssidx)) < 0) {
3653 WL_ERR(("Beacon params set failed \n"));
3654 goto fail;
3655 }
3656
3657 /* Parse IEs */
3658 if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) {
3659 WL_ERR(("Set IEs failed \n"));
3660 goto fail;
3661 }
3662
3663 if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies,
3664 dev_role, bssidx, info->privacy)) < 0)
3665 {
3666 WL_ERR(("Beacon set security failed \n"));
3667 goto fail;
3668 }
3669
3670 if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies,
3671 dev_role, bssidx)) < 0) {
3672 WL_ERR(("Beacon bring up AP/GO failed \n"));
3673 goto fail;
3674 }
3675
3676 /* Set GC/STA SCB expiry timings. */
3677 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
3678 WL_ERR(("scb setting failed \n"));
3679 // goto fail;
3680 }
3681
3682 wl_set_drv_status(cfg, CONNECTED, dev);
3683 WL_DBG(("** AP/GO Created **\n"));
3684
3685 #ifdef WL_CFG80211_ACL
3686 /* Enfoce Admission Control. */
3687 if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
3688 WL_ERR(("Set ACL failed\n"));
3689 }
3690 #endif /* WL_CFG80211_ACL */
3691
3692 /* Set IEs to FW */
3693 if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
3694 WL_ERR(("Set IEs failed \n"));
3695
3696 #ifdef WLDWDS
3697 if (dev->ieee80211_ptr->use_4addr) {
3698 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
3699 VNDR_IE_ASSOCRSP_FLAG, (const u8 *)info->beacon.assocresp_ies,
3700 info->beacon.assocresp_ies_len)) < 0) {
3701 WL_ERR(("Set ASSOC RESP IE Failed\n"));
3702 }
3703 }
3704 #endif /* WLDWDS */
3705
3706 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
3707 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
3708 bool pbc = 0;
3709 wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
3710 if (pbc) {
3711 WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
3712 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
3713 }
3714 }
3715
3716 /* Configure hidden SSID */
3717 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) {
3718 if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
3719 WL_ERR(("failed to set hidden : %d\n", err));
3720 WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
3721 }
3722
3723 #ifdef SUPPORT_AP_RADIO_PWRSAVE
3724 if (dev_role == NL80211_IFTYPE_AP) {
3725 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
3726 wl_cfg80211_init_ap_rps(cfg);
3727 } else {
3728 WL_ERR(("Set rpsnoa failed \n"));
3729 }
3730 }
3731 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
3732 fail:
3733 if (err) {
3734 WL_ERR(("ADD/SET beacon failed\n"));
3735 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
3736 wl_cfg80211_stop_ap(wiphy, dev);
3737 if (dev_role == NL80211_IFTYPE_AP) {
3738 #ifdef WL_EXT_IAPSTA
3739 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
3740 #endif /* WL_EXT_IAPSTA */
3741 #ifdef BCMDONGLEHOST
3742 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
3743 #ifdef PKT_FILTER_SUPPORT
3744 /* Enable packet filter */
3745 if (dhd->early_suspended) {
3746 WL_ERR(("Enable pkt_filter\n"));
3747 dhd_enable_packet_filter(1, dhd);
3748 #ifdef APF
3749 dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd));
3750 #endif /* APF */
3751 }
3752 #endif /* PKT_FILTER_SUPPORT */
3753 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
3754 wl_cfg80211_set_frameburst(cfg, TRUE);
3755 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
3756 #endif /* BCMDONGLEHOST */
3757 #ifdef WL_EXT_IAPSTA
3758 }
3759 #endif /* WL_EXT_IAPSTA */
3760 }
3761 #ifdef WLTDLS
3762 if (bssidx == 0) {
3763 /* Since AP creation failed, re-enable TDLS */
3764 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
3765 }
3766 #endif /* WLTDLS */
3767
3768 }
3769
3770 return err;
3771 }
3772
3773 s32
wl_cfg80211_stop_ap(struct wiphy * wiphy,struct net_device * dev)3774 wl_cfg80211_stop_ap(
3775 struct wiphy *wiphy,
3776 struct net_device *dev)
3777 {
3778 int err = 0;
3779 u32 dev_role = 0;
3780 int ap = 0;
3781 s32 bssidx = 0;
3782 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3783 s32 is_rsdb_supported = BCME_ERROR;
3784 #ifdef BCMDONGLEHOST
3785 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3786 #endif /* BCMDONGLEHOST */
3787
3788 WL_DBG(("Enter \n"));
3789
3790 if (wl_cfg80211_get_bus_state(cfg)) {
3791 /* since bus is down, iovar will fail. recovery path will bringup the bus. */
3792 WL_ERR(("bus is not ready\n"));
3793 return BCME_OK;
3794 }
3795 #if defined (BCMDONGLEHOST)
3796 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
3797 if (is_rsdb_supported < 0)
3798 return (-ENODEV);
3799 #endif
3800
3801 wl_clr_drv_status(cfg, AP_CREATING, dev);
3802 wl_clr_drv_status(cfg, AP_CREATED, dev);
3803 cfg->ap_oper_channel = INVCHANSPEC;
3804
3805 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
3806 dev_role = NL80211_IFTYPE_AP;
3807 WL_DBG(("stopping AP operation\n"));
3808 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
3809 dev_role = NL80211_IFTYPE_P2P_GO;
3810 WL_DBG(("stopping P2P GO operation\n"));
3811 } else {
3812 WL_ERR(("no AP/P2P GO interface is operational.\n"));
3813 return -EINVAL;
3814 }
3815
3816 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3817 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
3818 return BCME_ERROR;
3819 }
3820
3821 if (!check_dev_role_integrity(cfg, dev_role)) {
3822 WL_ERR(("role integrity check failed \n"));
3823 err = -EINVAL;
3824 goto exit;
3825 }
3826
3827 /* Free up resources */
3828 wl_cfg80211_cleanup_if(dev);
3829
3830 /* Clear AP/GO connected status */
3831 wl_clr_drv_status(cfg, CONNECTED, dev);
3832 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
3833 WL_ERR(("bss down error %d\n", err));
3834 }
3835
3836 if (dev_role == NL80211_IFTYPE_AP) {
3837 #ifdef BCMDONGLEHOST
3838 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
3839 wl_cfg80211_set_frameburst(cfg, TRUE);
3840 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
3841 #endif /* BCMDONGLEHOST */
3842 #ifdef PKT_FILTER_SUPPORT
3843 /* Enable packet filter */
3844 if (dhd->early_suspended) {
3845 WL_ERR(("Enable pkt_filter\n"));
3846 dhd_enable_packet_filter(1, dhd);
3847 #ifdef APF
3848 dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd));
3849 #endif /* APF */
3850 }
3851 #endif /* PKT_FILTER_SUPPORT */
3852
3853 if (is_rsdb_supported == 0) {
3854 /* For non-rsdb chips, we use stand alone AP. Do wl down on stop AP */
3855 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
3856 if (unlikely(err)) {
3857 WL_ERR(("WLC_UP error (%d)\n", err));
3858 err = -EINVAL;
3859 goto exit;
3860 }
3861 }
3862
3863 #ifdef WL_DISABLE_HE_SOFTAP
3864 if (wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP,
3865 TRUE) != BCME_OK) {
3866 WL_ERR(("failed to set he features\n"));
3867 }
3868 #endif /* WL_DISABLE_HE_SOFTAP */
3869
3870 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
3871 #ifdef SUPPORT_AP_RADIO_PWRSAVE
3872 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
3873 wl_cfg80211_init_ap_rps(cfg);
3874 } else {
3875 WL_ERR(("Set rpsnoa failed \n"));
3876 }
3877 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
3878 } else {
3879 /* Do we need to do something here */
3880 WL_DBG(("Stopping P2P GO \n"));
3881
3882 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
3883 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
3884 DHD_EVENT_TIMEOUT_MS*3);
3885 DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub));
3886 #endif
3887
3888 }
3889
3890 SUPP_LOG(("AP/GO Link down\n"));
3891 exit:
3892 if (err) {
3893 /* In case of failure, flush fw logs */
3894 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
3895 SUPP_LOG(("AP/GO Link down fail. err:%d\n", err));
3896 }
3897 #ifdef WLTDLS
3898 if (bssidx == 0) {
3899 /* re-enable TDLS if the number of connected interfaces is less than 2 */
3900 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
3901 }
3902 #endif /* WLTDLS */
3903
3904 #ifdef BCMDONGLEHOST
3905 if (dev_role == NL80211_IFTYPE_AP) {
3906 #ifdef WL_EXT_IAPSTA
3907 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
3908 #endif /* WL_EXT_IAPSTA */
3909 /* clear the AP mode */
3910 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
3911 #ifdef WL_EXT_IAPSTA
3912 }
3913 #endif /* WL_EXT_IAPSTA */
3914 }
3915 #endif /* BCMDONGLEHOST */
3916 return err;
3917 }
3918
3919 s32
wl_cfg80211_change_beacon(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_beacon_data * info)3920 wl_cfg80211_change_beacon(
3921 struct wiphy *wiphy,
3922 struct net_device *dev,
3923 struct cfg80211_beacon_data *info)
3924 {
3925 s32 err = BCME_OK;
3926 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3927 struct parsed_ies ies;
3928 u32 dev_role = 0;
3929 s32 bssidx = 0;
3930 bool pbc = 0;
3931
3932 WL_DBG(("Enter \n"));
3933
3934 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3935 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
3936 return BCME_ERROR;
3937 }
3938
3939 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
3940 dev_role = NL80211_IFTYPE_P2P_GO;
3941 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
3942 dev_role = NL80211_IFTYPE_AP;
3943 } else {
3944 err = -EINVAL;
3945 goto fail;
3946 }
3947
3948 if (!check_dev_role_integrity(cfg, dev_role)) {
3949 err = -EINVAL;
3950 goto fail;
3951 }
3952
3953 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
3954 WL_ERR(("P2P already down status!\n"));
3955 err = BCME_ERROR;
3956 goto fail;
3957 }
3958
3959 /* Parse IEs */
3960 if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) {
3961 WL_ERR(("Parse IEs failed \n"));
3962 goto fail;
3963 }
3964
3965 /* Set IEs to FW */
3966 if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
3967 WL_ERR(("Set IEs failed \n"));
3968 goto fail;
3969 }
3970
3971 if (dev_role == NL80211_IFTYPE_AP) {
3972 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
3973 WL_ERR(("Hostapd update sec failed \n"));
3974 err = -EINVAL;
3975 goto fail;
3976 }
3977 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
3978 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
3979 wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
3980 WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
3981 if (pbc)
3982 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
3983 else
3984 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
3985 }
3986 }
3987
3988 fail:
3989 if (err) {
3990 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
3991 }
3992 return err;
3993 }
3994 #else
3995 s32
wl_cfg80211_add_set_beacon(struct wiphy * wiphy,struct net_device * dev,struct beacon_parameters * info)3996 wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
3997 struct beacon_parameters *info)
3998 {
3999 s32 err = BCME_OK;
4000 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4001 s32 ie_offset = 0;
4002 s32 bssidx = 0;
4003 u32 dev_role = NL80211_IFTYPE_AP;
4004 struct parsed_ies ies;
4005 bcm_tlv_t *ssid_ie;
4006 bool pbc = 0;
4007 bool privacy;
4008 bool is_bss_up = 0;
4009 #ifdef BCMDONGLEHOST
4010 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
4011 #endif /* BCMDONGLEHOST */
4012
4013 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
4014 info->interval, info->dtim_period, info->head_len, info->tail_len));
4015
4016 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
4017 dev_role = NL80211_IFTYPE_AP;
4018 }
4019 #if defined(WL_ENABLE_P2P_IF)
4020 else if (dev == cfg->p2p_net) {
4021 /* Group Add request on p2p0 */
4022 dev = bcmcfg_to_prmry_ndev(cfg);
4023 dev_role = NL80211_IFTYPE_P2P_GO;
4024 }
4025 #endif /* WL_ENABLE_P2P_IF */
4026
4027 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4028 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4029 return BCME_ERROR;
4030 }
4031
4032 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
4033 dev_role = NL80211_IFTYPE_P2P_GO;
4034 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
4035 #ifdef BCMDONGLEHOST
4036 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
4037 #endif
4038 }
4039
4040 if (!check_dev_role_integrity(cfg, dev_role)) {
4041 err = -ENODEV;
4042 goto fail;
4043 }
4044
4045 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
4046 WL_ERR(("P2P already down status!\n"));
4047 err = BCME_ERROR;
4048 goto fail;
4049 }
4050
4051 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
4052 /* find the SSID */
4053 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
4054 info->head_len - ie_offset,
4055 DOT11_MNG_SSID_ID)) != NULL) {
4056 if (dev_role == NL80211_IFTYPE_AP) {
4057 /* Store the hostapd SSID */
4058 bzero(&cfg->hostapd_ssid.SSID[0], DOT11_MAX_SSID_LEN);
4059 cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
4060 memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
4061 cfg->hostapd_ssid.SSID_len);
4062 } else {
4063 /* P2P GO */
4064 bzero(&cfg->p2p->ssid.SSID[0], DOT11_MAX_SSID_LEN);
4065 cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
4066 memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
4067 cfg->p2p->ssid.SSID_len);
4068 }
4069 }
4070
4071 if (wl_cfg80211_parse_ies((u8 *)info->tail,
4072 info->tail_len, &ies) < 0) {
4073 WL_ERR(("Beacon get IEs failed \n"));
4074 err = -EINVAL;
4075 goto fail;
4076 }
4077
4078 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
4079 VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
4080 info->tail_len)) < 0) {
4081 WL_ERR(("Beacon set IEs failed \n"));
4082 goto fail;
4083 } else {
4084 WL_DBG(("Applied Vndr IEs for Beacon \n"));
4085 }
4086
4087 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4088 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
4089 VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies,
4090 info->proberesp_ies_len)) < 0) {
4091 WL_ERR(("ProbeRsp set IEs failed \n"));
4092 goto fail;
4093 } else {
4094 WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
4095 }
4096 #endif
4097
4098 is_bss_up = wl_cfg80211_bss_isup(dev, bssidx);
4099
4100 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4101 privacy = info->privacy;
4102 #else
4103 privacy = 0;
4104 #endif
4105 if (!is_bss_up &&
4106 (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx, privacy) < 0))
4107 {
4108 WL_ERR(("Beacon set security failed \n"));
4109 err = -EINVAL;
4110 goto fail;
4111 }
4112
4113 /* Set BI and DTIM period */
4114 if (info->interval) {
4115 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
4116 &info->interval, sizeof(s32))) < 0) {
4117 WL_ERR(("Beacon Interval Set Error, %d\n", err));
4118 return err;
4119 }
4120 }
4121 if (info->dtim_period) {
4122 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
4123 &info->dtim_period, sizeof(s32))) < 0) {
4124 WL_ERR(("DTIM Interval Set Error, %d\n", err));
4125 return err;
4126 }
4127 }
4128
4129 /* If bss is already up, skip bring up */
4130 if (!is_bss_up &&
4131 (err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0)
4132 {
4133 WL_ERR(("Beacon bring up AP/GO failed \n"));
4134 goto fail;
4135 }
4136
4137 /* Set GC/STA SCB expiry timings. */
4138 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
4139 WL_ERR(("scb setting failed \n"));
4140 if (err == BCME_UNSUPPORTED)
4141 err = 0;
4142 // goto fail;
4143 }
4144
4145 if (wl_get_drv_status(cfg, AP_CREATED, dev)) {
4146 /* Soft AP already running. Update changed params */
4147 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
4148 WL_ERR(("Hostapd update sec failed \n"));
4149 err = -EINVAL;
4150 goto fail;
4151 }
4152 }
4153
4154 /* Enable Probe Req filter */
4155 if (((dev_role == NL80211_IFTYPE_P2P_GO) ||
4156 (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) {
4157 wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
4158 if (pbc)
4159 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
4160 }
4161
4162 WL_DBG(("** ADD/SET beacon done **\n"));
4163 wl_set_drv_status(cfg, CONNECTED, dev);
4164
4165 fail:
4166 if (err) {
4167 WL_ERR(("ADD/SET beacon failed\n"));
4168 #ifdef BCMDONGLEHOST
4169 if (dev_role == NL80211_IFTYPE_AP) {
4170 #ifdef WL_EXT_IAPSTA
4171 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
4172 #endif /* WL_EXT_IAPSTA */
4173 /* clear the AP mode */
4174 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
4175 #ifdef WL_EXT_IAPSTA
4176 }
4177 #endif /* WL_EXT_IAPSTA */
4178 }
4179 #endif /* BCMDONGLEHOST */
4180 }
4181 return err;
4182
4183 }
4184
4185 s32
wl_cfg80211_del_beacon(struct wiphy * wiphy,struct net_device * dev)4186 wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
4187 {
4188 int err = 0;
4189 s32 bssidx = 0;
4190 int infra = 0;
4191 struct wireless_dev *wdev = dev->ieee80211_ptr;
4192 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4193 #ifdef BCMDONGLEHOST
4194 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
4195 #endif /* BCMDONGLEHOST */
4196
4197 WL_DBG(("Enter. \n"));
4198
4199 if (!wdev) {
4200 WL_ERR(("wdev null \n"));
4201 return -EINVAL;
4202 }
4203
4204 if ((wdev->iftype != NL80211_IFTYPE_P2P_GO) && (wdev->iftype != NL80211_IFTYPE_AP)) {
4205 WL_ERR(("Unspported iface type iftype:%d \n", wdev->iftype));
4206 }
4207
4208 wl_clr_drv_status(cfg, AP_CREATING, dev);
4209 wl_clr_drv_status(cfg, AP_CREATED, dev);
4210
4211 /* Clear AP/GO connected status */
4212 wl_clr_drv_status(cfg, CONNECTED, dev);
4213
4214 cfg->ap_oper_channel = INVCHANSPEC;
4215
4216 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4217 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4218 return BCME_ERROR;
4219 }
4220
4221 /* Do bss down */
4222 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
4223 WL_ERR(("bss down error %d\n", err));
4224 }
4225
4226 /* fall through is intentional */
4227 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
4228 if (err < 0) {
4229 WL_ERR(("SET INFRA error %d\n", err));
4230 }
4231 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
4232
4233 #ifdef BCMDONGLEHOST
4234 if (wdev->iftype == NL80211_IFTYPE_AP) {
4235 #ifdef WL_EXT_IAPSTA
4236 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
4237 #endif /* WL_EXT_IAPSTA */
4238 /* clear the AP mode */
4239 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
4240 #ifdef WL_EXT_IAPSTA
4241 }
4242 #endif /* WL_EXT_IAPSTA */
4243 }
4244 #endif /* BCMDONGLEHOST */
4245
4246 return 0;
4247 }
4248 #endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
4249
4250 s32
wl_get_auth_assoc_status(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)4251 wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
4252 const wl_event_msg_t *e, void *data)
4253 {
4254 u32 reason = ntoh32(e->reason);
4255 u32 event = ntoh32(e->event_type);
4256 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
4257
4258 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
4259 (void)memcpy_s(&cfg->event_auth_assoc, sizeof(wl_event_msg_t),
4260 e, sizeof(wl_event_msg_t));
4261 WL_DBG(("event=%d status %d reason %d \n",
4262 ntoh32(cfg->event_auth_assoc.event_type),
4263 ntoh32(cfg->event_auth_assoc.status),
4264 ntoh32(cfg->event_auth_assoc.reason)));
4265 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
4266 if (sec) {
4267 switch (event) {
4268 case WLC_E_ASSOC:
4269 case WLC_E_AUTH:
4270 case WLC_E_AUTH_IND:
4271 sec->auth_assoc_res_status = reason;
4272 break;
4273 default:
4274 break;
4275 }
4276 } else {
4277 WL_ERR(("sec is NULL\n"));
4278 }
4279 return 0;
4280 }
4281
4282 /* The mainline kernel >= 3.2.0 has support for indicating new/del station
4283 * to AP/P2P GO via events. If this change is backported to kernel for which
4284 * this driver is being built, then define WL_CFG80211_STA_EVENT. You
4285 * should use this new/del sta event mechanism for BRCM supplicant >= 22.
4286 */
4287 #if !defined(WL_CFG80211_STA_EVENT) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
4288 static s32
wl_notify_connect_status_ap_legacy(struct bcm_cfg80211 * cfg,struct net_device * ndev const wl_event_msg_t * e,void * data)4289 wl_notify_connect_status_ap_legacy(struct bcm_cfg80211 *cfg, struct net_device *ndev
4290 const wl_event_msg_t *e, void *data)
4291 {
4292 s32 err = 0;
4293 u32 event = ntoh32(e->event_type);
4294 u32 reason = ntoh32(e->reason);
4295 u32 len = ntoh32(e->datalen);
4296 u32 status = ntoh32(e->status);
4297
4298 bool isfree = false;
4299 u8 *mgmt_frame;
4300 u8 bsscfgidx = e->bsscfgidx;
4301 s32 freq;
4302 s32 channel;
4303 u8 *body = NULL;
4304 u16 fc = 0;
4305 u32 body_len = 0;
4306
4307 struct ieee80211_supported_band *band;
4308 struct ether_addr da;
4309 struct ether_addr bssid;
4310 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
4311 channel_info_t ci;
4312 u8 ioctl_buf[WLC_IOCTL_SMLEN];
4313
4314 WL_DBG(("Enter \n"));
4315 if (!len && (event == WLC_E_DEAUTH)) {
4316 len = 2; /* reason code field */
4317 data = &reason;
4318 }
4319 if (len) {
4320 body = (u8 *)MALLOCZ(cfg->osh, len);
4321 if (body == NULL) {
4322 WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
4323 return WL_INVALID;
4324 }
4325 }
4326 bzero(&bssid, ETHER_ADDR_LEN);
4327 WL_DBG(("Enter event %d ndev %p\n", event, ndev));
4328 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
4329 MFREE(cfg->osh, body, len);
4330 return WL_INVALID;
4331 }
4332 if (len)
4333 memcpy(body, data, len);
4334
4335 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
4336 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, NULL);
4337 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
4338 bzero(&bssid, sizeof(bssid));
4339 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
4340 switch (event) {
4341 case WLC_E_ASSOC_IND:
4342 fc = FC_ASSOC_REQ;
4343 break;
4344 case WLC_E_REASSOC_IND:
4345 fc = FC_REASSOC_REQ;
4346 break;
4347 case WLC_E_DISASSOC_IND:
4348 fc = FC_DISASSOC;
4349 break;
4350 case WLC_E_DEAUTH_IND:
4351 fc = FC_DISASSOC;
4352 break;
4353 case WLC_E_DEAUTH:
4354 fc = FC_DISASSOC;
4355 break;
4356 default:
4357 fc = 0;
4358 goto exit;
4359 }
4360 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
4361 if (unlikely(err)) {
4362 MFREE(cfg->osh, body, len);
4363 WL_ERR(("%s: Could not get chanspec %d\n", __FUNCTION__, err));
4364 return err;
4365 }
4366 chanspec = wl_chspec_driver_to_host(chanspec);
4367 freq = wl_channel_to_frequency(wf_chspec_ctlchan(chanspec), CHSPEC_BAND(chanspec));
4368 body_len = len;
4369 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
4370 &mgmt_frame, &len, body);
4371 if (err < 0)
4372 goto exit;
4373 isfree = true;
4374
4375 if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
4376 (event == WLC_E_DISASSOC_IND) ||
4377 ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
4378 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
4379 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
4380 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
4381 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
4382 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
4383 defined(WL_COMPAT_WIRELESS)
4384 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
4385 #else
4386 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
4387 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
4388 }
4389
4390 exit:
4391 if (isfree) {
4392 MFREE(cfg->osh, mgmt_frame, len);
4393 }
4394 if (body) {
4395 MFREE(cfg->osh, body, body_len);
4396 }
4397
4398 }
4399 #endif /* WL_CFG80211_STA_EVENT || KERNEL_VER < 3.2 */
4400
4401 s32
wl_notify_connect_status_ap(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)4402 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
4403 const wl_event_msg_t *e, void *data)
4404 {
4405 s32 err = 0;
4406 u32 event = ntoh32(e->event_type);
4407 u32 reason = ntoh32(e->reason);
4408 u32 len = ntoh32(e->datalen);
4409 u32 status = ntoh32(e->status);
4410 #if defined(WL_CFG80211_STA_EVENT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4411 struct station_info sinfo;
4412 #endif /* (LINUX_VERSION >= VERSION(3,2,0)) || !WL_CFG80211_STA_EVENT */
4413 #ifdef BIGDATA_SOFTAP
4414 dhd_pub_t *dhdp;
4415 #endif /* BIGDATA_SOFTAP */
4416
4417 WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n",
4418 ndev->name, event, ntoh32(e->status), reason));
4419
4420 #ifdef WL_CLIENT_SAE
4421 if (event == WLC_E_AUTH && ntoh32(e->auth_type) == DOT11_SAE) {
4422 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
4423 "add sta auth event for "MACDBG "\n", MAC2STRDBG(e->addr.octet));
4424 err = wl_handle_auth_event(cfg, ndev, e, data);
4425 if (err != BCME_OK) {
4426 return err;
4427 }
4428 }
4429 #endif /* WL_CLIENT_SAE */
4430
4431 if (event == WLC_E_AUTH_IND) {
4432 #ifdef WL_SAE
4433 if (ntoh32(e->auth_type) == DOT11_SAE) {
4434 wl_bss_handle_sae_auth(cfg, ndev, e, data);
4435 }
4436 #endif /* WL_SAE */
4437 wl_get_auth_assoc_status(cfg, ndev, e, data);
4438 return 0;
4439 }
4440 /* if link down, bsscfg is disabled. */
4441 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
4442 wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
4443 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
4444 WL_MSG(ndev->name, "AP mode link down !! \n");
4445 complete(&cfg->iface_disable);
4446 return 0;
4447 }
4448
4449 if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
4450 (reason == WLC_E_REASON_INITIAL_ASSOC) &&
4451 (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
4452 if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
4453 /* AP/GO brought up successfull in firmware */
4454 WL_MSG(ndev->name, "AP/GO Link up\n");
4455 wl_set_drv_status(cfg, AP_CREATED, ndev);
4456 if (delayed_work_pending(&cfg->ap_work)) {
4457 cancel_delayed_work_sync(&cfg->ap_work);
4458 WL_DBG(("cancelled ap_work\n"));
4459 }
4460 #ifdef BIGDATA_SOFTAP
4461 wl_ap_stainfo_init(cfg);
4462 #endif /* BIGDATA_SOFTAP */
4463 #ifdef WL_EXT_IAPSTA
4464 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_AP_ENABLED, NULL);
4465 #endif
4466 return 0;
4467 }
4468 }
4469
4470 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
4471 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
4472 "event %s(%d) status %d reason %d\n",
4473 bcmevent_get_name(event), event, ntoh32(e->status), reason);
4474 }
4475
4476 #ifdef BIGDATA_SOFTAP
4477 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) {
4478 WL_ERR(("AP link down - skip get sta data\n"));
4479 } else {
4480 dhdp = (dhd_pub_t *)(cfg->pub);
4481 if (dhdp && dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
4482 dhd_schedule_gather_ap_stadata(cfg, ndev, e);
4483 }
4484 }
4485 #endif /* BIGDATA_SOFTAP */
4486
4487 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
4488 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
4489 err = wl_notify_connect_status_ap_legacy(cfg, ndev, e, data);
4490 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
4491 memset_s(&sinfo, sizeof(sinfo), 0, sizeof(sinfo));
4492 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
4493 reason == DOT11_SC_SUCCESS) {
4494 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
4495 * STATION_INFO_ASSOC_REQ_IES flag
4496 */
4497 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
4498 sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
4499 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
4500 if (!data) {
4501 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
4502 return -EINVAL;
4503 }
4504 sinfo.assoc_req_ies = data;
4505 sinfo.assoc_req_ies_len = len;
4506 WL_MSG(ndev->name, "new sta event for "MACDBG "\n",
4507 MAC2STRDBG(e->addr.octet));
4508 #ifdef WL_EXT_IAPSTA
4509 wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
4510 WL_EXT_STATUS_STA_CONNECTED, (void *)&e->addr);
4511 #endif
4512 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
4513 #ifdef WL_WPS_SYNC
4514 wl_wps_session_update(ndev, WPS_STATE_LINKUP, e->addr.octet);
4515 #endif /* WL_WPS_SYNC */
4516 } else if ((event == WLC_E_DEAUTH_IND) ||
4517 ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
4518 (event == WLC_E_DISASSOC_IND)) {
4519 /*
4520 * WAR: Dongle sends WLC_E_DEAUTH event with DOT11_RC_RESERVED
4521 * to delete flowring in case of PCIE Full dongle.
4522 * By deleting flowring on SoftAP interface we can avoid any issues
4523 * due to stale/bad state of flowring.
4524 * Therefore, we don't need to notify the client dissaociation to Hostapd
4525 * in this case.
4526 * Please refer to the RB:115182 to understand the case more clearly.
4527 */
4528 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
4529 "del sta event for "MACDBG "\n", MAC2STRDBG(e->addr.octet));
4530 #ifdef WL_EXT_IAPSTA
4531 wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
4532 WL_EXT_STATUS_STA_DISCONNECTED, (void *)&e->addr);
4533 #endif
4534 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
4535 #ifdef WL_WPS_SYNC
4536 wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet);
4537 #endif /* WL_WPS_SYNC */
4538 }
4539
4540 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
4541 return err;
4542 }
4543
4544 s32
wl_frame_get_mgmt(struct bcm_cfg80211 * cfg,u16 fc,const struct ether_addr * da,const struct ether_addr * sa,const struct ether_addr * bssid,u8 ** pheader,u32 * body_len,u8 * pbody)4545 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
4546 const struct ether_addr *da, const struct ether_addr *sa,
4547 const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody)
4548 {
4549 struct dot11_management_header *hdr;
4550 u32 totlen = 0;
4551 s32 err = 0;
4552 u8 *offset;
4553 u32 prebody_len = *body_len;
4554 switch (fc) {
4555 case FC_ASSOC_REQ:
4556 /* capability , listen interval */
4557 totlen = DOT11_ASSOC_REQ_FIXED_LEN;
4558 *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
4559 break;
4560
4561 case FC_REASSOC_REQ:
4562 /* capability, listen inteval, ap address */
4563 totlen = DOT11_REASSOC_REQ_FIXED_LEN;
4564 *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
4565 break;
4566 }
4567 totlen += DOT11_MGMT_HDR_LEN + prebody_len;
4568 *pheader = (u8 *)MALLOCZ(cfg->osh, totlen);
4569 if (*pheader == NULL) {
4570 WL_ERR(("memory alloc failed \n"));
4571 return -ENOMEM;
4572 }
4573 hdr = (struct dot11_management_header *) (*pheader);
4574 hdr->fc = htol16(fc);
4575 hdr->durid = 0;
4576 hdr->seq = 0;
4577 offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
4578 bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
4579 bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
4580 bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
4581 if ((pbody != NULL) && prebody_len)
4582 bcopy((const char*)pbody, offset, prebody_len);
4583 *body_len = totlen;
4584 return err;
4585 }
4586
4587 #if defined(WLTDLS)
wl_cfg80211_is_tdls_tunneled_frame(void * frame,u32 frame_len)4588 bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len)
4589 {
4590 unsigned char *data;
4591
4592 if (frame == NULL) {
4593 WL_ERR(("Invalid frame \n"));
4594 return false;
4595 }
4596
4597 if (frame_len < 5) {
4598 WL_ERR(("Invalid frame length [%d] \n", frame_len));
4599 return false;
4600 }
4601
4602 data = frame;
4603
4604 if (!memcmp(data, TDLS_TUNNELED_PRB_REQ, 5) ||
4605 !memcmp(data, TDLS_TUNNELED_PRB_RESP, 5)) {
4606 WL_DBG(("TDLS Vendor Specific Received type\n"));
4607 return true;
4608 }
4609
4610 return false;
4611 }
4612 #endif /* WLTDLS */
4613
4614 #ifdef WLTDLS
4615 s32
wl_tdls_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)4616 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
4617 const wl_event_msg_t *e, void *data) {
4618
4619 struct net_device *ndev = NULL;
4620 u32 reason = ntoh32(e->reason);
4621 s8 *msg = NULL;
4622
4623 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
4624
4625 switch (reason) {
4626 case WLC_E_TDLS_PEER_DISCOVERED :
4627 msg = " TDLS PEER DISCOVERD ";
4628 break;
4629 case WLC_E_TDLS_PEER_CONNECTED :
4630 if (cfg->tdls_mgmt_frame) {
4631 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
4632 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
4633 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0);
4634 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
4635 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
4636 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0,
4637 GFP_ATOMIC);
4638 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
4639 defined(WL_COMPAT_WIRELESS)
4640 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
4641 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
4642 GFP_ATOMIC);
4643 #else
4644 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
4645 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, GFP_ATOMIC);
4646
4647 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
4648 }
4649 msg = " TDLS PEER CONNECTED ";
4650 #ifdef SUPPORT_SET_CAC
4651 /* TDLS connect reset CAC */
4652 wl_cfg80211_set_cac(cfg, 0);
4653 #endif /* SUPPORT_SET_CAC */
4654 break;
4655 case WLC_E_TDLS_PEER_DISCONNECTED :
4656 if (cfg->tdls_mgmt_frame) {
4657 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
4658 cfg->tdls_mgmt_frame_len = 0;
4659 cfg->tdls_mgmt_freq = 0;
4660 }
4661 msg = "TDLS PEER DISCONNECTED ";
4662 #ifdef SUPPORT_SET_CAC
4663 /* TDLS disconnec, set CAC */
4664 wl_cfg80211_set_cac(cfg, 1);
4665 #endif /* SUPPORT_SET_CAC */
4666 break;
4667 }
4668 if (msg) {
4669 WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((const u8*)(&e->addr)),
4670 (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
4671 }
4672 return 0;
4673
4674 }
4675
4676 #if defined(CUSTOMER_HW10)
wl_tdls_enable(struct bcm_cfg80211 * cfg)4677 static void wl_tdls_enable(struct bcm_cfg80211 *cfg)
4678 {
4679 int enable = true;
4680 int err = 0;
4681 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
4682 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
4683
4684 /* #define IS_P2P_OPERATING (p2p_is_on(cfg) && cfg->p2p->vif_created ) */
4685 #define IS_P2P_OPERATING (dhd->op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))
4686 #if !defined(DISABLE_TDLS_IN_P2P)
4687 if (cfg->vsdb_mode)
4688 #else
4689 if (cfg->vsdb_mode || IS_P2P_OPERATING)
4690 #endif
4691 {
4692 enable = false;
4693 }
4694
4695 err = wldev_iovar_setint(primary_dev, "tdls_enable", enable);
4696 if (err) {
4697 WL_ERR(("tdls_enable failed!!: %d\n", enable));
4698 }
4699 #undef IS_P2P_OPERATING
4700 }
4701 #endif /* defined(CUSTOMER_HW10) */
4702
4703 #endif /* WLTDLS */
4704
4705 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \
4706 defined(WL_COMPAT_WIRELESS)
4707 s32
4708 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || \
4709 ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)))
wl_cfg80211_tdls_mgmt(struct wiphy * wiphy,struct net_device * dev,u8 * peer,u8 action_code,u8 dialog_token,u16 status_code,u32 peer_capability,const u8 * buf,size_t len)4710 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
4711 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
4712 u32 peer_capability, const u8 *buf, size_t len)
4713 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
4714 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
4715 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
4716 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
4717 u32 peer_capability, const u8 *buf, size_t len)
4718 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
4719 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
4720 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
4721 u32 peer_capability, bool initiator, const u8 *buf, size_t len)
4722 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
4723 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
4724 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
4725 const u8 *buf, size_t len)
4726 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
4727 {
4728 s32 ret = 0;
4729 #if defined(BCMDONGLEHOST)
4730 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
4731 struct bcm_cfg80211 *cfg;
4732 tdls_wfd_ie_iovar_t info;
4733 bzero(&info, sizeof(info));
4734 cfg = wl_get_cfg(dev);
4735
4736 #if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
4737 /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
4738 * and that cuases build error
4739 */
4740 BCM_REFERENCE(peer_capability);
4741 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
4742
4743 switch (action_code) {
4744 /* We need to set TDLS Wifi Display IE to firmware
4745 * using tdls_wfd_ie iovar
4746 */
4747 case WLAN_TDLS_SET_PROBE_WFD_IE:
4748 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_PROBE_WFD_IE\n"));
4749 info.mode = TDLS_WFD_PROBE_IE_TX;
4750
4751 if (len > sizeof(info.data)) {
4752 return -EINVAL;
4753 }
4754 memcpy(&info.data, buf, len);
4755 info.length = len;
4756 break;
4757 case WLAN_TDLS_SET_SETUP_WFD_IE:
4758 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_SETUP_WFD_IE\n"));
4759 info.mode = TDLS_WFD_IE_TX;
4760
4761 if (len > sizeof(info.data)) {
4762 return -EINVAL;
4763 }
4764 memcpy(&info.data, buf, len);
4765 info.length = len;
4766 break;
4767 case WLAN_TDLS_SET_WFD_ENABLED:
4768 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_ENABLED\n"));
4769 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
4770 goto out;
4771 case WLAN_TDLS_SET_WFD_DISABLED:
4772 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_DISABLED\n"));
4773 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
4774 goto out;
4775 default:
4776 WL_ERR(("Unsupported action code : %d\n", action_code));
4777 goto out;
4778 }
4779 ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
4780 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4781
4782 if (ret) {
4783 WL_ERR(("tdls_wfd_ie error %d\n", ret));
4784 }
4785
4786 out:
4787 #endif /* TDLS_MSG_ONLY_WFD && WLTDLS */
4788 #endif /* BCMDONGLEHOST */
4789 return ret;
4790 }
4791
4792 s32
4793 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
wl_cfg80211_tdls_oper(struct wiphy * wiphy,struct net_device * dev,const u8 * peer,enum nl80211_tdls_operation oper)4794 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
4795 const u8 *peer, enum nl80211_tdls_operation oper)
4796 #else
4797 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
4798 u8 *peer, enum nl80211_tdls_operation oper)
4799 #endif
4800 {
4801 s32 ret = 0;
4802 #ifdef WLTDLS
4803 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4804 tdls_iovar_t info;
4805 dhd_pub_t *dhdp;
4806 bool tdls_auto_mode = false;
4807 dhdp = (dhd_pub_t *)(cfg->pub);
4808 bzero(&info, sizeof(tdls_iovar_t));
4809 if (peer) {
4810 memcpy(&info.ea, peer, ETHER_ADDR_LEN);
4811 } else {
4812 return -1;
4813 }
4814 switch (oper) {
4815 case NL80211_TDLS_DISCOVERY_REQ:
4816 /* If the discovery request is broadcast then we need to set
4817 * info.mode to Tunneled Probe Request
4818 */
4819 if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
4820 info.mode = TDLS_MANUAL_EP_WFD_TPQ;
4821 WL_ERR(("wl_cfg80211_tdls_oper: TDLS TUNNELED PRBOBE REQUEST\n"));
4822 } else {
4823 info.mode = TDLS_MANUAL_EP_DISCOVERY;
4824 }
4825 break;
4826 case NL80211_TDLS_SETUP:
4827 if (dhdp->tdls_mode == true) {
4828 info.mode = TDLS_MANUAL_EP_CREATE;
4829 tdls_auto_mode = false;
4830 /* Do tear down and create a fresh one */
4831 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_TEARDOWN, tdls_auto_mode);
4832 if (ret < 0) {
4833 return ret;
4834 }
4835 } else {
4836 tdls_auto_mode = true;
4837 }
4838 break;
4839 case NL80211_TDLS_TEARDOWN:
4840 info.mode = TDLS_MANUAL_EP_DELETE;
4841 break;
4842 default:
4843 WL_ERR(("Unsupported operation : %d\n", oper));
4844 goto out;
4845 }
4846 /* turn on TDLS */
4847 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_SETUP, tdls_auto_mode);
4848 if (ret < 0) {
4849 return ret;
4850 }
4851 if (info.mode) {
4852 ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
4853 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4854 if (ret) {
4855 WL_ERR(("tdls_endpoint error %d\n", ret));
4856 }
4857 }
4858 out:
4859 /* use linux generic error code instead of firmware error code */
4860 if (ret) {
4861 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
4862 return -ENOTSUPP;
4863 }
4864 #endif /* WLTDLS */
4865 return ret;
4866 }
4867 #endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
4868
check_dev_role_integrity(struct bcm_cfg80211 * cfg,u32 dev_role)4869 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
4870 {
4871 #if defined(BCMDONGLEHOST)
4872 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
4873 if (((dev_role == NL80211_IFTYPE_AP) &&
4874 !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
4875 ((dev_role == NL80211_IFTYPE_P2P_GO) &&
4876 !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
4877 {
4878 WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
4879 return false;
4880 }
4881 #endif /* defined(BCMDONGLEHOST) */
4882 return true;
4883 }
4884
4885 s32
wl_cfg80211_dfs_ap_move(struct net_device * ndev,char * data,char * command,int total_len)4886 wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int total_len)
4887 {
4888 char ioctl_buf[WLC_IOCTL_SMLEN];
4889 int err = 0;
4890 uint32 val = 0;
4891 chanspec_t chanspec = 0;
4892 int abort;
4893 int bytes_written = 0;
4894 struct wl_dfs_ap_move_status_v2 *status;
4895 char chanbuf[CHANSPEC_STR_LEN];
4896 const char *dfs_state_str[DFS_SCAN_S_MAX] = {
4897 "Radar Free On Channel",
4898 "Radar Found On Channel",
4899 "Radar Scan In Progress",
4900 "Radar Scan Aborted",
4901 "RSDB Mode switch in Progress For Scan"
4902 };
4903 if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
4904 bytes_written = snprintf(command, total_len, "AP is not up\n");
4905 return bytes_written;
4906 }
4907 if (!*data) {
4908 if ((err = wldev_iovar_getbuf(ndev, "dfs_ap_move", NULL, 0,
4909 ioctl_buf, sizeof(ioctl_buf), NULL))) {
4910 WL_ERR(("setting dfs_ap_move failed with err=%d \n", err));
4911 return err;
4912 }
4913 status = (struct wl_dfs_ap_move_status_v2 *)ioctl_buf;
4914
4915 if (status->version != WL_DFS_AP_MOVE_VERSION) {
4916 err = BCME_UNSUPPORTED;
4917 WL_ERR(("err=%d version=%d\n", err, status->version));
4918 return err;
4919 }
4920
4921 if (status->move_status != (int8) DFS_SCAN_S_IDLE) {
4922 chanspec = wl_chspec_driver_to_host(status->chanspec);
4923 if (chanspec != 0 && chanspec != INVCHANSPEC) {
4924 wf_chspec_ntoa(chanspec, chanbuf);
4925 bytes_written = snprintf(command, total_len,
4926 "AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
4927 }
4928 bytes_written += snprintf(command + bytes_written,
4929 total_len - bytes_written,
4930 "%s\n", dfs_state_str[status->move_status]);
4931 return bytes_written;
4932 } else {
4933 bytes_written = snprintf(command, total_len, "dfs AP move in IDLE state\n");
4934 return bytes_written;
4935 }
4936 }
4937
4938 abort = bcm_atoi(data);
4939 if (abort == -1) {
4940 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &abort,
4941 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
4942 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
4943 return err;
4944 }
4945 } else {
4946 chanspec = wf_chspec_aton(data);
4947 if (chanspec != 0) {
4948 val = wl_chspec_host_to_driver(chanspec);
4949 if (val != INVCHANSPEC) {
4950 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &val,
4951 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
4952 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
4953 return err;
4954 }
4955 WL_DBG((" set dfs_ap_move successfull"));
4956 } else {
4957 err = BCME_USAGE_ERROR;
4958 }
4959 }
4960 }
4961 return err;
4962 }
4963
4964 #ifdef WL_CFG80211_ACL
4965 static int
wl_cfg80211_set_mac_acl(struct wiphy * wiphy,struct net_device * cfgdev,const struct cfg80211_acl_data * acl)4966 wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
4967 const struct cfg80211_acl_data *acl)
4968 {
4969 int i;
4970 int ret = 0;
4971 int macnum = 0;
4972 int macmode = MACLIST_MODE_DISABLED;
4973 struct maclist *list;
4974 struct bcm_cfg80211 *cfg = wl_get_cfg(cfgdev);
4975
4976 /* get the MAC filter mode */
4977 if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
4978 macmode = MACLIST_MODE_ALLOW;
4979 } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
4980 acl->n_acl_entries) {
4981 macmode = MACLIST_MODE_DENY;
4982 }
4983
4984 /* if acl == NULL, macmode is still disabled.. */
4985 if (macmode == MACLIST_MODE_DISABLED) {
4986 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0)
4987 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list"
4988 " failed error=%d\n", ret));
4989
4990 return ret;
4991 }
4992
4993 macnum = acl->n_acl_entries;
4994 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
4995 WL_ERR(("wl_cfg80211_set_mac_acl: invalid number of MAC address entries %d\n",
4996 macnum));
4997 return -1;
4998 }
4999
5000 /* allocate memory for the MAC list */
5001 list = (struct maclist *)MALLOC(cfg->osh, sizeof(int) +
5002 sizeof(struct ether_addr) * macnum);
5003 if (!list) {
5004 WL_ERR(("wl_cfg80211_set_mac_acl: failed to allocate memory\n"));
5005 return -1;
5006 }
5007
5008 /* prepare the MAC list */
5009 list->count = htod32(macnum);
5010 for (i = 0; i < macnum; i++) {
5011 memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN);
5012 }
5013 /* set the list */
5014 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0)
5015 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list failed error=%d\n", ret));
5016
5017 MFREE(cfg->osh, list, sizeof(int) +
5018 sizeof(struct ether_addr) * macnum);
5019
5020 return ret;
5021 }
5022 #endif /* WL_CFG80211_ACL */
5023
5024 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
wl_chspec_chandef(chanspec_t chanspec,struct cfg80211_chan_def * chandef,struct wiphy * wiphy)5025 int wl_chspec_chandef(chanspec_t chanspec,
5026 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
5027 struct cfg80211_chan_def *chandef,
5028 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
5029 struct chan_info *chaninfo,
5030 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
5031 struct wiphy *wiphy)
5032 {
5033 uint16 freq = 0;
5034 int chan_type = 0;
5035 int channel = 0;
5036 struct ieee80211_channel *chan;
5037
5038 if (!chandef) {
5039 return -1;
5040 }
5041 channel = CHSPEC_CHANNEL(chanspec);
5042
5043 switch (CHSPEC_BW(chanspec)) {
5044 case WL_CHANSPEC_BW_20:
5045 chan_type = NL80211_CHAN_HT20;
5046 break;
5047 case WL_CHANSPEC_BW_40:
5048 {
5049 if (CHSPEC_SB_UPPER(chanspec)) {
5050 channel += CH_10MHZ_APART;
5051 } else {
5052 channel -= CH_10MHZ_APART;
5053 }
5054 }
5055 chan_type = NL80211_CHAN_HT40PLUS;
5056 break;
5057
5058 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
5059 case WL_CHANSPEC_BW_80:
5060 case WL_CHANSPEC_BW_8080:
5061 {
5062 uint16 sb = CHSPEC_CTL_SB(chanspec);
5063
5064 if (sb == WL_CHANSPEC_CTL_SB_LL) {
5065 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
5066 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
5067 channel -= CH_10MHZ_APART;
5068 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
5069 channel += CH_10MHZ_APART;
5070 } else {
5071 /* WL_CHANSPEC_CTL_SB_UU */
5072 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
5073 }
5074
5075 if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_LU)
5076 chan_type = NL80211_CHAN_HT40MINUS;
5077 else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU)
5078 chan_type = NL80211_CHAN_HT40PLUS;
5079 }
5080 break;
5081 case WL_CHANSPEC_BW_160:
5082 channel = wf_chspec_primary20_chan(chanspec);
5083 /* Using base chan_type as kernel does not define chan_type for 160 MHz */
5084 chan_type = NL80211_CHAN_HT20;
5085 break;
5086 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
5087 default:
5088 chan_type = NL80211_CHAN_HT20;
5089 break;
5090
5091 }
5092 freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chanspec));
5093 chan = ieee80211_get_channel(wiphy, freq);
5094 WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
5095 channel, freq, chan_type, chan));
5096 if (unlikely(!chan)) {
5097 /* fw and cfg80211 channel lists are not in sync */
5098 WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
5099 ASSERT(0);
5100 return -EINVAL;
5101 }
5102
5103 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
5104 cfg80211_chandef_create(chandef, chan, chan_type);
5105 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
5106 chaninfo->freq = freq;
5107 chaninfo->chan_type = chan_type;
5108 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
5109 return 0;
5110 }
5111
5112 void
wl_cfg80211_ch_switch_notify(struct net_device * dev,uint16 chanspec,struct wiphy * wiphy)5113 wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy)
5114 {
5115 u32 freq;
5116 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
5117 struct cfg80211_chan_def chandef;
5118 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
5119 struct chan_info chaninfo;
5120 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
5121
5122 if (!wiphy) {
5123 WL_ERR(("wiphy is null\n"));
5124 return;
5125 }
5126 #if (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0))
5127 /* Channel switch support is only for AP/GO/ADHOC/MESH */
5128 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
5129 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
5130 WL_ERR(("No channel switch notify support for STA/GC\n"));
5131 return;
5132 }
5133 #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
5134
5135 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
5136 if (wl_chspec_chandef(chanspec, &chandef, wiphy))
5137 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
5138 if (wl_chspec_chandef(chanspec, &chaninfo, wiphy))
5139 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
5140 {
5141 WL_ERR(("chspec_chandef failed\n"));
5142 return;
5143 }
5144 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
5145 freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1;
5146 cfg80211_ch_switch_notify(dev, &chandef);
5147 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
5148 freq = chan_info.freq;
5149 cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type);
5150 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
5151
5152 WL_MSG(dev->name, "Channel switch notification for freq: %d chanspec: 0x%x\n",
5153 freq, chanspec);
5154 return;
5155 }
5156 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
5157
5158 static void
wl_ap_channel_ind(struct bcm_cfg80211 * cfg,struct net_device * ndev,chanspec_t chanspec)5159 wl_ap_channel_ind(struct bcm_cfg80211 *cfg,
5160 struct net_device *ndev,
5161 chanspec_t chanspec)
5162 {
5163 u32 channel = LCHSPEC_CHANNEL(chanspec);
5164
5165 WL_INFORM_MEM(("(%s) AP channel:%d chspec:0x%x \n",
5166 ndev->name, channel, chanspec));
5167
5168 #ifdef SUPPORT_AP_BWCTRL
5169 wl_update_apchan_bwcap(cfg, ndev, chanspec);
5170 #endif /* SUPPORT_AP_BWCTRL */
5171
5172 if (!(cfg->ap_oper_channel == INVCHANSPEC) && (cfg->ap_oper_channel != chanspec)) {
5173 /*
5174 * If cached channel is different from the channel indicated
5175 * by the event, notify user space about the channel switch.
5176 */
5177 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
5178 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
5179 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
5180 cfg->ap_oper_channel = chanspec;
5181 }
5182 }
5183
5184 s32
wl_ap_start_ind(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)5185 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
5186 const wl_event_msg_t *e, void *data)
5187 {
5188 struct net_device *ndev = NULL;
5189 chanspec_t chanspec;
5190
5191 WL_DBG(("Enter\n"));
5192 if (unlikely(e->status)) {
5193 WL_ERR(("status:0x%x \n", e->status));
5194 return -1;
5195 }
5196
5197 if (!data) {
5198 return -EINVAL;
5199 }
5200
5201 if (likely(cfgdev)) {
5202 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
5203 chanspec = *((chanspec_t *)data);
5204
5205 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
5206 /* For AP/GO role */
5207 wl_ap_channel_ind(cfg, ndev, chanspec);
5208 }
5209 }
5210
5211 return 0;
5212 }
5213
5214 s32
wl_csa_complete_ind(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)5215 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
5216 const wl_event_msg_t *e, void *data)
5217 {
5218 int error = 0;
5219 u32 chanspec = 0;
5220 struct net_device *ndev = NULL;
5221 struct ether_addr bssid;
5222
5223 WL_DBG(("Enter\n"));
5224 if (unlikely(e->status)) {
5225 WL_ERR(("status:0x%x \n", e->status));
5226 return -1;
5227 }
5228
5229 if (likely(cfgdev)) {
5230 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
5231 /* Get association state if not AP and then query chanspec */
5232 if (!((wl_get_mode_by_netdev(cfg, ndev)) == WL_MODE_AP)) {
5233 error = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
5234 if (error) {
5235 WL_ERR(("CSA on %s. Not associated. error=%d\n",
5236 ndev->name, error));
5237 return BCME_ERROR;
5238 }
5239 }
5240
5241 error = wldev_iovar_getint(ndev, "chanspec", &chanspec);
5242 if (unlikely(error)) {
5243 WL_ERR(("Get chanspec error: %d \n", error));
5244 return -1;
5245 }
5246
5247 WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev->name, chanspec));
5248 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
5249 /* For AP/GO role */
5250 wl_ap_channel_ind(cfg, ndev, chanspec);
5251 } else {
5252 /* STA/GC roles */
5253 if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
5254 WL_ERR(("CSA on %s. Not associated.\n", ndev->name));
5255 return BCME_ERROR;
5256 }
5257 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
5258 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
5259 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
5260 }
5261
5262 }
5263
5264 return 0;
5265 }
5266
5267 #ifdef WLTDLS
5268 s32
wl_cfg80211_tdls_config(struct bcm_cfg80211 * cfg,enum wl_tdls_config state,bool auto_mode)5269 wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg, enum wl_tdls_config state, bool auto_mode)
5270 {
5271 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
5272 int err = 0;
5273 struct net_info *iter, *next;
5274 int update_reqd = 0;
5275 int enable = 0;
5276 dhd_pub_t *dhdp;
5277 dhdp = (dhd_pub_t *)(cfg->pub);
5278
5279 /*
5280 * TDLS need to be enabled only if we have a single STA/GC
5281 * connection.
5282 */
5283
5284 WL_DBG(("Enter state:%d\n", state));
5285 if (!cfg->tdls_supported) {
5286 /* FW doesn't support tdls. Do nothing */
5287 return -ENODEV;
5288 }
5289
5290 /* Protect tdls config session */
5291 mutex_lock(&cfg->tdls_sync);
5292
5293 if (state == TDLS_STATE_TEARDOWN) {
5294 /* Host initiated TDLS tear down */
5295 err = dhd_tdls_enable(ndev, false, auto_mode, NULL);
5296 goto exit;
5297 } else if ((state == TDLS_STATE_AP_CREATE) ||
5298 (state == TDLS_STATE_NMI_CREATE)) {
5299 /* We don't support tdls while AP/GO/NAN is operational */
5300 update_reqd = true;
5301 enable = false;
5302 } else if ((state == TDLS_STATE_CONNECT) || (state == TDLS_STATE_IF_CREATE)) {
5303 if (wl_get_drv_status_all(cfg,
5304 CONNECTED) >= TDLS_MAX_IFACE_FOR_ENABLE) {
5305 /* For STA/GC connect command request, disable
5306 * tdls if we have any concurrent interfaces
5307 * operational.
5308 */
5309 WL_DBG(("Interface limit restriction. disable tdls.\n"));
5310 update_reqd = true;
5311 enable = false;
5312 }
5313 } else if ((state == TDLS_STATE_DISCONNECT) ||
5314 (state == TDLS_STATE_AP_DELETE) ||
5315 (state == TDLS_STATE_SETUP) ||
5316 (state == TDLS_STATE_IF_DELETE)) {
5317 /* Enable back the tdls connection only if we have less than
5318 * or equal to a single STA/GC connection.
5319 */
5320 if (wl_get_drv_status_all(cfg,
5321 CONNECTED) == 0) {
5322 /* If there are no interfaces connected, enable tdls */
5323 update_reqd = true;
5324 enable = true;
5325 } else if (wl_get_drv_status_all(cfg,
5326 CONNECTED) == TDLS_MAX_IFACE_FOR_ENABLE) {
5327 /* We have one interface in CONNECTED state.
5328 * Verify whether its a STA interface before
5329 * we enable back tdls.
5330 */
5331 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
5332 for_each_ndev(cfg, iter, next) {
5333 GCC_DIAGNOSTIC_POP();
5334 if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, ndev)) &&
5335 (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)) {
5336 WL_DBG(("Non STA iface operational. cfg_iftype:%d"
5337 " Can't enable tdls.\n",
5338 ndev->ieee80211_ptr->iftype));
5339 err = -ENOTSUPP;
5340 goto exit;
5341 }
5342 }
5343 /* No AP/GO found. Enable back tdls */
5344 update_reqd = true;
5345 enable = true;
5346 } else {
5347 WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
5348 err = -ENOTSUPP;
5349 goto exit;
5350 }
5351 } else {
5352 WL_ERR(("Unknown tdls state:%d \n", state));
5353 err = -EINVAL;
5354 goto exit;
5355 }
5356
5357 if (update_reqd == true) {
5358 if (dhdp->tdls_enable == enable) {
5359 WL_DBG(("No change in tdls state. Do nothing."
5360 " tdls_enable:%d\n", enable));
5361 goto exit;
5362 }
5363 err = wldev_iovar_setint(ndev, "tdls_enable", enable);
5364 if (unlikely(err)) {
5365 WL_ERR(("tdls_enable setting failed. err:%d\n", err));
5366 goto exit;
5367 } else {
5368 WL_INFORM_MEM(("tdls_enable %d state:%d\n", enable, state));
5369 /* Update the dhd state variable to be in sync */
5370 dhdp->tdls_enable = enable;
5371 if (state == TDLS_STATE_SETUP) {
5372 /* For host initiated setup, apply TDLS params
5373 * Don't propagate errors up for param config
5374 * failures
5375 */
5376 dhd_tdls_enable(ndev, true, auto_mode, NULL);
5377
5378 }
5379 }
5380 } else {
5381 WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
5382 "current_status:%d \n",
5383 state, update_reqd, dhdp->tdls_enable));
5384 }
5385
5386 exit:
5387 if (err) {
5388 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
5389 }
5390 mutex_unlock(&cfg->tdls_sync);
5391 return err;
5392 }
5393 #endif /* WLTDLS */
5394
wl_get_ap_netdev(struct bcm_cfg80211 * cfg,char * ifname)5395 struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname)
5396 {
5397 struct net_info *iter, *next;
5398 struct net_device *ndev = NULL;
5399
5400 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
5401 for_each_ndev(cfg, iter, next) {
5402 GCC_DIAGNOSTIC_POP();
5403 if (iter->ndev) {
5404 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
5405 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
5406 ndev = iter->ndev;
5407 break;
5408 }
5409 }
5410 }
5411 }
5412
5413 return ndev;
5414 }
5415
5416 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
5417 #define WLC_RATE_FLAG 0x80
5418 #define RATE_MASK 0x7f
5419
wl_set_ap_beacon_rate(struct net_device * dev,int val,char * ifname)5420 int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname)
5421 {
5422 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5423 dhd_pub_t *dhdp;
5424 wl_rateset_args_t rs;
5425 int error = BCME_ERROR, i;
5426 struct net_device *ndev = NULL;
5427
5428 dhdp = (dhd_pub_t *)(cfg->pub);
5429
5430 if (dhdp && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
5431 WL_ERR(("Not Hostapd mode\n"));
5432 return BCME_NOTAP;
5433 }
5434
5435 ndev = wl_get_ap_netdev(cfg, ifname);
5436
5437 if (ndev == NULL) {
5438 WL_ERR(("No softAP interface named %s\n", ifname));
5439 return BCME_NOTAP;
5440 }
5441
5442 bzero(&rs, sizeof(wl_rateset_args_t));
5443 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
5444 &rs, sizeof(wl_rateset_args_t), NULL);
5445 if (error < 0) {
5446 WL_ERR(("get rateset failed = %d\n", error));
5447 return error;
5448 }
5449
5450 if (rs.count < 1) {
5451 WL_ERR(("Failed to get rate count\n"));
5452 return BCME_ERROR;
5453 }
5454
5455 /* Host delivers target rate in the unit of 500kbps */
5456 /* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic rate */
5457 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
5458 if (rs.rates[i] & WLC_RATE_FLAG)
5459 if ((rs.rates[i] & RATE_MASK) == val)
5460 break;
5461
5462 /* Valid rate has been delivered as an argument */
5463 if (i < rs.count && i < WL_NUMRATES) {
5464 error = wldev_iovar_setint(ndev, "force_bcn_rspec", val);
5465 if (error < 0) {
5466 WL_ERR(("set beacon rate failed = %d\n", error));
5467 return BCME_ERROR;
5468 }
5469 } else {
5470 WL_ERR(("Rate is invalid"));
5471 return BCME_BADARG;
5472 }
5473
5474 return BCME_OK;
5475 }
5476
5477 int
wl_get_ap_basic_rate(struct net_device * dev,char * command,char * ifname,int total_len)5478 wl_get_ap_basic_rate(struct net_device *dev, char* command, char *ifname, int total_len)
5479 {
5480 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5481 dhd_pub_t *dhdp;
5482 wl_rateset_args_t rs;
5483 int error = BCME_ERROR;
5484 int i, bytes_written = 0;
5485 struct net_device *ndev = NULL;
5486
5487 dhdp = (dhd_pub_t *)(cfg->pub);
5488
5489 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
5490 WL_ERR(("Not Hostapd mode\n"));
5491 return BCME_NOTAP;
5492 }
5493
5494 ndev = wl_get_ap_netdev(cfg, ifname);
5495
5496 if (ndev == NULL) {
5497 WL_ERR(("No softAP interface named %s\n", ifname));
5498 return BCME_NOTAP;
5499 }
5500
5501 bzero(&rs, sizeof(wl_rateset_args_t));
5502 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
5503 &rs, sizeof(wl_rateset_args_t), NULL);
5504 if (error < 0) {
5505 WL_ERR(("get rateset failed = %d\n", error));
5506 return error;
5507 }
5508
5509 if (rs.count < 1) {
5510 WL_ERR(("Failed to get rate count\n"));
5511 return BCME_ERROR;
5512 }
5513
5514 /* Delivers basic rate in the unit of 500kbps to host */
5515 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
5516 if (rs.rates[i] & WLC_RATE_FLAG)
5517 bytes_written += snprintf(command + bytes_written, total_len,
5518 "%d ", rs.rates[i] & RATE_MASK);
5519
5520 /* Remove last space in the command buffer */
5521 if (bytes_written && (bytes_written < total_len)) {
5522 command[bytes_written - 1] = '\0';
5523 bytes_written--;
5524 }
5525
5526 return bytes_written;
5527
5528 }
5529 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
5530
5531 #ifdef SUPPORT_AP_RADIO_PWRSAVE
5532 #define MSEC_PER_MIN (60000L)
5533
5534 static int
_wl_update_ap_rps_params(struct net_device * dev)5535 _wl_update_ap_rps_params(struct net_device *dev)
5536 {
5537 struct bcm_cfg80211 *cfg = NULL;
5538 rpsnoa_iovar_params_t iovar;
5539 u8 smbuf[WLC_IOCTL_SMLEN];
5540
5541 if (!dev)
5542 return BCME_BADARG;
5543
5544 cfg = wl_get_cfg(dev);
5545
5546 bzero(&iovar, sizeof(iovar));
5547 bzero(smbuf, sizeof(smbuf));
5548
5549 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
5550 iovar.hdr.subcmd = WL_RPSNOA_CMD_PARAMS;
5551 iovar.hdr.len = sizeof(iovar);
5552 iovar.param->band = WLC_BAND_ALL;
5553 iovar.param->level = cfg->ap_rps_info.level;
5554 iovar.param->stas_assoc_check = cfg->ap_rps_info.sta_assoc_check;
5555 iovar.param->pps = cfg->ap_rps_info.pps;
5556 iovar.param->quiet_time = cfg->ap_rps_info.quiet_time;
5557
5558 if (wldev_iovar_setbuf(dev, "rpsnoa", &iovar, sizeof(iovar),
5559 smbuf, sizeof(smbuf), NULL)) {
5560 WL_ERR(("Failed to set rpsnoa params"));
5561 return BCME_ERROR;
5562 }
5563
5564 return BCME_OK;
5565 }
5566
5567 int
wl_get_ap_rps(struct net_device * dev,char * command,char * ifname,int total_len)5568 wl_get_ap_rps(struct net_device *dev, char* command, char *ifname, int total_len)
5569 {
5570 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5571 dhd_pub_t *dhdp;
5572 int error = BCME_ERROR;
5573 int bytes_written = 0;
5574 struct net_device *ndev = NULL;
5575 rpsnoa_iovar_status_t iovar;
5576 u8 smbuf[WLC_IOCTL_SMLEN];
5577 u32 chanspec = 0;
5578 u8 idx = 0;
5579 u16 state;
5580 u32 sleep;
5581 u32 time_since_enable;
5582
5583 dhdp = (dhd_pub_t *)(cfg->pub);
5584
5585 if (!dhdp) {
5586 error = BCME_NOTUP;
5587 goto fail;
5588 }
5589
5590 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
5591 WL_ERR(("Not Hostapd mode\n"));
5592 error = BCME_NOTAP;
5593 goto fail;
5594 }
5595
5596 ndev = wl_get_ap_netdev(cfg, ifname);
5597
5598 if (ndev == NULL) {
5599 WL_ERR(("No softAP interface named %s\n", ifname));
5600 error = BCME_NOTAP;
5601 goto fail;
5602 }
5603
5604 bzero(&iovar, sizeof(iovar));
5605 bzero(smbuf, sizeof(smbuf));
5606
5607 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
5608 iovar.hdr.subcmd = WL_RPSNOA_CMD_STATUS;
5609 iovar.hdr.len = sizeof(iovar);
5610 iovar.stats->band = WLC_BAND_ALL;
5611
5612 error = wldev_iovar_getbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
5613 smbuf, sizeof(smbuf), NULL);
5614 if (error < 0) {
5615 WL_ERR(("get ap radio pwrsave failed = %d\n", error));
5616 goto fail;
5617 }
5618
5619 /* RSDB event doesn't seem to be handled correctly.
5620 * So check chanspec of AP directly from the firmware
5621 */
5622 error = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
5623 if (error < 0) {
5624 WL_ERR(("get chanspec from AP failed = %d\n", error));
5625 goto fail;
5626 }
5627
5628 chanspec = wl_chspec_driver_to_host(chanspec);
5629 if (CHSPEC_IS2G(chanspec))
5630 idx = 0;
5631 else if (
5632 #ifdef WL_6G_BAND
5633 CHSPEC_IS6G(chanspec) ||
5634 #endif /* WL_6G_BAND */
5635 CHSPEC_IS5G(chanspec))
5636 idx = 1;
5637 else {
5638 error = BCME_BADCHAN;
5639 goto fail;
5640 }
5641
5642 state = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].state;
5643 sleep = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_dur;
5644 time_since_enable = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_avail_dur;
5645
5646 /* Conver ms to minute, round down only */
5647 sleep = DIV_U64_BY_U32(sleep, MSEC_PER_MIN);
5648 time_since_enable = DIV_U64_BY_U32(time_since_enable, MSEC_PER_MIN);
5649
5650 bytes_written += snprintf(command + bytes_written, total_len,
5651 "state=%d sleep=%d time_since_enable=%d", state, sleep, time_since_enable);
5652 error = bytes_written;
5653
5654 fail:
5655 return error;
5656 }
5657
5658 int
wl_set_ap_rps(struct net_device * dev,bool enable,char * ifname)5659 wl_set_ap_rps(struct net_device *dev, bool enable, char *ifname)
5660 {
5661 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5662 dhd_pub_t *dhdp;
5663 struct net_device *ndev = NULL;
5664 rpsnoa_iovar_t iovar;
5665 u8 smbuf[WLC_IOCTL_SMLEN];
5666 int ret = BCME_OK;
5667
5668 dhdp = (dhd_pub_t *)(cfg->pub);
5669
5670 if (!dhdp) {
5671 ret = BCME_NOTUP;
5672 goto exit;
5673 }
5674
5675 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
5676 WL_ERR(("Not Hostapd mode\n"));
5677 ret = BCME_NOTAP;
5678 goto exit;
5679 }
5680
5681 ndev = wl_get_ap_netdev(cfg, ifname);
5682
5683 if (ndev == NULL) {
5684 WL_ERR(("No softAP interface named %s\n", ifname));
5685 ret = BCME_NOTAP;
5686 goto exit;
5687 }
5688
5689 if (cfg->ap_rps_info.enable != enable) {
5690 cfg->ap_rps_info.enable = enable;
5691 if (enable) {
5692 ret = _wl_update_ap_rps_params(ndev);
5693 if (ret) {
5694 WL_ERR(("Filed to update rpsnoa params\n"));
5695 goto exit;
5696 }
5697 }
5698 bzero(&iovar, sizeof(iovar));
5699 bzero(smbuf, sizeof(smbuf));
5700
5701 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
5702 iovar.hdr.subcmd = WL_RPSNOA_CMD_ENABLE;
5703 iovar.hdr.len = sizeof(iovar);
5704 iovar.data->band = WLC_BAND_ALL;
5705 iovar.data->value = (int16)enable;
5706
5707 ret = wldev_iovar_setbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
5708 smbuf, sizeof(smbuf), NULL);
5709 if (ret) {
5710 WL_ERR(("Failed to enable AP radio power save"));
5711 goto exit;
5712 }
5713 cfg->ap_rps_info.enable = enable;
5714 }
5715 exit:
5716 return ret;
5717 }
5718
5719 int
wl_update_ap_rps_params(struct net_device * dev,ap_rps_info_t * rps,char * ifname)5720 wl_update_ap_rps_params(struct net_device *dev, ap_rps_info_t* rps, char *ifname)
5721 {
5722 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5723 dhd_pub_t *dhdp;
5724 struct net_device *ndev = NULL;
5725
5726 dhdp = (dhd_pub_t *)(cfg->pub);
5727
5728 if (!dhdp)
5729 return BCME_NOTUP;
5730
5731 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
5732 WL_ERR(("Not Hostapd mode\n"));
5733 return BCME_NOTAP;
5734 }
5735
5736 ndev = wl_get_ap_netdev(cfg, ifname);
5737
5738 if (ndev == NULL) {
5739 WL_ERR(("No softAP interface named %s\n", ifname));
5740 return BCME_NOTAP;
5741 }
5742
5743 if (!rps)
5744 return BCME_BADARG;
5745
5746 if (rps->pps < RADIO_PWRSAVE_PPS_MIN)
5747 return BCME_BADARG;
5748
5749 if (rps->level < RADIO_PWRSAVE_LEVEL_MIN ||
5750 rps->level > RADIO_PWRSAVE_LEVEL_MAX)
5751 return BCME_BADARG;
5752
5753 if (rps->quiet_time < RADIO_PWRSAVE_QUIETTIME_MIN)
5754 return BCME_BADARG;
5755
5756 if (rps->sta_assoc_check > RADIO_PWRSAVE_ASSOCCHECK_MAX ||
5757 rps->sta_assoc_check < RADIO_PWRSAVE_ASSOCCHECK_MIN)
5758 return BCME_BADARG;
5759
5760 cfg->ap_rps_info.pps = rps->pps;
5761 cfg->ap_rps_info.level = rps->level;
5762 cfg->ap_rps_info.quiet_time = rps->quiet_time;
5763 cfg->ap_rps_info.sta_assoc_check = rps->sta_assoc_check;
5764
5765 if (cfg->ap_rps_info.enable) {
5766 if (_wl_update_ap_rps_params(ndev)) {
5767 WL_ERR(("Failed to update rpsnoa params"));
5768 return BCME_ERROR;
5769 }
5770 }
5771
5772 return BCME_OK;
5773 }
5774
5775 void
wl_cfg80211_init_ap_rps(struct bcm_cfg80211 * cfg)5776 wl_cfg80211_init_ap_rps(struct bcm_cfg80211 *cfg)
5777 {
5778 cfg->ap_rps_info.enable = FALSE;
5779 cfg->ap_rps_info.sta_assoc_check = RADIO_PWRSAVE_STAS_ASSOC_CHECK;
5780 cfg->ap_rps_info.pps = RADIO_PWRSAVE_PPS;
5781 cfg->ap_rps_info.quiet_time = RADIO_PWRSAVE_QUIET_TIME;
5782 cfg->ap_rps_info.level = RADIO_PWRSAVE_LEVEL;
5783 }
5784 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
5785
5786 int
wl_cfg80211_iface_count(struct net_device * dev)5787 wl_cfg80211_iface_count(struct net_device *dev)
5788 {
5789 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5790 struct net_info *iter, *next;
5791 int iface_count = 0;
5792
5793 /* Return the count of network interfaces (skip netless p2p discovery
5794 * interface)
5795 */
5796 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
5797 for_each_ndev(cfg, iter, next) {
5798 GCC_DIAGNOSTIC_POP();
5799 if (iter->ndev) {
5800 iface_count++;
5801 }
5802 }
5803 return iface_count;
5804 }
5805
5806 typedef struct {
5807 uint16 id;
5808 uint16 len;
5809 uint32 val;
5810 } he_xtlv_v32;
5811
5812 static bool
wl_he_get_uint_cb(void * ctx,uint16 * id,uint16 * len)5813 wl_he_get_uint_cb(void *ctx, uint16 *id, uint16 *len)
5814 {
5815 he_xtlv_v32 *v32 = ctx;
5816
5817 *id = v32->id;
5818 *len = v32->len;
5819
5820 return FALSE;
5821 }
5822
5823 static void
wl_he_pack_uint_cb(void * ctx,uint16 id,uint16 len,uint8 * buf)5824 wl_he_pack_uint_cb(void *ctx, uint16 id, uint16 len, uint8 *buf)
5825 {
5826 he_xtlv_v32 *v32 = ctx;
5827
5828 BCM_REFERENCE(id);
5829 BCM_REFERENCE(len);
5830
5831 v32->val = htod32(v32->val);
5832
5833 switch (v32->len) {
5834 case sizeof(uint8):
5835 *buf = (uint8)v32->val;
5836 break;
5837 case sizeof(uint16):
5838 store16_ua(buf, (uint16)v32->val);
5839 break;
5840 case sizeof(uint32):
5841 store32_ua(buf, v32->val);
5842 break;
5843 default:
5844 /* ASSERT(0); */
5845 break;
5846 }
5847 }
5848
wl_cfg80211_set_he_mode(struct net_device * dev,struct bcm_cfg80211 * cfg,s32 bssidx,u32 he_flag,bool set)5849 int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg,
5850 s32 bssidx, u32 he_flag, bool set)
5851 {
5852 bcm_xtlv_t read_he_xtlv;
5853 uint8 se_he_xtlv[32];
5854 int se_he_xtlv_len = sizeof(se_he_xtlv);
5855 he_xtlv_v32 v32;
5856 u32 he_feature = 0;
5857 s32 err = 0;
5858
5859 read_he_xtlv.id = WL_HE_CMD_FEATURES;
5860 read_he_xtlv.len = 0;
5861 err = wldev_iovar_getbuf_bsscfg(dev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
5862 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, NULL);
5863 if (err < 0) {
5864 WL_ERR(("HE get failed. error=%d\n", err));
5865 return err;
5866 } else {
5867 he_feature = *(int*)cfg->ioctl_buf;
5868 he_feature = dtoh32(he_feature);
5869 }
5870
5871 v32.id = WL_HE_CMD_FEATURES;
5872 v32.len = sizeof(s32);
5873
5874 if (set) {
5875 v32.val = (he_feature | he_flag);
5876 } else {
5877 v32.val = (he_feature & ~he_flag);
5878 }
5879
5880 err = bcm_pack_xtlv_buf((void *)&v32, se_he_xtlv, sizeof(se_he_xtlv),
5881 BCM_XTLV_OPTION_ALIGN32, wl_he_get_uint_cb, wl_he_pack_uint_cb,
5882 &se_he_xtlv_len);
5883 if (err != BCME_OK) {
5884 WL_ERR(("failed to pack he settvl=%d\n", err));
5885 }
5886
5887 err = wldev_iovar_setbuf_bsscfg(dev, "he", &se_he_xtlv, sizeof(se_he_xtlv),
5888 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
5889 if (err < 0) {
5890 WL_ERR(("failed to set he features, error=%d\n", err));
5891 }
5892 WL_INFORM(("Set HE[%d] done\n", set));
5893
5894 return err;
5895 }
5896
5897 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
5898 int
wl_cfg80211_channel_switch(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_csa_settings * params)5899 wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
5900 struct cfg80211_csa_settings *params)
5901 {
5902 s32 err = BCME_OK;
5903 u32 bw = WL_CHANSPEC_BW_20;
5904 chanspec_t chspec = 0;
5905 wl_chan_switch_t csa_arg;
5906 struct cfg80211_chan_def *chandef = ¶ms->chandef;
5907 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5908 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
5909
5910 dev = ndev_to_wlc_ndev(dev, cfg);
5911 chspec = wl_freq_to_chanspec(chandef->chan->center_freq);
5912
5913 WL_ERR(("netdev_ifidx(%d), target channel(%d) target bandwidth(%d),"
5914 " mode(%d), count(%d)\n", dev->ifindex, CHSPEC_CHANNEL(chspec), chandef->width,
5915 params->block_tx, params->count));
5916
5917 if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) {
5918 WL_ERR(("Channel Switch doesn't support on "
5919 "the non-SoftAP mode\n"));
5920 return -EINVAL;
5921 }
5922
5923 /* Check if STA is trying to associate with an AP */
5924 if (wl_get_drv_status(cfg, CONNECTING, primary_dev)) {
5925 WL_ERR(("Connecting is in progress\n"));
5926 return BCME_BUSY;
5927 }
5928
5929 if (chspec == cfg->ap_oper_channel) {
5930 WL_ERR(("Channel %d is same as current operating channel,"
5931 " so skip\n", CHSPEC_CHANNEL(chspec)));
5932 return BCME_OK;
5933 }
5934
5935 if (
5936 #ifdef WL_6G_BAND
5937 CHSPEC_IS6G(chspec) ||
5938 #endif
5939 CHSPEC_IS5G(chspec)) {
5940 #ifdef APSTA_RESTRICTED_CHANNEL
5941 if (CHSPEC_CHANNEL(chspec) != DEFAULT_5G_SOFTAP_CHANNEL) {
5942 WL_ERR(("Invalid 5G Channel, chan=%d\n", CHSPEC_CHANNEL(chspec)));
5943 return -EINVAL;
5944 }
5945 #endif /* APSTA_RESTRICTED_CHANNEL */
5946 err = wl_get_bandwidth_cap(primary_dev, CHSPEC_BAND(chspec), &bw);
5947 if (err < 0) {
5948 WL_ERR(("Failed to get bandwidth information,"
5949 " err=%d\n", err));
5950 return err;
5951 }
5952 } else if (CHSPEC_IS2G(chspec)) {
5953 #ifdef BCMDONGLEHOST
5954 #ifdef APSTA_RESTRICTED_CHANNEL
5955 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
5956 chanspec_t *sta_chanspec = (chanspec_t *)wl_read_prof(cfg,
5957 primary_dev, WL_PROF_CHAN);
5958
5959 /* In 2GHz STA/SoftAP concurrent mode, the operating channel
5960 * of STA and SoftAP should be confgiured to the same 2GHz
5961 * channel. Otherwise, it is an invalid configuration.
5962 */
5963 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
5964 wl_get_drv_status(cfg, CONNECTED, primary_dev) &&
5965 sta_chanspec && (CHSPEC_CHANNEL(*sta_chanspec) != CHSPEC_CHANNEL(chspec))) {
5966 WL_ERR(("Invalid 2G Channel in case of STA/SoftAP"
5967 " concurrent mode, sta_chan=%d, chan=%d\n",
5968 CHSPEC_CHANNEL(*sta_chanspec), CHSPEC_CHANNEL(chspec)));
5969 return -EINVAL;
5970 }
5971 #endif /* APSTA_RESTRICTED_CHANNEL */
5972 #endif /* BCMDONGLEHOST */
5973 bw = WL_CHANSPEC_BW_20;
5974 } else {
5975 WL_ERR(("invalid band (%d)\n", CHSPEC_BAND(chspec)));
5976 return -EINVAL;
5977 }
5978
5979 #ifdef WL_6G_BAND
5980 /* Avoid in case of 6G as for each center frequency bw is unique and is
5981 * detected based on centre frequency.
5982 */
5983 if (!CHSPEC_IS6G(chspec))
5984 #endif /* WL_6G_BAND */
5985 {
5986 chspec = wf_channel2chspec(CHSPEC_CHANNEL(chspec), bw);
5987 }
5988 if (!wf_chspec_valid(chspec)) {
5989 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
5990 return -EINVAL;
5991 }
5992
5993 /* Send CSA to associated STAs */
5994 memset(&csa_arg, 0, sizeof(wl_chan_switch_t));
5995 csa_arg.mode = params->block_tx;
5996 csa_arg.count = params->count;
5997 csa_arg.chspec = chspec;
5998 csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME;
5999 csa_arg.reg = 0;
6000
6001 err = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(wl_chan_switch_t),
6002 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
6003 if (err < 0) {
6004 WL_ERR(("Failed to switch channel, err=%d\n", err));
6005 }
6006
6007 return err;
6008 }
6009 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
6010
6011 #ifdef SUPPORT_AP_SUSPEND
6012 void
wl_set_ap_suspend_error_handler(struct net_device * ndev,bool suspend)6013 wl_set_ap_suspend_error_handler(struct net_device *ndev, bool suspend)
6014 {
6015 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6016 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6017
6018 if (wl_get_drv_status(cfg, READY, ndev)) {
6019 #if defined(BCMDONGLEHOST)
6020 /* IF dongle is down due to previous hang or other conditions, sending
6021 * one more hang notification is not needed.
6022 */
6023 if (dhd_query_bus_erros(dhdp)) {
6024 return;
6025 }
6026 dhdp->iface_op_failed = TRUE;
6027 #if defined(DHD_FW_COREDUMP)
6028 if (dhdp->memdump_enabled) {
6029 dhdp->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
6030 dhd_bus_mem_dump(dhdp);
6031 }
6032 #endif /* DHD_FW_COREDUMP */
6033 #endif /* BCMDONGLEHOST */
6034
6035 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
6036 WL_ERR(("Notify hang event to upper layer \n"));
6037 dhdp->hang_reason = suspend ?
6038 HANG_REASON_BSS_DOWN_FAILURE : HANG_REASON_BSS_UP_FAILURE;
6039 net_os_send_hang_message(ndev);
6040 #endif /* BCMDONGLEHOST && OEM_ANDROID */
6041
6042 }
6043 }
6044
6045 #define MAX_AP_RESUME_TIME 5000
6046 int
wl_set_ap_suspend(struct net_device * dev,bool suspend,char * ifname)6047 wl_set_ap_suspend(struct net_device *dev, bool suspend, char *ifname)
6048 {
6049 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6050 dhd_pub_t *dhdp;
6051 struct net_device *ndev = NULL;
6052 int ret = BCME_OK;
6053 bool is_bssup = FALSE;
6054 int bssidx;
6055 unsigned long start_j;
6056 int time_to_sleep = MAX_AP_RESUME_TIME;
6057
6058 dhdp = (dhd_pub_t *)(cfg->pub);
6059
6060 if (!dhdp) {
6061 return BCME_NOTUP;
6062 }
6063
6064 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
6065 WL_ERR(("Not Hostapd mode\n"));
6066 return BCME_NOTAP;
6067 }
6068
6069 ndev = wl_get_ap_netdev(cfg, ifname);
6070
6071 if (ndev == NULL) {
6072 WL_ERR(("No softAP interface named %s\n", ifname));
6073 return BCME_NOTAP;
6074 }
6075
6076 if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
6077 WL_ERR(("Find p2p index from wdev(%p) failed\n", ndev->ieee80211_ptr));
6078 return BCME_NOTFOUND;
6079 }
6080
6081 is_bssup = wl_cfg80211_bss_isup(ndev, bssidx);
6082 if (is_bssup && suspend) {
6083 wl_clr_drv_status(cfg, AP_CREATED, ndev);
6084 wl_clr_drv_status(cfg, CONNECTED, ndev);
6085
6086 if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 0)) < 0) {
6087 WL_ERR(("AP suspend error %d, suspend %d\n", ret, suspend));
6088 ret = BCME_NOTDOWN;
6089 goto exit;
6090 }
6091 } else if (!is_bssup && !suspend) {
6092 /* Abort scan before starting AP again */
6093 wl_cfgscan_cancel_scan(cfg);
6094
6095 if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 1)) < 0) {
6096 WL_ERR(("AP resume error %d, suspend %d\n", ret, suspend));
6097 ret = BCME_NOTUP;
6098 goto exit;
6099 }
6100
6101 while (TRUE) {
6102 start_j = get_jiffies_64();
6103 /* Wait for Linkup event to mark successful AP bring up */
6104 ret = wait_event_interruptible_timeout(cfg->netif_change_event,
6105 wl_get_drv_status(cfg, AP_CREATED, ndev),
6106 msecs_to_jiffies(time_to_sleep));
6107 if (ret == -ERESTARTSYS) {
6108 WL_ERR(("waitqueue was interrupted by a signal\n"));
6109 time_to_sleep -= jiffies_to_msecs(get_jiffies_64() - start_j);
6110 if (time_to_sleep <= 0) {
6111 WL_ERR(("time to sleep hits 0\n"));
6112 ret = BCME_NOTUP;
6113 goto exit;
6114 }
6115 } else if (ret == 0 || !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
6116 WL_ERR(("AP resume failed!\n"));
6117 ret = BCME_NOTUP;
6118 goto exit;
6119 } else {
6120 wl_set_drv_status(cfg, CONNECTED, ndev);
6121 wl_clr_drv_status(cfg, AP_CREATING, ndev);
6122 ret = BCME_OK;
6123 break;
6124 }
6125 }
6126 } else {
6127 /* bssup + resume or bssdown + suspend,
6128 * So, returns OK
6129 */
6130 ret = BCME_OK;
6131 }
6132 exit:
6133 if (ret != BCME_OK)
6134 wl_set_ap_suspend_error_handler(bcmcfg_to_prmry_ndev(cfg), suspend);
6135
6136 return ret;
6137 }
6138 #endif /* SUPPORT_AP_SUSPEND */
6139
6140 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
wl_set_softap_elna_bypass(struct net_device * dev,char * ifname,int enable)6141 int wl_set_softap_elna_bypass(struct net_device *dev, char *ifname, int enable)
6142 {
6143 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6144 struct net_device *ifdev = NULL;
6145 char iobuf[WLC_IOCTL_SMLEN];
6146 int err = BCME_OK;
6147 int iftype = 0;
6148
6149 memset(iobuf, 0, WLC_IOCTL_SMLEN);
6150
6151 /* Check the interface type */
6152 ifdev = wl_get_netdev_by_name(cfg, ifname);
6153 if (ifdev == NULL) {
6154 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__, ifname));
6155 err = BCME_BADARG;
6156 goto fail;
6157 }
6158
6159 iftype = ifdev->ieee80211_ptr->iftype;
6160 if (iftype == NL80211_IFTYPE_AP) {
6161 err = wldev_iovar_setint(ifdev, "softap_elnabypass", enable);
6162 if (unlikely(err)) {
6163 WL_ERR(("%s: Failed to set softap_elnabypass, err=%d\n",
6164 __FUNCTION__, err));
6165 }
6166 } else {
6167 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
6168 __FUNCTION__));
6169 err = BCME_BADARG;
6170 }
6171 fail:
6172 return err;
6173 }
wl_get_softap_elna_bypass(struct net_device * dev,char * ifname,void * param)6174 int wl_get_softap_elna_bypass(struct net_device *dev, char *ifname, void *param)
6175 {
6176 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6177 int *enable = (int*)param;
6178 struct net_device *ifdev = NULL;
6179 char iobuf[WLC_IOCTL_SMLEN];
6180 int err = BCME_OK;
6181 int iftype = 0;
6182
6183 memset(iobuf, 0, WLC_IOCTL_SMLEN);
6184
6185 /* Check the interface type */
6186 ifdev = wl_get_netdev_by_name(cfg, ifname);
6187 if (ifdev == NULL) {
6188 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__, ifname));
6189 err = BCME_BADARG;
6190 goto fail;
6191 }
6192
6193 iftype = ifdev->ieee80211_ptr->iftype;
6194 if (iftype == NL80211_IFTYPE_AP) {
6195 err = wldev_iovar_getint(ifdev, "softap_elnabypass", enable);
6196 if (unlikely(err)) {
6197 WL_ERR(("%s: Failed to get softap_elnabypass, err=%d\n",
6198 __FUNCTION__, err));
6199 }
6200 } else {
6201 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
6202 __FUNCTION__));
6203 err = BCME_BADARG;
6204 }
6205 fail:
6206 return err;
6207
6208 }
6209 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
6210
6211 #ifdef SUPPORT_AP_BWCTRL
6212 #define OPER_MODE_ENABLE (1 << 8)
6213 static int op2bw[] = {20, 40, 80, 160};
6214
6215 static int
wl_get_ap_he_mode(struct net_device * ndev,struct bcm_cfg80211 * cfg,bool * he)6216 wl_get_ap_he_mode(struct net_device *ndev, struct bcm_cfg80211 *cfg, bool *he)
6217 {
6218 bcm_xtlv_t read_he_xtlv;
6219 int ret = 0;
6220 u8 he_enab = 0;
6221 u32 he_feature = 0;
6222 *he = FALSE;
6223
6224 /* Check he enab first */
6225 read_he_xtlv.id = WL_HE_CMD_ENAB;
6226 read_he_xtlv.len = 0;
6227
6228 ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
6229 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
6230 if (ret < 0) {
6231 if (ret == BCME_UNSUPPORTED) {
6232 /* HE not supported */
6233 ret = BCME_OK;
6234 } else {
6235 WL_ERR(("HE ENAB get failed. ret=%d\n", ret));
6236 }
6237 goto exit;
6238 } else {
6239 he_enab = *(u8*)cfg->ioctl_buf;
6240 }
6241
6242 if (!he_enab) {
6243 goto exit;
6244 }
6245
6246 /* Then check BIT3 of he features */
6247 read_he_xtlv.id = WL_HE_CMD_FEATURES;
6248 read_he_xtlv.len = 0;
6249
6250 ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
6251 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
6252 if (ret < 0) {
6253 WL_ERR(("HE FEATURE get failed. error=%d\n", ret));
6254 goto exit;
6255 } else {
6256 he_feature = *(int*)cfg->ioctl_buf;
6257 he_feature = dtoh32(he_feature);
6258 }
6259
6260 if (he_feature & WL_HE_FEATURES_HE_AP) {
6261 WL_DBG(("HE is enabled in AP\n"));
6262 *he = TRUE;
6263 }
6264 exit:
6265 return ret;
6266 }
6267
6268 static void
wl_update_apchan_bwcap(struct bcm_cfg80211 * cfg,struct net_device * ndev,chanspec_t chanspec)6269 wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg, struct net_device *ndev, chanspec_t chanspec)
6270 {
6271 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
6272 struct wireless_dev *wdev = ndev_to_wdev(dev);
6273 struct wiphy *wiphy = wdev->wiphy;
6274 int ret = BCME_OK;
6275 u32 bw_cap;
6276 u32 ctl_chan;
6277 chanspec_t chanbw = WL_CHANSPEC_BW_20;
6278
6279 /* Update channel in profile */
6280 ctl_chan = wf_chspec_ctlchan(chanspec);
6281 wl_update_prof(cfg, ndev, NULL, &chanspec, WL_PROF_CHAN);
6282
6283 /* BW cap is only updated in 5GHz */
6284 if (ctl_chan <= CH_MAX_2G_CHANNEL)
6285 return;
6286
6287 /* Get WL BW CAP */
6288 ret = wl_get_bandwidth_cap(bcmcfg_to_prmry_ndev(cfg),
6289 CHSPEC_BAND(chanspec), &bw_cap);
6290 if (ret < 0) {
6291 WL_ERR(("get bw_cap failed = %d\n", ret));
6292 goto exit;
6293 }
6294
6295 chanbw = CHSPEC_BW(wl_channel_to_chanspec(wiphy,
6296 ndev, wf_chspec_ctlchan(chanspec), bw_cap));
6297
6298 exit:
6299 cfg->bw_cap_5g = bw2cap[chanbw >> WL_CHANSPEC_BW_SHIFT];
6300 WL_INFORM_MEM(("supported bw cap is:0x%x\n", cfg->bw_cap_5g));
6301
6302 }
6303
6304 int
wl_rxchain_to_opmode_nss(int rxchain)6305 wl_rxchain_to_opmode_nss(int rxchain)
6306 {
6307 /*
6308 * Nss 1 -> 0, Nss 2 -> 1
6309 * This is from operating mode field
6310 * in 8.4.1.50 of 802.11ac-2013
6311 */
6312 /* TODO : Nss 3 ? */
6313 if (rxchain == 3)
6314 return (1 << 4);
6315 else
6316 return 0;
6317 }
6318
6319 int
wl_update_opmode(struct net_device * ndev,u32 bw)6320 wl_update_opmode(struct net_device *ndev, u32 bw)
6321 {
6322 int ret = BCME_OK;
6323 int oper_mode;
6324 int rxchain;
6325
6326 ret = wldev_iovar_getint(ndev, "rxchain", (s32 *)&rxchain);
6327 if (ret < 0) {
6328 WL_ERR(("get rxchain failed = %d\n", ret));
6329 goto exit;
6330 }
6331
6332 oper_mode = bw;
6333 oper_mode |= wl_rxchain_to_opmode_nss(rxchain);
6334 /* Enable flag */
6335 oper_mode |= OPER_MODE_ENABLE;
6336
6337 ret = wldev_iovar_setint(ndev, "oper_mode", oper_mode);
6338 if (ret < 0) {
6339 WL_ERR(("set oper_mode failed = %d\n", ret));
6340 goto exit;
6341 }
6342
6343 exit:
6344 return ret;
6345 }
6346
6347 int
wl_set_ap_bw(struct net_device * dev,u32 bw,char * ifname)6348 wl_set_ap_bw(struct net_device *dev, u32 bw, char *ifname)
6349 {
6350 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6351 dhd_pub_t *dhdp;
6352 struct net_device *ndev = NULL;
6353 int ret = BCME_OK;
6354 chanspec_t *chanspec;
6355 bool he;
6356
6357 dhdp = (dhd_pub_t *)(cfg->pub);
6358
6359 if (!dhdp) {
6360 return BCME_NOTUP;
6361 }
6362
6363 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
6364 WL_ERR(("Not Hostapd mode\n"));
6365 return BCME_NOTAP;
6366 }
6367
6368 ndev = wl_get_ap_netdev(cfg, ifname);
6369
6370 if (ndev == NULL) {
6371 WL_ERR(("No softAP interface named %s\n", ifname));
6372 return BCME_NOTAP;
6373 }
6374
6375 if (bw > DOT11_OPER_MODE_160MHZ) {
6376 WL_ERR(("BW is too big %d\n", bw));
6377 return BCME_BADARG;
6378 }
6379
6380 chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
6381 if (CHSPEC_IS2G(*chanspec)) {
6382 WL_ERR(("current chanspec is %d, not supported\n", *chanspec));
6383 ret = BCME_BADCHAN;
6384 goto exit;
6385 }
6386
6387 if ((DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
6388 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) ||
6389 wl_cfgnan_is_enabled(cfg)) {
6390 WL_ERR(("BW control in concurrent mode is not supported\n"));
6391 return BCME_BUSY;
6392 }
6393
6394 /* When SCAN is on going either in STA or in AP, return BUSY */
6395 if (wl_get_drv_status_all(cfg, SCANNING)) {
6396 WL_ERR(("STA is SCANNING, not support BW control\n"));
6397 return BCME_BUSY;
6398 }
6399
6400 /* When SCANABORT is on going either in STA or in AP, return BUSY */
6401 if (wl_get_drv_status_all(cfg, SCAN_ABORTING)) {
6402 WL_ERR(("STA is SCAN_ABORTING, not support BW control\n"));
6403 return BCME_BUSY;
6404 }
6405
6406 /* When CONNECTION is on going in STA, return BUSY */
6407 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
6408 WL_ERR(("STA is CONNECTING, not support BW control\n"));
6409 return BCME_BUSY;
6410 }
6411
6412 /* BW control in AX mode needs more verification */
6413 ret = wl_get_ap_he_mode(ndev, cfg, &he);
6414 if (ret == BCME_OK && he) {
6415 WL_ERR(("BW control in HE mode is not supported\n"));
6416 return BCME_UNSUPPORTED;
6417 }
6418 if (ret < 0) {
6419 WL_ERR(("Check AX mode is failed\n"));
6420 goto exit;
6421 }
6422
6423 if ((!WL_BW_CAP_160MHZ(cfg->bw_cap_5g) && (bw == DOT11_OPER_MODE_160MHZ)) ||
6424 (!WL_BW_CAP_80MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_80MHZ)) ||
6425 (!WL_BW_CAP_40MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_40MHZ)) ||
6426 (!WL_BW_CAP_20MHZ(cfg->bw_cap_5g))) {
6427 WL_ERR(("bw_cap %x does not support bw = %d\n", cfg->bw_cap_5g, bw));
6428 ret = BCME_BADARG;
6429 goto exit;
6430 }
6431
6432 WL_DBG(("Updating AP BW to %d\n", op2bw[bw]));
6433
6434 ret = wl_update_opmode(ndev, bw);
6435 if (ret < 0) {
6436 WL_ERR(("opmode set failed = %d\n", ret));
6437 goto exit;
6438 }
6439
6440 exit:
6441 return ret;
6442 }
6443
6444 int
wl_get_ap_bw(struct net_device * dev,char * command,char * ifname,int total_len)6445 wl_get_ap_bw(struct net_device *dev, char* command, char *ifname, int total_len)
6446 {
6447 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6448 dhd_pub_t *dhdp;
6449 struct net_device *ndev = NULL;
6450 int ret = BCME_OK;
6451 u32 chanspec = 0;
6452 u32 bw = DOT11_OPER_MODE_20MHZ;
6453 int bytes_written = 0;
6454
6455 dhdp = (dhd_pub_t *)(cfg->pub);
6456
6457 if (!dhdp) {
6458 return BCME_NOTUP;
6459 }
6460
6461 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
6462 WL_ERR(("Not Hostapd mode\n"));
6463 return BCME_NOTAP;
6464 }
6465
6466 ndev = wl_get_ap_netdev(cfg, ifname);
6467
6468 if (ndev == NULL) {
6469 WL_ERR(("No softAP interface named %s\n", ifname));
6470 return BCME_NOTAP;
6471 }
6472
6473 ret = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
6474 if (ret < 0) {
6475 WL_ERR(("get chanspec from AP failed = %d\n", ret));
6476 goto exit;
6477 }
6478
6479 chanspec = wl_chspec_driver_to_host(chanspec);
6480
6481 if (CHSPEC_IS20(chanspec)) {
6482 bw = DOT11_OPER_MODE_20MHZ;
6483 } else if (CHSPEC_IS40(chanspec)) {
6484 bw = DOT11_OPER_MODE_40MHZ;
6485 } else if (CHSPEC_IS80(chanspec)) {
6486 bw = DOT11_OPER_MODE_80MHZ;
6487 } else if (CHSPEC_IS_BW_160_WIDE(chanspec)) {
6488 bw = DOT11_OPER_MODE_160MHZ;
6489 } else {
6490 WL_ERR(("chanspec error %x\n", chanspec));
6491 ret = BCME_BADCHAN;
6492 goto exit;
6493 }
6494
6495 bytes_written += snprintf(command + bytes_written, total_len,
6496 "bw=%d", bw);
6497 ret = bytes_written;
6498 exit:
6499 return ret;
6500 }
6501
6502 void
wl_restore_ap_bw(struct bcm_cfg80211 * cfg)6503 wl_restore_ap_bw(struct bcm_cfg80211 *cfg)
6504 {
6505 int ret = BCME_OK;
6506 u32 bw;
6507 bool he = FALSE;
6508 struct net_info *iter, *next;
6509 struct net_device *ndev = NULL;
6510 chanspec_t *chanspec;
6511
6512 if (!cfg) {
6513 return;
6514 }
6515
6516 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
6517 for_each_ndev(cfg, iter, next) {
6518 GCC_DIAGNOSTIC_POP();
6519 if (iter->ndev) {
6520 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
6521 chanspec = (chanspec_t *)wl_read_prof(cfg, iter->ndev,
6522 WL_PROF_CHAN);
6523 if (CHSPEC_IS2G(*chanspec)) {
6524 ndev = iter->ndev;
6525 break;
6526 }
6527 }
6528 }
6529 }
6530
6531 if (!ndev) {
6532 return;
6533 }
6534
6535 /* BW control in AX mode not allowed */
6536 ret = wl_get_ap_he_mode(bcmcfg_to_prmry_ndev(cfg), cfg, &he);
6537 if (ret == BCME_OK && he) {
6538 return;
6539 }
6540 if (ret < 0) {
6541 WL_ERR(("Check AX mode is failed\n"));
6542 return;
6543 }
6544
6545 if (WL_BW_CAP_160MHZ(cfg->bw_cap_5g)) {
6546 bw = DOT11_OPER_MODE_160MHZ;
6547 } else if (WL_BW_CAP_80MHZ(cfg->bw_cap_5g)) {
6548 bw = DOT11_OPER_MODE_80MHZ;
6549 } else if (WL_BW_CAP_40MHZ(cfg->bw_cap_5g)) {
6550 bw = DOT11_OPER_MODE_40MHZ;
6551 } else {
6552 return;
6553 }
6554
6555 WL_DBG(("Restoring AP BW to %d\n", op2bw[bw]));
6556
6557 ret = wl_update_opmode(ndev, bw);
6558 if (ret < 0) {
6559 WL_ERR(("bw restore failed = %d\n", ret));
6560 return;
6561 }
6562 }
6563 #endif /* SUPPORT_AP_BWCTRL */
6564