From cf935fd867065385b80e9cbd2ccfb9cbf56d1bb6 Mon Sep 17 00:00:00 2001
From: Carter Chen <carter.chen@infineon.com>
Date: Mon, 25 Dec 2023 01:50:16 -0600
Subject: [PATCH 208/301] brcmfmac: fixing mbss iovar setting for multiple BSS
 is enabled

1.) if the user enabled hostapd on wlan0,
the type of wlan0 changes to AP_TYPE.

2.) then the user uses iw command to created a new interface wlan1,
or wlan2 to AP mode.
the vif->mbss belongs to wlan1, and wlan2 will always is "1"

which causes while the start_ap is called,
it highly relies on the interface's index to set related AP's parameter.

if the first enabling AP interface is not the "first"
interface with vif->mbss is "0",
the upcoming ap interface enabling will fail.

for example,
- hostapd_cli -p /var/run/hostapd -i wlan2 disable
- hostapd_cli -p /var/run/hostapd -i wlan1 disable
- hostapd_cli -p /var/run/hostapd -i wlan0 disable

- hostapd_cli -p /var/run/hostapd -i wlan2 enable  //pass
- hostapd_cli -p /var/run/hostapd -i wlan1 enable  //fail
- hostapd_cli -p /var/run/hostapd -i wlan0 enable  //pass

to make the judgement of check_vif_up can be workable.

the command of disable shall add "ifconfig xxx down".
for example,
- hostapd_cli -p /var/run/hostapd -i wlan2 disable
- ifconfig wlan2 down
- hostapd_cli -p /var/run/hostapd -i wlan1 disable
- ifconfig wlan1 down


Signed-off-by: Carter Chen <carter.chen@infineon.com>
---
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 0e26ca784..82d605b95 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5931,7 +5931,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 	enum nl80211_iftype dev_role;
 	struct brcmf_fil_bss_enable_le bss_enable;
 	u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
-	bool mbss;
+	bool mbss = false;
 	int is_11d;
 	bool supports_11d;
 	bool closednet;
@@ -5945,7 +5945,24 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 		  settings->ssid, settings->ssid_len, settings->auth_type,
 		  settings->inactivity_timeout);
 	dev_role = ifp->vif->wdev.iftype;
-	mbss = ifp->vif->mbss;
+
+	if (dev_role == NL80211_IFTYPE_AP &&
+	    brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
+		struct brcmf_cfg80211_vif *vif_walk;
+
+		list_for_each_entry(vif_walk, &cfg->vif_list, list) {
+			if (brcmf_is_apmode(vif_walk) &&
+			    check_vif_up(vif_walk) &&
+			    vif_walk != ifp->vif) {
+				/* found a vif is with the 1st AP type,
+				 * and it doesn't equal to the currect vif calls start_ap.
+				 * then it is mbss case.
+				 */
+				mbss = true;
+				break;
+			}
+		}
+	}
 	brcmf_dbg(TRACE, "mbss %s\n", mbss ? "enabled" : "disabled");
 
 	/* store current 11d setting */
@@ -6039,8 +6056,29 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 	ifp->isap = false;
 	/* Interface specific setup */
 	if (dev_role == NL80211_IFTYPE_AP) {
-		if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
-			brcmf_fil_iovar_int_set(ifp, "mbss", 1);
+		u32 is_up;
+
+		if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && !mbss) {
+			err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_UP, &is_up);
+			if (err < 0) {
+				bphy_err(drvr, "BRCMF_C_GET_UP error (%d)\n", err);
+				goto exit;
+			}
+
+			/* mbss must be set in DOWN state. */
+			if (is_up) {
+				err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
+				if (err < 0) {
+					bphy_err(drvr, "BRCMF_C_DOWN error (%d)\n", err);
+					goto exit;
+				}
+			}
+			err = brcmf_fil_iovar_int_set(ifp, "mbss", 1);
+			if (err < 0) {
+				bphy_err(drvr, "set mbss error (%d)\n", err);
+				goto exit;
+			}
+		}
 
 		if (!test_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state)) {
 			bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
@@ -6070,7 +6108,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 			goto exit;
 		}
 
-		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
+		err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_UP, &is_up);
+		if (err < 0) {
+			bphy_err(drvr, "BRCMF_C_GET_UP error (%d)\n", err);
+			goto exit;
+		}
+
+		if (!is_up)
+			err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
 		if (err < 0) {
 			bphy_err(drvr, "BRCMF_C_UP error (%d)\n", err);
 			goto exit;
@@ -7281,10 +7326,7 @@ struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings)
 struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
 					   enum nl80211_iftype type)
 {
-	struct brcmf_cfg80211_vif *vif_walk;
 	struct brcmf_cfg80211_vif *vif;
-	bool mbss;
-	struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
 
 	brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
 		  sizeof(*vif));
@@ -7296,19 +7338,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
 	vif->wdev.iftype = type;
 
 	brcmf_init_prof(&vif->profile);
-
-	if (type == NL80211_IFTYPE_AP &&
-	    brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
-		mbss = false;
-		list_for_each_entry(vif_walk, &cfg->vif_list, list) {
-			if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
-				mbss = true;
-				break;
-			}
-		}
-		vif->mbss = mbss;
-	}
-
 	init_completion(&vif->mgmt_tx);
 	list_add_tail(&vif->list, &cfg->vif_list);
 	return vif;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 337023d07..76dafc90b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -245,7 +245,6 @@ struct vif_saved_ie {
  * @sme_state: SME state using enum brcmf_vif_status bits.
  * @list: linked list.
  * @mgmt_rx_reg: registered rx mgmt frame types.
- * @mbss: Multiple BSS type, set if not first AP (not relevant for P2P).
  * @cqm_rssi_low: Lower RSSI limit for CQM monitoring
  * @cqm_rssi_high: Upper RSSI limit for CQM monitoring
  * @cqm_rssi_last: Last RSSI reading for CQM monitoring
@@ -261,7 +260,6 @@ struct brcmf_cfg80211_vif {
 	unsigned long mgmt_tx_status;
 	u32 mgmt_tx_id;
 	u16 mgmt_rx_reg;
-	bool mbss;
 	int is_11d;
 	s32 cqm_rssi_low;
 	s32 cqm_rssi_high;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
index 5547bb6b2..703e98888 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
@@ -65,6 +65,7 @@
 #define BRCMF_C_GET_BANDLIST			140
 #define BRCMF_C_SET_SCB_TIMEOUT			158
 #define BRCMF_C_GET_ASSOCLIST			159
+#define BRCMF_C_GET_UP				162
 #define BRCMF_C_GET_PHYLIST			180
 #define BRCMF_C_SET_SCAN_CHANNEL_TIME		185
 #define BRCMF_C_SET_SCAN_UNASSOC_TIME		187
