From c76c913a52989cf90947012d137d78ecc0db6052 Mon Sep 17 00:00:00 2001
From: Adesh Kumar Singh <adeshkumar.singh@infineon.com>
Date: Wed, 8 Mar 2023 22:37:22 -0600
Subject: [PATCH] non-upstream: PFN offload implementation

PFN offload support added
Signed-off-by: adesh kumar singh <adeshkumar.singh@infineon.com>
---
 .../broadcom/brcm80211/brcmfmac/cfg80211.c    |  22 +-
 .../broadcom/brcm80211/brcmfmac/cfg80211.h    |  18 ++
 .../broadcom/brcm80211/brcmfmac/core.c        |   3 +
 .../broadcom/brcm80211/brcmfmac/pno.c         | 248 ++++++++++++++++++
 .../broadcom/brcm80211/brcmfmac/pno.h         | 115 ++++++++
 .../broadcom/brcm80211/brcmfmac/vendor.c      |  14 +
 .../broadcom/brcm80211/brcmfmac/vendor_ifx.c  |  94 +++++++
 .../broadcom/brcm80211/brcmfmac/vendor_ifx.h  |   6 +-
 .../broadcom/brcm80211/include/brcmu_wifi.h   |   3 +
 9 files changed, 520 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 5d6a11919..7827fee7c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -3024,6 +3024,13 @@ 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
 	 */
@@ -3091,6 +3098,11 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
 	clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &ifp->vif->sme_state);
 	cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
 
+	if (cfg->pfn_enable) {
+		memset(&cfg->curr_network, '\0', sizeof(struct network_blob));
+		pfn_send_network_blob_fw(wiphy, &ifp->vif->wdev);
+	}
+
 	memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
 	scbval.val = cpu_to_le32(reason_code);
 	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
@@ -7891,7 +7903,14 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
 	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
 	struct cfg80211_connect_resp_params conn_params;
 
-	brcmf_dbg(TRACE, "Enter\n");
+	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));
+
+		if (strlen(cfg->curr_network.ssid))
+			pfn_send_network_blob_fw(cfg->wiphy, &ifp->vif->wdev);
+	}
 
 	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 			       &ifp->vif->sme_state)) {
@@ -8020,6 +8039,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
 			} else {
 				brcmf_bss_connect_done(cfg, ndev, e, true);
 			}
+			brcmf_bss_connect_done(cfg, ndev, e, true);
 		}
 		brcmf_net_setcarrier(ifp, true);
 	} else if (brcmf_is_linkdown(ifp->vif, e)) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index b339dce79..af069f91f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -344,6 +344,21 @@ struct brcmf_cfg80211_wowl {
 	bool nd_enabled;
 };
 
