From 3fa886cfecbc9a6a73addaec503b3af8dc7a0024 Mon Sep 17 00:00:00 2001
From: Adesh Kumar Singh <adeshkumar.singh@infineon.com>
Date: Fri, 2 Jun 2023 02:10:27 -0500
Subject: [PATCH] non-upstream: Add support for pfn autoswitch

PFN autoswitch support added

Fixes: SWWLAN-146955

Signed-off-by: Adesh Kumar Singh <adeshkumar.singh@infineon.com>
---
 .../broadcom/brcm80211/brcmfmac/cfg80211.c    |  42 +++--
 .../broadcom/brcm80211/brcmfmac/cfg80211.h    |   3 +-
 .../broadcom/brcm80211/brcmfmac/pno.c         | 158 +++---------------
 .../broadcom/brcm80211/brcmfmac/pno.h         |  12 +-
 .../broadcom/brcm80211/brcmfmac/vendor_ifx.c  |  30 ++--
 5 files changed, 71 insertions(+), 174 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 96cef53ca..ee2df3b51 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2819,6 +2819,28 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
 	bool skip_hints = ifp->drvr->settings->fw_ap_select;
 
 	brcmf_dbg(TRACE, "Enter\n");
+
+	if (cfg->pfn_enable && cfg->pfn_connection) {
+		err = brcmf_fil_cmd_data_set(ifp,
+				BRCMF_C_DISASSOC, NULL, 0);
+		if (err) {
+			brcmf_err("BRCMF_C_DISASSOC error:%d\n", err);
+			return -1;
+		}
+		cfg->pfn_connection = 0;
+
+		/* Disable pfn */
+		err = brcmf_fil_iovar_int_set(ifp, "pfn", 0);
+		if (err < 0) {
+			brcmf_err("pfn disable error:%d\n", err);
+		} else {
+			/* clear pfn */
+			err = brcmf_fil_iovar_data_set(ifp, "pfnclear", NULL, 0);
+			if (err)
+				brcmf_err("pfnclear error:%d\n", err);
+		}
+	}
+
 	if (!check_vif_up(ifp->vif))
 		return -EIO;
 
@@ -3024,13 +3046,6 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
 
 	brcmf_set_join_pref(ifp, &sme->bss_select);
 
-	if (cfg->pfn_enable) {
-		err = pfn_save_curr_network(wiphy, ndev, sme);
-		if (err) {
-			brcmf_err("pfn: not able to save the curr network:%d\n", err);
-		}
-	}
-
 	/* The internal supplicant judges to use assoc or reassoc itself.
 	 * it is not necessary to specify REASSOC
 	 */
@@ -3099,7 +3114,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
 	cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
 
 	if (cfg->pfn_enable) {
-		memset(&cfg->curr_network, '\0', sizeof(struct network_blob));
+		cfg->pfn_connection = 0;
 		pfn_send_network_blob_fw(wiphy, &ifp->vif->wdev);
 	}
 
@@ -7904,15 +7919,6 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
 	struct cfg80211_connect_resp_params conn_params;
 
 	brcmf_dbg(TRACE, "Enter cfg->pfn_enable %d\n", cfg->pfn_enable);
-	if (cfg->pfn_enable) {
-		if (!completed) {
-			memset(&cfg->curr_network, '\0', sizeof(struct network_blob));
-			pfn_send_network_blob_fw(cfg->wiphy, &ifp->vif->wdev);
-		}
-		if (cfg->curr_network.ssid_len) {
-			pfn_send_network_blob_fw(cfg->wiphy, &ifp->vif->wdev);
-		}
-	}
 
 	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 			       &ifp->vif->sme_state)) {
@@ -7945,6 +7951,8 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
 		cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
 		brcmf_dbg(CONN, "Report connect result - connection %s\n",
 			  completed ? "succeeded" : "failed");
+	} else if (cfg->pfn_enable && completed) {
+		cfg->pfn_connection = 1;
 	}
 	brcmf_dbg(TRACE, "Exit\n");
 	return 0;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 6e7ba4300..34cb76c38 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -356,6 +356,7 @@ struct network_blob {
 };
 
 struct drv_config_pfn_params {
+	u8 pfn_config;
 	u8 count;
 	struct network_blob *network_blob_data;
 };
