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