+struct network_blob {
+	char ssid[32];
+	int key_mgmt;
+	char psk[64];
+	char sae_password[64];
+	u8 proto;
+	u8 pairwise_cipher;
+	u8 frequency;
+};
+
+struct drv_config_pfn_params {
+	u8 count;
+	struct network_blob *network_blob_data;
+};
+
 /**
  * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
  *
@@ -414,6 +429,9 @@ struct brcmf_cfg80211_info {
 	u8 ac_priority[MAX_8021D_PRIO];
 	u8 pm_state;
 	u8 num_softap;
+	u8 pfn_enable;
+	struct drv_config_pfn_params pfn_data;
+	struct network_blob curr_network;
 };
 
 /**
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index fd7e017c6..7f83dae14 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1849,6 +1849,9 @@ void brcmf_detach(struct device *dev)
 	}
 
 	if (drvr->config) {
+		if (drvr->config->pfn_data.network_blob_data)
+			kfree(drvr->config->pfn_data.network_blob_data);
+
 		brcmf_p2p_detach(&drvr->config->p2p);
 		brcmf_cfg80211_detach(drvr->config);
 		drvr->config = NULL;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
index 05f66ab13..a8bb44037 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -12,6 +12,8 @@
 #include "fwil_types.h"
 #include "cfg80211.h"
 #include "pno.h"
+#include "vendor_ifx.h"
+#include <brcmu_wifi.h>
 
 #define BRCMF_PNO_VERSION		2
 #define BRCMF_PNO_REPEAT		4
@@ -593,3 +595,249 @@ u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
 	mutex_unlock(&pi->req_lock);
 	return bucket_map;
 }
+
+int pfn_send_network_blob_fw(struct wiphy *wiphy,
+				struct wireless_dev *wdev)
+{
+	int i, ret;
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_if *ifp;
+	struct network_blob *network_blob_data;
+	brcm_pfn_param_t pfn_param;
+	struct brcm_pfn *pfn_list_buffer, *pssidnet;
+	int brcm_pfn_length = 0;
+
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+	ifp = vif->ifp;
+
+	brcmf_dbg(TRACE, "Enter\n");
+	brcmf_pno_clean(ifp);
+
+	ret = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
+	if (ret) {
+		brcmf_err("sup_wpa set error:%d\n", ret);
+		return -1;
+	}
+
+	if (!cfg->pfn_data.count && !strlen(cfg->curr_network.ssid))
+		return 0;
+
+	pfn_param.version = PFN_VERSION;
+	pfn_param.flags = (PFN_LIST_ORDER << SORT_CRITERIA_BIT | ENABLE << IMMEDIATE_SCAN_BIT);
+	pfn_param.scan_freq = 30;
+	pfn_param.slow_freq = 0;
+	pfn_param.rssi_margin = 10;
+	pfn_param.lost_network_timeout = 60;
+	pfn_param.bestn = DEFAULT_BESTN;
+	pfn_param.mscan = DEFAULT_MSCAN;
+	pfn_param.repeat = DEFAULT_REPEAT;
+	pfn_param.exp = DEFAULT_EXP;
+	pfn_param.flags |= AUTO_CONNECT_MASK;
+
+	pfn_param.version = cpu_to_le32(pfn_param.version);
+	pfn_param.scan_freq = cpu_to_le32(pfn_param.scan_freq);
+	pfn_param.lost_network_timeout = cpu_to_le32(pfn_param.lost_network_timeout);
+	pfn_param.flags = cpu_to_le16(pfn_param.flags);
+	pfn_param.rssi_margin = cpu_to_le16(pfn_param.rssi_margin);
+	pfn_param.slow_freq = cpu_to_le32(pfn_param.slow_freq);
+
+	ret = brcmf_fil_iovar_data_set(ifp, "pfn_set", (void *)&pfn_param,
+					sizeof(brcm_pfn_param_t));
+	if (ret) {
+		brcmf_err("set pfn_set enable error:%d\n", ret);
+		return -1;
+	}
+
+	brcm_pfn_length = (cfg->pfn_data.count) * sizeof(struct brcm_pfn);
+
+	if (strlen(cfg->curr_network.ssid))
+		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 (strlen(cfg->curr_network.ssid)) {
+		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,
+				strlen(cfg->curr_network.ssid));
+		pssidnet->ssid.SSID_len = cpu_to_le32(strlen(cfg->curr_network.ssid));
+		pssidnet->flags = cpu_to_le32(pssidnet->flags);
+
+		if (cfg->curr_network.proto == KEY_MGMT_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;
+		pssidnet->wpa_auth = WPA_AUTH_DISABLED;
+		pssidnet->wsec = WPA_CIPHER_NONE;
+		pssidnet->infra = WPAS_MODE_IBSS;
+		pssidnet->flags = 0;
+		memcpy((char *)pssidnet->ssid.SSID, network_blob_data->ssid,
+				strlen(network_blob_data->ssid));
+		pssidnet->ssid.SSID_len = cpu_to_le32(strlen(network_blob_data->ssid));
+		pssidnet->flags = cpu_to_le32(pssidnet->flags);
+
+		if (network_blob_data->proto == KEY_MGMT_WPA &&
+				network_blob_data->key_mgmt == KEY_MGMT_WPA) {
+			pssidnet->wpa_auth = WPA_AUTH_PSK;
+			pssidnet->wsec = AES_ENABLED;
+
+		} else if (network_blob_data->proto == WPA_PROTO_RSN &&
+				network_blob_data->key_mgmt == KEY_MGMT_WPA2) {
+			pssidnet->wpa_auth = WPA2_AUTH_PSK;
+			pssidnet->wsec = AES_ENABLED;
+
+		} else if (network_blob_data->proto == WPA_PROTO_RSN &&
+				network_blob_data->key_mgmt == KEY_MGMT_SAE) {
+			pssidnet->wpa_auth = WPA3_AUTH_SAE_PSK;
+			pssidnet->wsec = AES_ENABLED;
+			pssidnet->auth = WLAN_AUTH_SAE;
+
+		} else if (network_blob_data->proto == WPA_PROTO_RSN &&
+				network_blob_data->key_mgmt == KEY_MGMT_OWE) {
+			pssidnet->wpa_auth = WPA3_AUTH_OWE;
+			pssidnet->wsec = AES_ENABLED;
+		}
+
+		if (network_blob_data->pairwise_cipher == BIT(WPA_CIPHER_AES_CCM))
+			pssidnet->wsec = AES_ENABLED;
+
+		else if (network_blob_data->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",
+				network_blob_data->ssid, network_blob_data->key_mgmt,
+				network_blob_data->proto, pssidnet->wsec,
+				pssidnet->wpa_auth, pssidnet->auth);
+		pssidnet++;
+		network_blob_data++;
+	}
+
+	ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", (void *)pfn_list_buffer, brcm_pfn_length);
+	if (ret) {
+		brcmf_err("set pfnadd enable error:%d\n", ret);
+		return -1;
+	}
+	ret =  brcmf_fil_iovar_int_set(ifp, "pfn", PFN_SET);
+	if (ret) {
+		brcmf_err("set pfn error:%d\n", ret);
+		return -1;
+	}
+	kfree(pfn_list_buffer);
+	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)
+		memcpy(curr_network->ssid, sme->ssid, 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 25d406019..7040d360c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
@@ -10,6 +10,115 @@
 #define BRCMF_PNO_SCHED_SCAN_MIN_PERIOD	10
 #define BRCMF_PNO_SCHED_SCAN_MAX_PERIOD	508
 
+#define WPA_CIPHER_NONE                 0       /* None */
+#define WPA_CIPHER_WEP_40               1       /* WEP (40-bit) */
+#define WPA_CIPHER_TKIP                 2       /* TKIP: default for WPA */
+#define WPA_CIPHER_AES_CCM              4       /* AES (CCM) */
+#define WPA_CIPHER_WEP_104              5       /* WEP (104-bit) */
+
+#define AUTO_CONNECT_MASK		0x0010
+#define BRCMF_PNO_WPA_AUTH_ANY		0xFFFFFFFF
+#define MAXNUM_SSID_PER_ADD		16
+#define WSEC_MIN_PSK_LEN		8
+#define WSEC_MAX_PSK_LEN		64
+#define DOT11_MAX_SSID_LEN		32      /* d11 max ssid length */
+#define PFN_VERSION			2
+#define PFN_LIST_ORDER			0
+#define SORT_CRITERIA_BIT		0
+#define ENABLE				1
+#define IMMEDIATE_SCAN_BIT		3
+#define DEFAULT_BESTN			2
+#define DEFAULT_MSCAN			0
+#define DEFAULT_REPEAT			10
+#define DEFAULT_EXP			2
+#define WPA_AUTH_DISABLED		0x0000
+#define PFN_SET				1
+#define PFN_UNSET			0
+#define WLAN_AUTH_OPEN			0
+#define WLAN_AUTH_SHARED_KEY		1
+#define WLAN_AUTH_FT			2
+#define WLAN_AUTH_SAE			3
+
+#define KEY_MGMT_WPA			0x00000001
+#define KEY_MGMT_WPA2			0x00000002
+#define KEY_MGMT_WPA_PSK		0x00000004
+#define KEY_MGMT_WPA2_PSK		0x00000008
+#define KEY_MGMT_WPA_NONE		0x00000010
+#define KEY_MGMT_FT			0x00000020
+#define KEY_MGMT_FT_PSK			0x00000040
+#define KEY_MGMT_WAPI_PSK		0x00000080
+#define KEY_MGMT_SUITE_B		0x00000100
+#define KEY_MGMT_SUITE_B_192		0x00000200
+#define KEY_MGMT_OWE			0x00000400
+#define KEY_MGMT_DPP			0x00000800
+#define KEY_MGMT_FILS_SHA256		0x00001000
+#define KEY_MGMT_FILS_SHA384		0x00002000
+#define KEY_MGMT_FT_FILS_SHA256		0x00004000
+#define KEY_MGMT_FT_FILS_SHA384		0x00008000
+#define KEY_MGMT_SAE			0x00010000
+#define KEY_MGMT_802_1X_SHA256		0x00020000
+#define KEY_MGMT_PSK_SHA256		0x00040000
+#define KEY_MGMT_TPK_HANDSHAKE		0x00080000
+#define KEY_MGMT_FT_SAE			0x00100000
+#define KEY_MGMT_FT_802_1X_SHA384	0x00200000
+#define KEY_MGMT_CCKM			0x00400000
+#define KEY_MGMT_OSEN			0x00800000
+
+typedef struct brcm_pfn_param {
+	s32 version;
+	s32 scan_freq;
+	s32 lost_network_timeout;
+	s16 flags;
+	s16 rssi_margin;
+	u8 bestn;
+	u8 mscan;
+	u8 repeat;
+	u8 exp;
+	s32 slow_freq;
+} brcm_pfn_param_t;
+
+typedef struct wsec_pmk {
+	u16  key_len;
+	u16  flags;
+	u8   key[WSEC_MAX_PSK_LEN];
+} wsec_pmk_t;
+
+typedef struct brcm_ssid {
+	u32          SSID_len;
+	u8           SSID[DOT11_MAX_SSID_LEN];
+} brcm_ssid_t;
+
+struct brcm_pfn {
+	brcm_ssid_t              ssid;                   /**< ssid name and its length */
+	s32                   flags;                  /**< bit2: hidden */
+	s32                   infra;                  /**< BSS Vs IBSS */
+	s32                   auth;                   /**< Open Vs Closed */
+	s32                   wpa_auth;               /**< WPA type */
+	s32                   wsec;                   /**< wsec value */
+	wsec_pmk_t              psk;                    /**< Password */
+};
+
+struct pfn_conn_info {
+	u8 SSID_len;
+	u8 SSID[32];
+	u8 BSSID[ETH_ALEN];
+	s16 RSSI;
+	s8 phy_noise;
+	u16 channel;
+	s16 SNR;
+	u8 proto;
+	int key_mgmt;
+};
+
+enum wpas_mode {
+	WPAS_MODE_INFRA = 0,
+	WPAS_MODE_IBSS = 1,
+	WPAS_MODE_AP = 2,
+	WPAS_MODE_P2P_GO = 3,
+	WPAS_MODE_P2P_GROUP_FORMATION = 4,
+	WPAS_MODE_MESH = 5,
+};
+
 /* forward declaration */
 struct brcmf_pno_info;
 