@@ -431,8 +432,8 @@ struct brcmf_cfg80211_info {
 	u8 pm_state;
 	u8 num_softap;
 	u8 pfn_enable;
+	u8 pfn_connection;
 	struct drv_config_pfn_params pfn_data;
-	struct network_blob curr_network;
 };
 
 /**
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
index e5cb83585..a1a774d9a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -613,13 +613,11 @@ int pfn_send_network_blob_fw(struct wiphy *wiphy,
 
 	brcmf_dbg(TRACE, "Enter\n");
 
-	if (!cfg->curr_network.ssid_len) {
-		ret = brcmf_fil_cmd_data_set(vif->ifp,
-				BRCMF_C_DISASSOC, NULL, 0);
-		if (ret) {
-			brcmf_err("BRCMF_C_DISASSOC error:%d\n", ret);
-			return -1;
-		}
+	ret = brcmf_fil_cmd_data_set(vif->ifp,
+					BRCMF_C_DISASSOC, NULL, 0);
+	if (ret) {
+		brcmf_err("BRCMF_C_DISASSOC error:%d\n", ret);
+		return -1;
 	}
 	brcmf_pno_clean(ifp);
 
@@ -629,7 +627,7 @@ int pfn_send_network_blob_fw(struct wiphy *wiphy,
 		return -1;
 	}
 
-	if (!cfg->pfn_data.count && !cfg->curr_network.ssid_len)
+	if (!cfg->pfn_data.count)
 		return 0;
 
 	pfn_param.version = PFN_VERSION;
@@ -642,7 +640,18 @@ int pfn_send_network_blob_fw(struct wiphy *wiphy,
 	pfn_param.mscan = DEFAULT_MSCAN;
 	pfn_param.repeat = DEFAULT_REPEAT;
 	pfn_param.exp = DEFAULT_EXP;
-	pfn_param.flags |= AUTO_CONNECT_MASK;
+
+	if (cfg->pfn_data.pfn_config == PFN_CONFIG_AUTOCONNECT) {
+		pfn_param.flags |= AUTO_CONNECT_MASK;
+
+	} else if (cfg->pfn_data.pfn_config == PFN_CONFIG_AUTOSWITCH_LISTORDER) {
+		pfn_param.flags |= AUTO_NET_SWITCH_MASK;
+		pfn_param.flags |= (PFN_LIST_ORDER << SORT_CRITERIA_BIT);
+
+	} else if (cfg->pfn_data.pfn_config == PFN_CONFIG_AUTOSWITCH_RSSI) {
+		pfn_param.flags |= AUTO_NET_SWITCH_MASK;
+		pfn_param.flags |= (PFN_RSSI << SORT_CRITERIA_BIT);
+	}
 
 	pfn_param.version = cpu_to_le32(pfn_param.version);
 	pfn_param.scan_freq = cpu_to_le32(pfn_param.scan_freq);
@@ -660,55 +669,10 @@ int pfn_send_network_blob_fw(struct wiphy *wiphy,
 
 	brcm_pfn_length = (cfg->pfn_data.count) * sizeof(struct brcm_pfn);
 
-	if (cfg->curr_network.ssid_len)
-		brcm_pfn_length += sizeof(struct brcm_pfn);
-
 	pfn_list_buffer = (struct brcm_pfn *)kzalloc(brcm_pfn_length, GFP_KERNEL);
 	pssidnet = pfn_list_buffer;
 	network_blob_data = cfg->pfn_data.network_blob_data;
 
-	if (cfg->curr_network.ssid_len) {
-		pssidnet->auth = WLAN_AUTH_OPEN;
-		pssidnet->wpa_auth = WPA_AUTH_DISABLED;
-		pssidnet->wsec = WPA_CIPHER_NONE;
-		pssidnet->infra = WPAS_MODE_IBSS;
-		pssidnet->flags = 0;
-		memcpy((char *)pssidnet->ssid.SSID, cfg->curr_network.ssid,
-				cfg->curr_network.ssid_len);
-		pssidnet->ssid.SSID_len = cpu_to_le32(cfg->curr_network.ssid_len);
-		pssidnet->flags = cpu_to_le32(pssidnet->flags);
-
-		if (cfg->curr_network.proto == WPA_PROTO_WPA &&
-				cfg->curr_network.key_mgmt == KEY_MGMT_WPA) {
-			pssidnet->wpa_auth = WPA_AUTH_PSK;
-
-		} else if (cfg->curr_network.proto == WPA_PROTO_RSN &&
-				cfg->curr_network.key_mgmt == KEY_MGMT_WPA2) {
-			pssidnet->wpa_auth = WPA2_AUTH_PSK;
-
-		} else if (cfg->curr_network.proto == WPA_PROTO_RSN &&
-				cfg->curr_network.key_mgmt == KEY_MGMT_SAE) {
-			pssidnet->wpa_auth = WPA3_AUTH_SAE_PSK;
-			pssidnet->auth = WLAN_AUTH_SAE;
-
-		} else if (cfg->curr_network.proto == WPA_PROTO_RSN &&
-				cfg->curr_network.key_mgmt == KEY_MGMT_OWE) {
-			pssidnet->wpa_auth = WPA3_AUTH_OWE;
-		}
-
-		if (cfg->curr_network.pairwise_cipher == BIT(WPA_CIPHER_AES_CCM))
-			pssidnet->wsec = AES_ENABLED;
-
-		else if (cfg->curr_network.pairwise_cipher == BIT(WPA_CIPHER_TKIP))
-			pssidnet->wsec = TKIP_ENABLED;
-
-		brcmf_dbg(TRACE, "ssid %s key_mgmt %d proto %d wsec %d wpa_auth %d auth %d\n",
-				cfg->curr_network.ssid, cfg->curr_network.key_mgmt,
-				cfg->curr_network.proto, pssidnet->wsec,
-				pssidnet->wpa_auth, pssidnet->auth);
-		pssidnet++;
-	}
-
 	for (i = 0; i < cfg->pfn_data.count; i++) {
 		/* Default setting, open, no WPA, no WEP and bss */
 		pssidnet->auth = WLAN_AUTH_OPEN;
