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