@@ -70,3 +179,9 @@ u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
 			     struct brcmf_pno_net_info_le *netinfo);
 
 #endif /* _BRCMF_PNO_H */
+
+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.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
index 03085634e..65adad8bd 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
@@ -357,6 +357,20 @@ const struct wiphy_vendor_command brcmf_vendor_cmds[] = {
 			VENDOR_CMD_RAW_DATA,
 			ifx_cfg80211_vndr_cmds_str)
 	},
+	{
+		IFX_SUBCMD(PFN_CONFIG,
+				(WIPHY_VENDOR_CMD_NEED_WDEV |
+				 WIPHY_VENDOR_CMD_NEED_NETDEV),
+				VENDOR_CMD_RAW_DATA,
+				ifx_cfg80211_vndr_cmds_config_pfn)
+	},
+	{
+		IFX_SUBCMD(PFN_STATUS,
+				(WIPHY_VENDOR_CMD_NEED_WDEV |
+				 WIPHY_VENDOR_CMD_NEED_NETDEV),
+				VENDOR_CMD_RAW_DATA,
+				ifx_cfg80211_vndr_cmds_get_pfn_status)
+	},
 };
 
 const struct nl80211_vendor_cmd_info brcmf_vendor_events[] = {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
index c8bffb02e..fabb48658 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
@@ -40,6 +40,7 @@
 #include "vendor_ifx.h"
 #include "xtlv.h"
 #include "twt.h"
+#include "pno.h"
 #include "bus.h"
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -1032,3 +1033,96 @@ int ifx_cfg80211_vndr_cmds_str(struct wiphy *wiphy, struct wireless_dev *wdev,
 
 	return ret;
 }
+
+int ifx_cfg80211_vndr_cmds_config_pfn(struct wiphy *wiphy,
+		struct wireless_dev *wdev,
+		const void *data, int len)
+{
+	int buflen;
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+
+	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);
+
+	if (!cfg->pfn_data.count)
+		return 0;
+
+	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);
+	pfn_send_network_blob_fw(wiphy, wdev);
+	brcmf_dbg(TRACE, "Exit\n");
+	return 0;
+}
+
+int ifx_cfg80211_vndr_cmds_get_pfn_status(struct wiphy *wiphy,
+					struct wireless_dev *wdev,
+					const void *data, int len)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	u8 *buf = NULL;
+	struct brcmf_bss_info_le *bi = NULL;
+	int err = 0, i = 0;
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_if *ifp;
+	struct network_blob *curr_network = NULL, *network_blob_data = NULL;
+	struct brcmu_chan ch;
+	struct pfn_conn_info curr_bssid;
+
+	brcmf_dbg(TRACE, "Enter\n");
+	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+	ifp = vif->ifp;
+	if (cfg->pfn_enable != 1)
+		return 0;
+	buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+	if (!buf) {
+		err = -ENOMEM;
+		return 0;
+	}
+
+	*(u32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
+	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
+					buf, WL_BSS_INFO_MAX);
+	if (err) {
+		brcmf_err("pfn_status buf error:%d\n", err);
+		return 0;
+	}
+	bi = (struct brcmf_bss_info_le *)(buf + 4);
+	memset(&curr_bssid, '\0', sizeof(struct pfn_conn_info));
+
+	if (bi->SSID_len > 0) {
+		memcpy(curr_bssid.SSID, bi->SSID, bi->SSID_len);
+		memcpy(curr_bssid.BSSID, bi->BSSID, ETH_ALEN);
+		curr_bssid.SSID_len = bi->SSID_len;
+		curr_bssid.RSSI = bi->RSSI;
+		curr_bssid.phy_noise = bi->phy_noise;
+		ch.chspec = le16_to_cpu(bi->chanspec);
+		cfg->d11inf.decchspec(&ch);
+		curr_bssid.channel = ch.control_ch_num;
+		curr_bssid.SNR = bi->SNR;
+
+		network_blob_data = cfg->pfn_data.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_network = network_blob_data;
+				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)
+		ifx_cfg80211_vndr_send_cmd_reply(wiphy, (void *)&curr_bssid,
+						sizeof(struct pfn_conn_info));
+	kfree(buf);
+	brcmf_dbg(TRACE, "Exit\n");
+	return 0;
+}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h
index 6e2218a3c..37cdf0dbf 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h
@@ -796,6 +796,8 @@ int ifx_vndr_cmdstr_tko(struct wiphy *wiphy, struct wireless_dev *wdev,
 			long *cmd_val);
 int ifx_cfg80211_vndr_cmds_str(struct wiphy *wiphy, struct wireless_dev *wdev,
 			       const void *data, int len);
-
+int ifx_cfg80211_vndr_cmds_config_pfn(struct wiphy *wiphy,
+				struct wireless_dev *wdev, const void  *data, int len);
+int ifx_cfg80211_vndr_cmds_get_pfn_status(struct wiphy *wiphy,
+					struct wireless_dev *wdev, const void  *data, int len);
 #endif /* IFX_VENDOR_H */
-
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
index 1023a1176..f6b019556 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
@@ -260,4 +260,7 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
 #define HT_CAP_RX_STBC_NO		0x0
 #define HT_CAP_RX_STBC_ONE_STREAM	0x1
 
+#define WPA_PROTO_WPA BIT(0)
+#define WPA_PROTO_RSN BIT(1)
+
 #endif				/* _BRCMU_WIFI_H_ */
-- 
2.39.5 (Apple Git-154)