@@ -721,6 +685,12 @@ int pfn_send_network_blob_fw(struct wiphy *wiphy,
 		pssidnet->ssid.SSID_len = cpu_to_le32(network_blob_data->ssid_len);
 		pssidnet->flags = cpu_to_le32(pssidnet->flags);
 
+		if (strlen(network_blob_data->psk)) {
+			strncpy((char *)pssidnet->psk.key,
+				network_blob_data->psk, WSEC_MAX_PSK_LEN);
+			pssidnet->psk.key_len = strlen(network_blob_data->psk);
+		}
+
 		if (network_blob_data->proto == WPA_PROTO_WPA &&
 				network_blob_data->key_mgmt == KEY_MGMT_WPA) {
 			pssidnet->wpa_auth = WPA_AUTH_PSK;
@@ -767,83 +737,3 @@ int pfn_send_network_blob_fw(struct wiphy *wiphy,
 	brcmf_dbg(TRACE, "Exit\n");
 	return 0;
 }
-
-int pfn_save_curr_network(struct wiphy *wiphy, struct net_device *ndev,
-				struct cfg80211_connect_params *sme)
-{
-	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-	struct brcmf_if *ifp = netdev_priv(ndev);
-	struct brcmf_pub *drvr = ifp->drvr;
-	struct network_blob *curr_network;
-	int ret;
-	s32 val;
-
-	brcmf_dbg(TRACE, "Enter\n");
-	curr_network = &cfg->curr_network;
-	brcmf_pno_clean(ifp);
-
-	if (sme->ssid_len)
-		memcpy(curr_network->ssid, sme->ssid, sme->ssid_len);
-
-	curr_network->ssid_len = sme->ssid_len;
-	ret = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
-	if (ret) {
-		bphy_err(drvr, "could not get wpa_auth (%d)\n", ret);
-		return ret;
-	}
-
-	if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
-		switch (sme->crypto.akm_suites[0]) {
-		case WLAN_AKM_SUITE_8021X:
-			val = WPA_AUTH_UNSPECIFIED;
-			curr_network->proto = (WPA_PROTO_RSN | WPA_PROTO_WPA);
-			curr_network->key_mgmt = KEY_MGMT_WPA_NONE;
-			break;
-		case WLAN_AKM_SUITE_PSK:
-			val = WPA_AUTH_PSK;
-			curr_network->proto = WPA_PROTO_RSN;
-			curr_network->key_mgmt = KEY_MGMT_WPA;
-			break;
-		default:
-			bphy_err(drvr, "invalid cipher group (%d)\n",
-					sme->crypto.cipher_group);
-			return -EINVAL;
-		}
-	} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
-		switch (sme->crypto.akm_suites[0]) {
-		case WLAN_AKM_SUITE_8021X:
-			val = WPA2_AUTH_UNSPECIFIED;
-			curr_network->proto = (WPA_PROTO_RSN | WPA_PROTO_WPA);
-			curr_network->key_mgmt = KEY_MGMT_WPA_NONE;
-			break;
-		case WLAN_AKM_SUITE_PSK:
-			val = WPA2_AUTH_PSK;
-			curr_network->proto = WPA_PROTO_RSN;
-			curr_network->key_mgmt = KEY_MGMT_WPA2;
-			break;
-		case WLAN_AKM_SUITE_OWE:
-			val = WPA3_AUTH_OWE;
-			curr_network->proto = WPA_PROTO_RSN;
-			curr_network->key_mgmt = KEY_MGMT_OWE;
-			break;
-		default:
-			bphy_err(drvr, "invalid cipher group (%d)\n",
-					sme->crypto.cipher_group);
-			return -EINVAL;
-		}
-	} else if (val & WPA3_AUTH_SAE_PSK) {
-		switch (sme->crypto.akm_suites[0]) {
-		case WLAN_AKM_SUITE_SAE:
-			val = WPA3_AUTH_SAE_PSK;
-			curr_network->proto = WPA_PROTO_RSN;
-			curr_network->key_mgmt = KEY_MGMT_SAE;
-			break;
-		default:
-			bphy_err(drvr, "invalid cipher group (%d)\n",
-					sme->crypto.cipher_group);
-			return -EINVAL;
-		}
-	}
-	brcmf_dbg(TRACE, "Exit\n");
-	return 0;
-}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
index 7040d360c..7d4a2c635 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
@@ -17,6 +17,7 @@
 #define WPA_CIPHER_WEP_104              5       /* WEP (104-bit) */
 
 #define AUTO_CONNECT_MASK		0x0010
