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