+#define AUTO_NET_SWITCH_MASK		0x0002
 #define BRCMF_PNO_WPA_AUTH_ANY		0xFFFFFFFF
 #define MAXNUM_SSID_PER_ADD		16
 #define WSEC_MIN_PSK_LEN		8
@@ -24,6 +25,7 @@
 #define DOT11_MAX_SSID_LEN		32      /* d11 max ssid length */
 #define PFN_VERSION			2
 #define PFN_LIST_ORDER			0
+#define PFN_RSSI			1
 #define SORT_CRITERIA_BIT		0
 #define ENABLE				1
 #define IMMEDIATE_SCAN_BIT		3
@@ -34,6 +36,7 @@
 #define WPA_AUTH_DISABLED		0x0000
 #define PFN_SET				1
 #define PFN_UNSET			0
+#define PFN_CONFIG_AND_COUNT_SIZE	2
 #define WLAN_AUTH_OPEN			0
 #define WLAN_AUTH_SHARED_KEY		1
 #define WLAN_AUTH_FT			2
@@ -110,6 +113,12 @@ struct pfn_conn_info {
 	int key_mgmt;
 };
 
+enum {
+	PFN_CONFIG_AUTOCONNECT,
+	PFN_CONFIG_AUTOSWITCH_LISTORDER,
+	PFN_CONFIG_AUTOSWITCH_RSSI,
+};
+
 enum wpas_mode {
 	WPAS_MODE_INFRA = 0,
 	WPAS_MODE_IBSS = 1,
@@ -182,6 +191,3 @@ u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
 
 int pfn_send_network_blob_fw(struct wiphy *wiphy,
 				struct wireless_dev *wdev);
-
-int pfn_save_curr_network(struct wiphy *wiphy, struct net_device *ndev,
-				struct cfg80211_connect_params *sme);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
index a29c2df95..d7168aeb0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
@@ -1040,20 +1040,20 @@ int ifx_cfg80211_vndr_cmds_config_pfn(struct wiphy *wiphy,
 {
 	int buflen;
 	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct drv_config_pfn_params *pfn_data;
 
 	brcmf_dbg(TRACE, "Enter pfn_enable %d Network_blob count %d\n",
 			cfg->pfn_enable, *((u8 *)data));
 
-	if (!cfg->pfn_enable)
-		memset(&cfg->curr_network, '\0', sizeof(struct network_blob));
-
 	cfg->pfn_enable = 1;
-	cfg->pfn_data.count = *((u8 *)data);
+	pfn_data = (struct drv_config_pfn_params *)data;
+	cfg->pfn_data.pfn_config = pfn_data->pfn_config;
+	cfg->pfn_data.count = pfn_data->count;
 
 	buflen = cfg->pfn_data.count * sizeof(struct network_blob);
 	cfg->pfn_data.network_blob_data = (struct network_blob *)kmalloc(buflen, GFP_KERNEL);
 	memset(cfg->pfn_data.network_blob_data, '\0', buflen);
-	memcpy(cfg->pfn_data.network_blob_data, (u8 *)data + sizeof(u8), buflen);
+	memcpy(cfg->pfn_data.network_blob_data, (u8 *)data + PFN_CONFIG_AND_COUNT_SIZE, buflen);
 	pfn_send_network_blob_fw(wiphy, wdev);
 	brcmf_dbg(TRACE, "Exit\n");
 	return 0;
@@ -1106,21 +1106,13 @@ int ifx_cfg80211_vndr_cmds_get_pfn_status(struct wiphy *wiphy,
 		curr_bssid.SNR = bi->SNR;
 
 		network_blob_data = cfg->pfn_data.network_blob_data;
-		if (cfg->curr_network.ssid_len) {
-			if (!strncmp(cfg->curr_network.ssid, bi->SSID, bi->SSID_len)) {
-				curr_bssid.proto = cfg->curr_network.proto;
-				curr_bssid.key_mgmt = cfg->curr_network.key_mgmt;
-			}
-
-		} else {
-			for (; i < cfg->pfn_data.count && network_blob_data; i++) {
-				if (!strncmp(network_blob_data->ssid, bi->SSID, bi->SSID_len)) {
-					curr_bssid.proto = network_blob_data->proto;
-					curr_bssid.key_mgmt = network_blob_data->key_mgmt;
-					break;
-				}
-				network_blob_data++;
+		for (; i < cfg->pfn_data.count && network_blob_data; i++) {
+			if (!strncmp(network_blob_data->ssid, bi->SSID, bi->SSID_len)) {
+				curr_bssid.proto = network_blob_data->proto;
+				curr_bssid.key_mgmt = network_blob_data->key_mgmt;
+				break;
 			}
+			network_blob_data++;
 		}
 	}
 	if (curr_bssid.SSID_len)
-- 
2.39.5 (Apple Git-154)

