From d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 11 Dec 2023 02:45:28 +0000
Subject: [PATCH] add boot partition  size

---
 kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c | 2835 +++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 1,584 insertions(+), 1,251 deletions(-)

diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c
index 418a01f..e01c7ff 100644
--- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c
+++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c
@@ -1,16 +1,17 @@
-/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Broadcom Dongle Host Driver (DHD)
  * Prefered Network Offload and Wi-Fi Location Service(WLS) code.
  *
- * Copyright (C) 1999-2019, Broadcom Corporation
- * 
+ * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation
+ *
+ * Copyright (C) 1999-2017, Broadcom Corporation
+ *
  *      Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
  * under the terms of the GNU General Public License version 2 (the "GPL"),
  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  * following added to such license:
- * 
+ *
  *      As a special exception, the copyright holders of this software give you
  * permission to link this software with independent modules, and to copy and
  * distribute the resulting executable under terms of your choice, provided that
@@ -18,7 +19,7 @@
  * the license of that module.  An independent module is a module which is not
  * derived from this software.  The special exception does not apply to any
  * modifications of the software.
- * 
+ *
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
@@ -26,12 +27,12 @@
  *
  * <<Broadcom-WL-IPTag/Open:>>
  *
- * $Id: dhd_pno.c 423669 2013-09-18 13:01:55Z yangj$
+ * $Id: dhd_pno.c 812762 2019-04-02 09:36:26Z $
  */
 
 #if defined(GSCAN_SUPPORT) && !defined(PNO_SUPPORT)
 #error "GSCAN needs PNO to be enabled!"
-#endif
+#endif // endif
 
 #ifdef PNO_SUPPORT
 #include <typedefs.h>
@@ -41,21 +42,27 @@
 #include <bcmutils.h>
 
 #include <bcmendian.h>
+#ifdef OEM_ANDROID
 #include <linuxver.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/sort.h>
+#endif // endif
 #include <dngl_stats.h>
 #include <wlioctl.h>
 
-#include <proto/bcmevent.h>
+#include <bcmevent.h>
 #include <dhd.h>
+#include <dhd_linux.h>
 #include <dhd_pno.h>
 #include <dhd_dbg.h>
 #ifdef GSCAN_SUPPORT
 #include <linux/gcd.h>
 #endif /* GSCAN_SUPPORT */
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif /* WL_CFG80211 */
 
 #ifdef __BIG_ENDIAN
 #include <bcmendian.h>
@@ -74,20 +81,21 @@
 #define dtohchanspec(i) (i)
 #endif /* IL_BIGENDINA */
 
-#define NULL_CHECK(p, s, err)  \
-			do { \
-				if (!(p)) { \
-					printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \
-					err = BCME_ERROR; \
-					return err; \
-				} \
-			} while (0)
+#ifdef OEM_ANDROID
 #define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state)
-#define PNO_BESTNET_LEN 2048
+
+#define PNO_BESTNET_LEN		WLC_IOCTL_MEDLEN
+
 #define PNO_ON 1
 #define PNO_OFF 0
+#define CHANNEL_2G_MIN 1
 #define CHANNEL_2G_MAX 14
+#define CHANNEL_5G_MIN 34
 #define CHANNEL_5G_MAX 165
+#define IS_2G_CHANNEL(ch) ((ch >= CHANNEL_2G_MIN) && \
+	(ch <= CHANNEL_2G_MAX))
+#define IS_5G_CHANNEL(ch) ((ch >= CHANNEL_5G_MIN) && \
+	(ch <= CHANNEL_5G_MAX))
 #define MAX_NODE_CNT 5
 #define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE)
 #define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000)  \
@@ -99,30 +107,46 @@
 
 #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====")
 #define TIME_MIN_DIFF 5
-#define EVENT_DATABUF_MAXLEN   (512 - sizeof(bcm_event_t))
-#define EVENT_MAX_NETCNT \
-   ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_t)) \
-   / sizeof(wl_pfn_net_info_t) + 1)
-#define WL_SCAN_IE_LEN_MAX      2048
 
-static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd,
-        dhd_pno_status_info_t *pno_state);
+#define EVENT_DATABUF_MAXLEN	(512 - sizeof(bcm_event_t))
+#define EVENT_MAX_NETCNT_V1 \
+	((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_v1_t)) \
+	/ sizeof(wl_pfn_net_info_v1_t) + 1)
+#define EVENT_MAX_NETCNT_V2 \
+	((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_v2_t)) \
+	/ sizeof(wl_pfn_net_info_v2_t) + 1)
+
 #ifdef GSCAN_SUPPORT
+static int _dhd_pno_flush_ssid(dhd_pub_t *dhd);
 static wl_pfn_gscan_ch_bucket_cfg_t *
 dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state,
-      uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw);
+	uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw);
 #endif /* GSCAN_SUPPORT */
 
+static int dhd_pno_set_legacy_pno(dhd_pub_t *dhd, uint16  scan_fr, int pno_repeat,
+	int pno_freq_expo_max, uint16 *channel_list, int nchan);
+
 static inline bool
-is_dfs(uint16 channel)
+is_dfs(dhd_pub_t *dhd, uint16 channel)
 {
-	if (channel >= 52 && channel <= 64)			/* class 2 */
-		return TRUE;
-	else if (channel >= 100 && channel <= 140)	/* class 4 */
-		return TRUE;
-	else
+	u32 ch;
+	s32 err;
+	u8 buf[32];
+
+	ch = wl_ch_host_to_driver(channel);
+	err = dhd_iovar(dhd, 0, "per_chan_info", (char *)&ch,
+		sizeof(u32), buf, sizeof(buf), FALSE);
+	if (unlikely(err)) {
+		DHD_ERROR(("get per chan info failed:%d\n", err));
 		return FALSE;
+	}
+	/* Check the channel flags returned by fw */
+	if (*((u32 *)buf) & WL_CHAN_PASSIVE) {
+		return TRUE;
+	}
+	return FALSE;
 }
+
 int
 dhd_pno_clean(dhd_pub_t *dhd)
 {
@@ -180,33 +204,100 @@
 
 #ifdef GSCAN_SUPPORT
 static uint64
-convert_fw_rel_time_to_systime(uint32 fw_ts_ms)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
+convert_fw_rel_time_to_systime(struct timespec64 *ts, uint32 fw_ts_ms)
+#else
+convert_fw_rel_time_to_systime(struct timespec *ts, uint32 fw_ts_ms)
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */
 {
-	struct timespec ts;
-
-	get_monotonic_boottime(&ts);
-	return ((uint64)(TIMESPEC_TO_US(ts)) - (uint64)(fw_ts_ms * 1000));
+	return ((uint64)(TIMESPEC_TO_US(*ts)) - (uint64)(fw_ts_ms * 1000));
 }
 
 static void
 dhd_pno_idx_to_ssid(struct dhd_pno_gscan_params *gscan_params,
-            dhd_epno_results_t *res, uint32 idx)
+		dhd_epno_results_t *res, uint32 idx)
 {
-	dhd_epno_params_t *iter, *next;
+	dhd_pno_ssid_t *iter, *next;
+	int i;
 
-	if (gscan_params->num_epno_ssid > 0) {
+	/* If idx doesn't make sense */
+	if (idx >= gscan_params->epno_cfg.num_epno_ssid) {
+		DHD_ERROR(("No match, idx %d num_ssid %d\n", idx,
+			gscan_params->epno_cfg.num_epno_ssid));
+		goto exit;
+	}
+
+	if (gscan_params->epno_cfg.num_epno_ssid > 0) {
+		i = 0;
+
+		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 		list_for_each_entry_safe(iter, next,
-			&gscan_params->epno_ssid_list, list) {
-			if (iter->index == idx) {
-				memcpy(res->ssid, iter->ssid, iter->ssid_len);
-				res->ssid_len = iter->ssid_len;
+			&gscan_params->epno_cfg.epno_ssid_list, list) {
+			GCC_DIAGNOSTIC_POP();
+			if (i++ == idx) {
+				memcpy(res->ssid, iter->SSID, iter->SSID_len);
+				res->ssid_len = iter->SSID_len;
 				return;
 			}
 		}
 	}
+exit:
 	/* If we are here then there was no match */
 	res->ssid[0] = '\0';
 	res->ssid_len = 0;
+	return;
+}
+
+/* Translate HAL flag bitmask to BRCM FW flag bitmask */
+void
+dhd_pno_translate_epno_fw_flags(uint32 *flags)
+{
+	uint32 in_flags, fw_flags = 0;
+	in_flags = *flags;
+
+	if (in_flags & DHD_EPNO_A_BAND_TRIG) {
+		fw_flags |= WL_PFN_SSID_A_BAND_TRIG;
+	}
+
+	if (in_flags & DHD_EPNO_BG_BAND_TRIG) {
+		fw_flags |= WL_PFN_SSID_BG_BAND_TRIG;
+	}
+
+	if (!(in_flags & DHD_EPNO_STRICT_MATCH) &&
+			!(in_flags & DHD_EPNO_HIDDEN_SSID)) {
+		fw_flags |= WL_PFN_SSID_IMPRECISE_MATCH;
+	}
+
+	if (in_flags & DHD_EPNO_SAME_NETWORK) {
+		fw_flags |= WL_PFN_SSID_SAME_NETWORK;
+	}
+
+	/* Add any hard coded flags needed */
+	fw_flags |= WL_PFN_SUPPRESS_AGING_MASK;
+	*flags = fw_flags;
+
+	return;
+}
+
+/* Translate HAL auth bitmask to BRCM FW bitmask */
+void
+dhd_pno_set_epno_auth_flag(uint32 *wpa_auth)
+{
+	switch (*wpa_auth) {
+		case DHD_PNO_AUTH_CODE_OPEN:
+			*wpa_auth = WPA_AUTH_DISABLED;
+			break;
+		case DHD_PNO_AUTH_CODE_PSK:
+			*wpa_auth = (WPA_AUTH_PSK | WPA2_AUTH_PSK);
+			break;
+		case DHD_PNO_AUTH_CODE_EAPOL:
+			*wpa_auth = ~WPA_AUTH_NONE;
+			break;
+		default:
+			DHD_ERROR(("%s: Unknown auth %d", __FUNCTION__, *wpa_auth));
+			*wpa_auth = WPA_AUTH_PFN_ANY;
+			break;
+	}
 	return;
 }
 
@@ -244,6 +335,21 @@
 		goto exit;
 	}
 exit:
+	return err;
+}
+
+static int
+_dhd_pno_flush_ssid(dhd_pub_t *dhd)
+{
+	int err;
+	wl_pfn_t pfn_elem;
+	memset(&pfn_elem, 0, sizeof(wl_pfn_t));
+	pfn_elem.flags = htod32(WL_PFN_FLUSH_ALL_SSIDS);
+
+	err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_elem, sizeof(wl_pfn_t), NULL, 0, TRUE);
+	if (err < 0) {
+		DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__));
+	}
 	return err;
 }
 
@@ -298,7 +404,7 @@
 	}
 	if (enable) {
 		if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) &&
-			dhd_is_associated(dhd, NULL, NULL)) {
+			dhd_is_associated(dhd, 0, NULL)) {
 			DHD_ERROR(("%s Legacy PNO mode cannot be enabled "
 				"in assoc mode , ignore it\n", __FUNCTION__));
 			err = BCME_BADOPTION;
@@ -450,18 +556,17 @@
 		pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
 
 		if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
-			dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
-			dhd_pno_params_t *_params;
+			dhd_pno_params_t *params;
 
-			_params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
+			params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
 
-			pfn_param.scan_freq = htod32(gcd(pno_params->params_gscan.scan_fr,
-			                 _params->params_legacy.scan_fr));
+			pfn_param.scan_freq = gcd(pno_params->params_gscan.scan_fr,
+			                 params->params_legacy.scan_fr);
 
-			if ((_params->params_legacy.pno_repeat != 0) ||
-				(_params->params_legacy.pno_freq_expo_max != 0)) {
-				pfn_param.repeat = (uchar) (_params->params_legacy.pno_repeat);
-				pfn_param.exp = (uchar) (_params->params_legacy.pno_freq_expo_max);
+			if ((params->params_legacy.pno_repeat != 0) ||
+				(params->params_legacy.pno_freq_expo_max != 0)) {
+				pfn_param.repeat = (uchar) (params->params_legacy.pno_repeat);
+				pfn_param.exp = (uchar) (params->params_legacy.pno_freq_expo_max);
 			}
 		}
 
@@ -494,12 +599,11 @@
 	}
 
 #ifdef GSCAN_SUPPORT
-			if (mode == DHD_PNO_BATCH_MODE ||
-				((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) {
+	if (mode == DHD_PNO_BATCH_MODE ||
+	((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) {
 #else
-			if (mode == DHD_PNO_BATCH_MODE) {
+	if (mode == DHD_PNO_BATCH_MODE) {
 #endif /* GSCAN_SUPPORT */
-
 		int _tmp = pfn_param.bestn;
 		/* set bestn to calculate the max mscan which firmware supports */
 		err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), NULL, 0, TRUE);
@@ -528,69 +632,64 @@
 	return err;
 }
 static int
-_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssids_list, int nssid)
+_dhd_pno_add_ssid(dhd_pub_t *dhd, struct list_head* ssid_list, int nssid)
 {
 	int err = BCME_OK;
-	int i = 0;
-	wl_pfn_t pfn_element;
+	int i = 0, mem_needed;
+	wl_pfn_t *pfn_elem_buf;
+	struct dhd_pno_ssid *iter, *next;
+
 	NULL_CHECK(dhd, "dhd is NULL", err);
-	if (nssid) {
-		NULL_CHECK(ssids_list, "ssid list is NULL", err);
+	if (!nssid) {
+		NULL_CHECK(ssid_list, "ssid list is NULL", err);
+		return BCME_ERROR;
 	}
-	memset(&pfn_element, 0, sizeof(pfn_element));
-	{
-		int j;
-		for (j = 0; j < nssid; j++) {
-			DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n",
-				ssids_list[j].SSID, ssids_list[j].SSID_len, ssids_list[j].hidden,
-				ssids_list[j].flags, ssids_list[i].rssi_thresh));
-		}
+	mem_needed = (sizeof(wl_pfn_t) * nssid);
+	pfn_elem_buf = (wl_pfn_t *) MALLOCZ(dhd->osh, mem_needed);
+	if (!pfn_elem_buf) {
+		DHD_ERROR(("%s: Can't malloc %d bytes!\n", __FUNCTION__, mem_needed));
+		return BCME_NOMEM;
 	}
-	/* Check for broadcast ssid */
-	for (i = 0; i < nssid; i++) {
-		if (!ssids_list[i].SSID_len) {
-			DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", i));
-			err = BCME_ERROR;
-			goto exit;
-		}
-	}
-	/* set all pfn ssid */
-	for (i = 0; i < nssid; i++) {
-		pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE);
-		pfn_element.auth = (DOT11_OPEN_SYSTEM);
-		pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
-		pfn_element.wsec = htod32(0);
-		pfn_element.infra = htod32(1);
-		if (ssids_list[i].hidden) {
-			pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT);
-		} else {
-			pfn_element.flags = 0;
-		}
-		pfn_element.flags |= htod32(ssids_list[i].flags);
+
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+	list_for_each_entry_safe(iter, next, ssid_list, list) {
+		GCC_DIAGNOSTIC_POP();
+		pfn_elem_buf[i].infra = htod32(1);
+		pfn_elem_buf[i].auth = htod32(DOT11_OPEN_SYSTEM);
+		pfn_elem_buf[i].wpa_auth = htod32(iter->wpa_auth);
+		pfn_elem_buf[i].flags = htod32(iter->flags);
+		if (iter->hidden)
+			pfn_elem_buf[i].flags |= htod32(ENABLE << WL_PFN_HIDDEN_BIT);
 		/* If a single RSSI threshold is defined, use that */
 #ifdef PNO_MIN_RSSI_TRIGGER
-		pfn_element.flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT);
+		pfn_elem_buf[i].flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT);
 #else
-		pfn_element.flags |= ((ssids_list[i].rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT);
+		pfn_elem_buf[i].flags |= ((iter->rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT);
 #endif /* PNO_MIN_RSSI_TRIGGER */
-		memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID,
-			ssids_list[i].SSID_len);
-		pfn_element.ssid.SSID_len = ssids_list[i].SSID_len;
-		err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, sizeof(pfn_element),
-				NULL, 0, TRUE);
-		if (err < 0) {
-			DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__));
-			goto exit;
+		memcpy((char *)pfn_elem_buf[i].ssid.SSID, iter->SSID,
+			iter->SSID_len);
+		pfn_elem_buf[i].ssid.SSID_len = iter->SSID_len;
+		DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n",
+			iter->SSID, iter->SSID_len, iter->hidden,
+			iter->flags, iter->rssi_thresh));
+		if (++i >= nssid) {
+			/* shouldn't happen */
+			break;
 		}
 	}
-exit:
+
+	err = dhd_iovar(dhd, 0, "pfn_add", (char *)pfn_elem_buf, mem_needed, NULL, 0, TRUE);
+	if (err < 0) {
+		DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__));
+	}
+	MFREE(dhd->osh, pfn_elem_buf, mem_needed);
 	return err;
 }
 /* qsort compare function */
 static int
 _dhd_pno_cmpfunc(const void *a, const void *b)
 {
-	return (*(uint16*)a - *(uint16*)b);
+	return (*(const uint16*)a - *(const uint16*)b);
 }
 static int
 _dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan,
@@ -639,40 +738,43 @@
 	if (*nchan) {
 		NULL_CHECK(d_chan_list, "d_chan_list is NULL", err);
 	}
+	memset(&chan_buf, 0, sizeof(chan_buf));
 	list = (wl_uint32_list_t *) (void *)chan_buf;
 	list->count = htod32(WL_NUMCHANNELS);
 	err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0);
 	if (err < 0) {
 		DHD_ERROR(("failed to get channel list (err: %d)\n", err));
-		goto exit;
+		return err;
 	}
 	for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) {
-		if (band == WLC_BAND_2G) {
-			if (dtoh32(list->element[i]) > CHANNEL_2G_MAX)
+		if (IS_2G_CHANNEL(dtoh32(list->element[i]))) {
+			if (!(band & WLC_BAND_2G)) {
+				/* Skip, if not 2g */
 				continue;
-		} else if (band == WLC_BAND_5G) {
-			if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX)
+			}
+			/* fall through to include the channel */
+		} else if (IS_5G_CHANNEL(dtoh32(list->element[i]))) {
+			bool dfs_channel = is_dfs(dhd, dtoh32(list->element[i]));
+			if ((skip_dfs && dfs_channel) ||
+				(!(band & WLC_BAND_5G) && !dfs_channel)) {
+				/* Skip the channel if:
+				* the DFS bit is NOT set & the channel is a dfs channel
+				* the band 5G is not set & the channel is a non DFS 5G channel
+				*/
 				continue;
-			if (skip_dfs && is_dfs(dtoh32(list->element[i])))
-				continue;
-
-		} else if (band == WLC_BAND_AUTO) {
-			if (skip_dfs || !is_dfs(dtoh32(list->element[i])))
-				continue;
-
-		} else { /* All channels */
-			if (skip_dfs && is_dfs(dtoh32(list->element[i])))
-				continue;
-		}
-		if (dtoh32(list->element[i]) <= CHANNEL_5G_MAX) {
-			d_chan_list[j++] = (uint16) dtoh32(list->element[i]);
+			}
+			/* fall through to include the channel */
 		} else {
-			err = BCME_BADCHAN;
-			goto exit;
+			/* Not in range. Bad channel */
+			DHD_ERROR(("Not in range. bad channel\n"));
+			*nchan = 0;
+			return BCME_BADCHAN;
 		}
+
+		/* Include the channel */
+		d_chan_list[j++] = (uint16) dtoh32(list->element[i]);
 	}
 	*nchan = j;
-exit:
 	return err;
 }
 static int
@@ -689,7 +791,7 @@
 #ifdef PNO_DEBUG
 	char *_base_bp;
 	char msg[150];
-#endif
+#endif // endif
 	dhd_pno_bestnet_entry_t *iter, *next;
 	dhd_pno_scan_results_t *siter, *snext;
 	dhd_pno_best_header_t *phead, *pprev;
@@ -701,15 +803,17 @@
 	DHD_PNO(("%s enter \n", __FUNCTION__));
 	/* # of scans */
 	if (!params_batch->get_batch.batch_started) {
-		bp += nreadsize = sprintf(bp, "scancount=%d\n",
+		bp += nreadsize = snprintf(bp, nleftsize, "scancount=%d\n",
 			params_batch->get_batch.expired_tot_scan_cnt);
 		nleftsize -= nreadsize;
 		params_batch->get_batch.batch_started = TRUE;
 	}
 	DHD_PNO(("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt));
 	/* preestimate scan count until which scan result this report is going to end */
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 	list_for_each_entry_safe(siter, snext,
 		&params_batch->get_batch.expired_scan_results_list, list) {
+		GCC_DIAGNOSTIC_POP();
 		phead = siter->bestnetheader;
 		while (phead != NULL) {
 			/* if left_size is less than bestheader total size , stop this */
@@ -722,54 +826,57 @@
 			DHD_PNO(("\n<loop : %d, apcount %d>\n", cnt - 1, phead->tot_cnt));
 			/* attribute of the scan */
 			if (phead->reason & PNO_STATUS_ABORT_MASK) {
-				bp += nreadsize = sprintf(bp, "trunc\n");
+				bp += nreadsize = snprintf(bp, nleftsize, "trunc\n");
 				nleftsize -= nreadsize;
 			}
+			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 			list_for_each_entry_safe(iter, next,
 				&phead->entry_list, list) {
+				GCC_DIAGNOSTIC_POP();
 				t_delta = jiffies_to_msecs(jiffies - iter->recorded_time);
 #ifdef PNO_DEBUG
 				_base_bp = bp;
 				memset(msg, 0, sizeof(msg));
-#endif
+#endif // endif
 				/* BSSID info */
-				bp += nreadsize = sprintf(bp, "bssid=%s\n",
+				bp += nreadsize = snprintf(bp, nleftsize, "bssid=%s\n",
 				bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf));
 				nleftsize -= nreadsize;
 				/* SSID */
-				bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID);
+				bp += nreadsize = snprintf(bp, nleftsize, "ssid=%s\n", iter->SSID);
 				nleftsize -= nreadsize;
 				/* channel */
-				bp += nreadsize = sprintf(bp, "freq=%d\n",
+				bp += nreadsize = snprintf(bp, nleftsize, "freq=%d\n",
 				wf_channel2mhz(iter->channel,
 				iter->channel <= CH_MAX_2G_CHANNEL?
 				WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
 				nleftsize -= nreadsize;
 				/* RSSI */
-				bp += nreadsize = sprintf(bp, "level=%d\n", iter->RSSI);
+				bp += nreadsize = snprintf(bp, nleftsize, "level=%d\n", iter->RSSI);
 				nleftsize -= nreadsize;
 				/* add the time consumed in Driver to the timestamp of firmware */
 				iter->timestamp += t_delta;
-				bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp);
+				bp += nreadsize = snprintf(bp, nleftsize,
+					"age=%d\n", iter->timestamp);
 				nleftsize -= nreadsize;
 				/* RTT0 */
-				bp += nreadsize = sprintf(bp, "dist=%d\n",
+				bp += nreadsize = snprintf(bp, nleftsize, "dist=%d\n",
 				(iter->rtt0 == 0)? -1 : iter->rtt0);
 				nleftsize -= nreadsize;
 				/* RTT1 */
-				bp += nreadsize = sprintf(bp, "distSd=%d\n",
+				bp += nreadsize = snprintf(bp, nleftsize, "distSd=%d\n",
 				(iter->rtt0 == 0)? -1 : iter->rtt1);
 				nleftsize -= nreadsize;
-				bp += nreadsize = sprintf(bp, "%s", AP_END_MARKER);
+				bp += nreadsize = snprintf(bp, nleftsize, "%s", AP_END_MARKER);
 				nleftsize -= nreadsize;
 				list_del(&iter->list);
 				MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE);
 #ifdef PNO_DEBUG
 				memcpy(msg, _base_bp, bp - _base_bp);
 				DHD_PNO(("Entry : \n%s", msg));
-#endif
+#endif // endif
 			}
-			bp += nreadsize = sprintf(bp, "%s", SCAN_END_MARKER);
+			bp += nreadsize = snprintf(bp, nleftsize, "%s", SCAN_END_MARKER);
 			DHD_PNO(("%s", SCAN_END_MARKER));
 			nleftsize -= nreadsize;
 			pprev = phead;
@@ -793,9 +900,11 @@
 	}
 	params_batch->get_batch.expired_tot_scan_cnt -= cnt;
 	/* set FALSE only if the link list  is empty after returning the data */
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 	if (list_empty(&params_batch->get_batch.expired_scan_results_list)) {
+		GCC_DIAGNOSTIC_POP();
 		params_batch->get_batch.batch_started = FALSE;
-		bp += sprintf(bp, "%s", RESULTS_END_MARKER);
+		bp += snprintf(bp, nleftsize, "%s", RESULTS_END_MARKER);
 		DHD_PNO(("%s", RESULTS_END_MARKER));
 		DHD_PNO(("%s : Getting the batching data is complete\n", __FUNCTION__));
 	}
@@ -815,6 +924,8 @@
 	NULL_CHECK(head, "head is NULL", err);
 	NULL_CHECK(head->next, "head->next is NULL", err);
 	DHD_PNO(("%s enter\n", __FUNCTION__));
+
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 	list_for_each_entry_safe(siter, snext,
 		head, list) {
 		if (only_last) {
@@ -843,6 +954,7 @@
 			MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE);
 		}
 	}
+	GCC_DIAGNOSTIC_POP();
 	return removed_scan_cnt;
 }
 
@@ -892,12 +1004,15 @@
 	case DHD_PNO_LEGACY_MODE: {
 		struct dhd_pno_ssid *iter, *next;
 		if (params->params_legacy.nssid > 0) {
+			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 			list_for_each_entry_safe(iter, next,
 				&params->params_legacy.ssid_list, list) {
+				GCC_DIAGNOSTIC_POP();
 				list_del(&iter->list);
-				kfree(iter);
+				MFREE(dhd->osh, iter, sizeof(struct dhd_pno_ssid));
 			}
 		}
+
 		params->params_legacy.nssid = 0;
 		params->params_legacy.scan_fr = 0;
 		params->params_legacy.pno_freq_expo_max = 0;
@@ -935,10 +1050,12 @@
 	case DHD_PNO_HOTLIST_MODE: {
 		struct dhd_pno_bssid *iter, *next;
 		if (params->params_hotlist.nbssid > 0) {
+			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 			list_for_each_entry_safe(iter, next,
 				&params->params_hotlist.bssid_list, list) {
+				GCC_DIAGNOSTIC_POP();
 				list_del(&iter->list);
-				kfree(iter);
+				MFREE(dhd->osh, iter, sizeof(struct dhd_pno_ssid));
 			}
 		}
 		params->params_hotlist.scan_fr = 0;
@@ -974,40 +1091,15 @@
 	return err;
 }
 
-#ifdef GSCAN_SUPPORT
-static int
-_dhd_pno_add_significant_bssid(dhd_pub_t *dhd,
-   wl_pfn_significant_bssid_t *p_pfn_significant_bssid, int nbssid)
-{
-	int err = BCME_OK;
-	NULL_CHECK(dhd, "dhd is NULL", err);
-
-	if (!nbssid) {
-		err = BCME_ERROR;
-		goto exit;
-	}
-
-	NULL_CHECK(p_pfn_significant_bssid, "bssid list is NULL", err);
-
-	err = dhd_iovar(dhd, 0, "pfn_add_swc_bssid", (char *)p_pfn_significant_bssid,
-			sizeof(wl_pfn_significant_bssid_t) * nbssid, NULL, 0, TRUE);
-	if (err < 0) {
-		DHD_ERROR(("%s : failed to execute pfn_significant_bssid %d\n", __FUNCTION__, err));
-		goto exit;
-	}
-exit:
-	return err;
-}
-#endif /* GSCAN_SUPPORT */
-
 int
 dhd_pno_stop_for_ssid(dhd_pub_t *dhd)
 {
 	int err = BCME_OK;
-	uint32 mode = 0;
+	uint32 mode = 0, cnt = 0;
 	dhd_pno_status_info_t *_pno_state;
-	dhd_pno_params_t *_params;
-	wl_pfn_bssid_t *p_pfn_bssid = NULL;
+	dhd_pno_params_t *_params = NULL;
+	wl_pfn_bssid_t *p_pfn_bssid = NULL, *tmp_bssid;
+
 	NULL_CHECK(dhd, "dev is NULL", err);
 	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
 	_pno_state = PNO_GET_PNOSTATE(dhd);
@@ -1016,7 +1108,11 @@
 		goto exit;
 	}
 	DHD_PNO(("%s enter\n", __FUNCTION__));
+	/* If pno mode is PNO_LEGACY_MODE clear the pno values and unset the DHD_PNO_LEGACY_MODE */
+	_params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS];
+	_dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
 	_pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+
 #ifdef GSCAN_SUPPORT
 	if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
 		struct dhd_pno_gscan_params *gscan_params;
@@ -1053,7 +1149,14 @@
 		dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE);
 		/* save current pno_mode before calling dhd_pno_clean */
 		mode = _pno_state->pno_mode;
-		dhd_pno_clean(dhd);
+		err = dhd_pno_clean(dhd);
+		if (err < 0) {
+			err = BCME_ERROR;
+			DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
+				__FUNCTION__, err));
+			goto exit;
+		}
+
 		/* restore previous pno_mode */
 		_pno_state->pno_mode = mode;
 		if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) {
@@ -1070,8 +1173,8 @@
 			/* restart HOTLIST SCAN */
 			struct dhd_pno_bssid *iter, *next;
 			_params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]);
-			p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) *
-			_params->params_hotlist.nbssid, GFP_KERNEL);
+			p_pfn_bssid = MALLOCZ(dhd->osh, sizeof(wl_pfn_bssid_t) *
+			_params->params_hotlist.nbssid);
 			if (p_pfn_bssid == NULL) {
 				DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array"
 				" (count: %d)",
@@ -1081,12 +1184,23 @@
 				goto exit;
 			}
 			/* convert dhd_pno_bssid to wl_pfn_bssid */
+			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+			cnt = 0;
+			tmp_bssid = p_pfn_bssid;
 			list_for_each_entry_safe(iter, next,
 			&_params->params_hotlist.bssid_list, list) {
-				memcpy(&p_pfn_bssid->macaddr,
+				GCC_DIAGNOSTIC_POP();
+				memcpy(&tmp_bssid->macaddr,
 				&iter->macaddr, ETHER_ADDR_LEN);
-				p_pfn_bssid->flags = iter->flags;
-				p_pfn_bssid++;
+				tmp_bssid->flags = iter->flags;
+				if (cnt < _params->params_hotlist.nbssid) {
+					tmp_bssid++;
+					cnt++;
+				} else {
+					DHD_ERROR(("%s: Allocated insufficient memory\n",
+						__FUNCTION__));
+					break;
+				}
 			}
 			err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist);
 			if (err < 0) {
@@ -1105,7 +1219,10 @@
 		}
 	}
 exit:
-	kfree(p_pfn_bssid);
+	if (p_pfn_bssid) {
+		MFREE(dhd->osh, p_pfn_bssid, sizeof(wl_pfn_bssid_t) *
+			_params->params_hotlist.nbssid);
+	}
 	return err;
 }
 
@@ -1118,140 +1235,11 @@
 	return (_dhd_pno_enable(dhd, enable));
 }
 
-static wlc_ssid_ext_t *
-dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state)
-{
-	int err = BCME_OK;
-	int i;
-	struct dhd_pno_ssid *iter, *next;
-	dhd_pno_params_t	*_params1 = &pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS];
-	wlc_ssid_ext_t *p_ssid_list;
-
-	p_ssid_list = kzalloc(sizeof(wlc_ssid_ext_t) *
-	                   _params1->params_legacy.nssid, GFP_KERNEL);
-	if (p_ssid_list == NULL) {
-		DHD_ERROR(("%s : failed to allocate wlc_ssid_ext_t array (count: %d)",
-			__FUNCTION__, _params1->params_legacy.nssid));
-		err = BCME_ERROR;
-		pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
-		goto exit;
-	}
-	i = 0;
-	/* convert dhd_pno_ssid to wlc_ssid_ext_t */
-	list_for_each_entry_safe(iter, next, &_params1->params_legacy.ssid_list, list) {
-		p_ssid_list[i].SSID_len = iter->SSID_len;
-		p_ssid_list[i].hidden = iter->hidden;
-		p_ssid_list[i].rssi_thresh = iter->rssi_thresh;
-		memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len);
-		i++;
-	}
-exit:
-	return p_ssid_list;
-}
-
-#ifdef GSCAN_SUPPORT
-static int dhd_epno_set_ssid(dhd_pub_t *dhd,
-            dhd_pno_status_info_t *pno_state)
-{
-	int err = BCME_OK;
-	dhd_epno_params_t *iter, *next;
-	dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
-	struct dhd_pno_gscan_params *gscan_params;
-	wlc_ssid_ext_t ssid_elem;
-	wl_pfn_ext_list_t *p_ssid_ext_elem = NULL;
-	uint32 mem_needed = 0, i = 0;
-	uint16 num_visible_epno_ssid;
-	uint8 flags;
-
-	gscan_params = &_params1->params_gscan;
-	num_visible_epno_ssid = gscan_params->num_visible_epno_ssid;
-
-	if (num_visible_epno_ssid) {
-		mem_needed =  sizeof(wl_pfn_ext_list_t) + (sizeof(wl_pfn_ext_t) *
-		                        (num_visible_epno_ssid - 1));
-		p_ssid_ext_elem = kzalloc(mem_needed, GFP_KERNEL);
-		if (p_ssid_ext_elem == NULL) {
-			DHD_ERROR(("%s : failed to allocate memory %u\n",
-				__FUNCTION__, mem_needed));
-			err = BCME_NOMEM;
-			goto exit;
-		}
-		p_ssid_ext_elem->version = PFN_SSID_EXT_VERSION;
-		p_ssid_ext_elem->count = num_visible_epno_ssid;
-	}
-
-	DHD_ERROR(("Total ssids %d, visible SSIDs %d\n", gscan_params->num_epno_ssid,
-	     num_visible_epno_ssid));
-
-	/* convert dhd_pno_ssid to wlc_ssid_ext_t */
-	list_for_each_entry_safe(iter, next, &gscan_params->epno_ssid_list, list) {
-		if (iter->flags & DHD_PNO_USE_SSID) {
-			memset(&ssid_elem, 0, sizeof(ssid_elem));
-			ssid_elem.SSID_len = iter->ssid_len;
-			ssid_elem.hidden = TRUE;
-			flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ?
-			       WL_PFN_SSID_A_BAND_TRIG: 0;
-			flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ?
-			       WL_PFN_SSID_BG_BAND_TRIG: 0;
-			ssid_elem.flags = flags;
-			ssid_elem.rssi_thresh = iter->rssi_thresh;
-			memcpy(ssid_elem.SSID, iter->ssid, iter->ssid_len);
-			if ((err = _dhd_pno_add_ssid(dhd, &ssid_elem, 1)) < 0) {
-				DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err));
-				goto exit;
-			}
-		} else if (i < num_visible_epno_ssid) {
-			p_ssid_ext_elem->pfn_ext[i].rssi_thresh = iter->rssi_thresh;
-			switch (iter->auth) {
-				case DHD_PNO_AUTH_CODE_OPEN:
-					p_ssid_ext_elem->pfn_ext[i].wpa_auth = WPA_AUTH_DISABLED;
-					break;
-				case DHD_PNO_AUTH_CODE_PSK:
-					p_ssid_ext_elem->pfn_ext[i].wpa_auth =
-					          (WPA2_AUTH_PSK | WPA_AUTH_PSK);
-					break;
-				case DHD_PNO_AUTH_CODE_EAPOL:
-					p_ssid_ext_elem->pfn_ext[i].wpa_auth =
-					           (uint16)WPA_AUTH_PFN_ANY;
-					break;
-				default:
-					p_ssid_ext_elem->pfn_ext[i].wpa_auth =
-					           (uint16)WPA_AUTH_PFN_ANY;
-					break;
-			}
-			memcpy(p_ssid_ext_elem->pfn_ext[i].ssid, iter->ssid, iter->ssid_len);
-			p_ssid_ext_elem->pfn_ext[i].ssid_len = iter->ssid_len;
-			iter->index = gscan_params->ssid_ext_last_used_index++;
-			flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ?
-			       WL_PFN_SSID_A_BAND_TRIG: 0;
-			flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ?
-			       WL_PFN_SSID_BG_BAND_TRIG: 0;
-			p_ssid_ext_elem->pfn_ext[i].flags = flags;
-			DHD_ERROR(("SSID %s idx %d rssi thresh %d flags %x\n", iter->ssid,
-			        iter->index, iter->rssi_thresh, flags));
-			i++;
-		}
-	}
-	if (num_visible_epno_ssid) {
-		err = dhd_iovar(dhd, 0, "pfn_add_ssid_ext", (char *)p_ssid_ext_elem,
-			mem_needed, NULL, 0, TRUE);
-
-		if (err < 0) {
-			DHD_ERROR(("%s : failed to execute pfn_add_pno_ext_ssid %d\n", __FUNCTION__,
-			     err));
-		}
-	}
-exit:
-	kfree(p_ssid_ext_elem);
-	return err;
-}
-#endif /* GSCAN_SUPPORT */
-
 static int
-dhd_pno_add_to_ssid_list(dhd_pno_params_t *params, wlc_ssid_ext_t *ssid_list,
-    int nssid)
+dhd_pno_add_to_ssid_list(dhd_pub_t *dhd, struct list_head *ptr, wlc_ssid_ext_t *ssid_list,
+    int nssid, int *num_ssid_added)
 {
-	int ret = 0;
+	int ret = BCME_OK;
 	int i;
 	struct dhd_pno_ssid *_pno_ssid;
 
@@ -1262,7 +1250,14 @@
 			ret = BCME_ERROR;
 			goto exit;
 		}
-		_pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL);
+		/* Check for broadcast ssid */
+		if (!ssid_list[i].SSID_len) {
+			DHD_ERROR(("%d: Broadcast SSID is illegal for PNO setting\n", i));
+			ret = BCME_ERROR;
+			goto exit;
+		}
+		_pno_ssid = (struct dhd_pno_ssid *)MALLOCZ(dhd->osh,
+			sizeof(struct dhd_pno_ssid));
 		if (_pno_ssid == NULL) {
 			DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n",
 				__FUNCTION__));
@@ -1272,12 +1267,15 @@
 		_pno_ssid->SSID_len = ssid_list[i].SSID_len;
 		_pno_ssid->hidden = ssid_list[i].hidden;
 		_pno_ssid->rssi_thresh = ssid_list[i].rssi_thresh;
+		_pno_ssid->flags = ssid_list[i].flags;
+		_pno_ssid->wpa_auth = WPA_AUTH_PFN_ANY;
+
 		memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len);
-		list_add_tail(&_pno_ssid->list, &params->params_legacy.ssid_list);
-		params->params_legacy.nssid++;
+		list_add_tail(&_pno_ssid->list, ptr);
 	}
 
 exit:
+	*num_ssid_added = i;
 	return ret;
 }
 
@@ -1285,25 +1283,63 @@
 dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid,
 	uint16  scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan)
 {
+	dhd_pno_status_info_t *_pno_state;
+	dhd_pno_params_t *_params;
+	struct dhd_pno_legacy_params *params_legacy;
+	int err = BCME_OK;
+
+	if (!dhd || !dhd->pno_state) {
+		DHD_ERROR(("%s: PNO Not enabled/Not ready\n", __FUNCTION__));
+		return BCME_NOTREADY;
+	}
+
+	if (!dhd_support_sta_mode(dhd)) {
+		return BCME_BADOPTION;
+	}
+
+	_pno_state = PNO_GET_PNOSTATE(dhd);
+	_params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
+	params_legacy = &(_params->params_legacy);
+	err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
+
+	if (err < 0) {
+		DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n",
+			__FUNCTION__, err));
+		return err;
+	}
+
+	INIT_LIST_HEAD(&params_legacy->ssid_list);
+
+	if (dhd_pno_add_to_ssid_list(dhd, &params_legacy->ssid_list, ssid_list,
+		nssid, &params_legacy->nssid) < 0) {
+		_dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
+		return BCME_ERROR;
+	}
+
+	DHD_PNO(("%s enter : nssid %d, scan_fr :%d, pno_repeat :%d,"
+		"pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__,
+		params_legacy->nssid, scan_fr, pno_repeat, pno_freq_expo_max, nchan));
+
+	return dhd_pno_set_legacy_pno(dhd, scan_fr, pno_repeat,
+		pno_freq_expo_max, channel_list, nchan);
+
+}
+
+static int
+dhd_pno_set_legacy_pno(dhd_pub_t *dhd, uint16  scan_fr, int pno_repeat,
+	int pno_freq_expo_max, uint16 *channel_list, int nchan)
+{
 	dhd_pno_params_t *_params;
 	dhd_pno_params_t *_params2;
 	dhd_pno_status_info_t *_pno_state;
 	uint16 _chan_list[WL_NUMCHANNELS];
 	int32 tot_nchan = 0;
 	int err = BCME_OK;
-	int i;
+	int i, nssid;
 	int mode = 0;
-	NULL_CHECK(dhd, "dhd is NULL", err);
-	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
-	_pno_state = PNO_GET_PNOSTATE(dhd);
+	struct list_head *ssid_list;
 
-	if (!dhd_support_sta_mode(dhd)) {
-		err = BCME_BADOPTION;
-		goto exit_no_clear;
-	}
-	DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d,"
-			"pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__,
-			scan_fr, pno_repeat, pno_freq_expo_max, nchan));
+	_pno_state = PNO_GET_PNOSTATE(dhd);
 
 	_params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
 	/* If GSCAN is also ON will handle this down below */
@@ -1311,7 +1347,7 @@
 	if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE &&
 		!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) {
 #else
-		if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
+	if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
 #endif /* GSCAN_SUPPORT */
 		DHD_ERROR(("%s : Legacy PNO mode was already started, "
 			"will disable previous one to start new one\n", __FUNCTION__));
@@ -1319,16 +1355,10 @@
 		if (err < 0) {
 			DHD_ERROR(("%s : failed to stop legacy PNO (err %d)\n",
 				__FUNCTION__, err));
-			goto exit_no_clear;
+			return err;
 		}
 	}
 	_pno_state->pno_mode |= DHD_PNO_LEGACY_MODE;
-	err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
-	if (err < 0) {
-		DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n",
-			__FUNCTION__, err));
-		goto exit_no_clear;
-	}
 	memset(_chan_list, 0, sizeof(_chan_list));
 	tot_nchan = MIN(nchan, WL_NUMCHANNELS);
 	if (tot_nchan > 0 && channel_list) {
@@ -1339,13 +1369,13 @@
 	else {
 		tot_nchan = WL_NUMCHANNELS;
 		err = _dhd_pno_get_channels(dhd, _chan_list, &tot_nchan,
-				(WLC_BAND_2G | WLC_BAND_5G), FALSE);
+			(WLC_BAND_2G | WLC_BAND_5G), FALSE);
 		if (err < 0) {
 			tot_nchan = 0;
 			DHD_PNO(("Could not get channel list for PNO SSID\n"));
 		} else {
 			for (i = 0; i < tot_nchan; i++)
-			_params->params_legacy.chan_list[i] = _chan_list[i];
+				_params->params_legacy.chan_list[i] = _chan_list[i];
 		}
 	}
 #endif /* GSCAN_SUPPORT */
@@ -1359,7 +1389,7 @@
 		err = _dhd_pno_enable(dhd, PNO_OFF);
 		if (err < 0) {
 			DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__));
-			goto exit_no_clear;
+			goto exit;
 		}
 		/* restore the previous mode */
 		_pno_state->pno_mode = mode;
@@ -1375,7 +1405,7 @@
 					DHD_ERROR(("%s : failed to merge channel list"
 					" between legacy and batch\n",
 						__FUNCTION__));
-					goto exit_no_clear;
+					goto exit;
 				}
 			}  else {
 				DHD_PNO(("superset channel will use"
@@ -1392,7 +1422,7 @@
 					DHD_ERROR(("%s : failed to merge channel list"
 					" between legacy and hotlist\n",
 						__FUNCTION__));
-					goto exit_no_clear;
+					goto exit;
 				}
 			}
 		}
@@ -1401,13 +1431,18 @@
 	_params->params_legacy.pno_repeat = pno_repeat;
 	_params->params_legacy.pno_freq_expo_max = pno_freq_expo_max;
 	_params->params_legacy.nchan = tot_nchan;
-	_params->params_legacy.nssid = 0;
-	INIT_LIST_HEAD(&_params->params_legacy.ssid_list);
+	ssid_list = &_params->params_legacy.ssid_list;
+	nssid = _params->params_legacy.nssid;
+
 #ifdef GSCAN_SUPPORT
 	/* dhd_pno_initiate_gscan_request will handle simultaneous Legacy PNO and GSCAN */
 	if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
-		if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) {
-			err = BCME_ERROR;
+		struct dhd_pno_gscan_params *gscan_params;
+		gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan;
+		/* ePNO and Legacy PNO do not co-exist */
+		if (gscan_params->epno_cfg.num_epno_ssid) {
+			DHD_PNO(("ePNO and Legacy PNO do not co-exist\n"));
+			err = BCME_EPERM;
 			goto exit;
 		}
 		DHD_PNO(("GSCAN mode is ON! Will restart GSCAN+Legacy PNO\n"));
@@ -1421,10 +1456,6 @@
 	}
 	if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) {
 		DHD_ERROR(("failed to add ssid list(err %d), %d in firmware\n", err, nssid));
-		goto exit;
-	}
-	if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) {
-		err = BCME_ERROR;
 		goto exit;
 	}
 	if (tot_nchan > 0) {
@@ -1442,7 +1473,6 @@
 	if (err < 0) {
 		_dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
 	}
-exit_no_clear:
 	/* clear mode in case of error */
 	if (err < 0) {
 		int ret = dhd_pno_clean(dhd);
@@ -1466,7 +1496,6 @@
 	dhd_pno_params_t *_params;
 	dhd_pno_params_t *_params2;
 	dhd_pno_status_info_t *_pno_state;
-	wlc_ssid_ext_t *p_ssid_list = NULL;
 	NULL_CHECK(dhd, "dhd is NULL", err);
 	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
 	NULL_CHECK(batch_params, "batch_params is NULL", err);
@@ -1529,7 +1558,7 @@
 		}
 		DHD_PNO(("\n"));
 }
-#endif
+#endif // endif
 	if (_params->params_batch.nchan) {
 		/* copy the channel list into local array */
 		memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list));
@@ -1562,14 +1591,8 @@
 		} else {
 			DHD_PNO(("superset channel will use all channels in firmware\n"));
 		}
-		p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
-		if (!p_ssid_list) {
-			err = BCME_NOMEM;
-			DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
-			goto exit;
-		}
-		if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list,
-			_params2->params_legacy.nssid)) < 0) {
+		if ((err = _dhd_pno_add_ssid(dhd, &_params2->params_legacy.ssid_list,
+				_params2->params_legacy.nssid)) < 0) {
 			DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err));
 			goto exit;
 		}
@@ -1601,18 +1624,84 @@
 		/* return #max scan firmware can do */
 		err = mscan;
 	}
-	if (p_ssid_list)
-		kfree(p_ssid_list);
 	return err;
 }
 
-
 #ifdef GSCAN_SUPPORT
+
+static int
+dhd_set_epno_params(dhd_pub_t *dhd, wl_ssid_ext_params_t *params, bool set)
+{
+	wl_pfn_ssid_cfg_t cfg;
+	int err;
+	NULL_CHECK(dhd, "dhd is NULL\n", err);
+	memset(&cfg, 0, sizeof(wl_pfn_ssid_cfg_t));
+	cfg.version = WL_PFN_SSID_CFG_VERSION;
+
+	/* If asked to clear params (set == FALSE) just set the CLEAR bit */
+	if (!set)
+		cfg.flags |= WL_PFN_SSID_CFG_CLEAR;
+	else if (params)
+		memcpy(&cfg.params, params, sizeof(wl_ssid_ext_params_t));
+	err = dhd_iovar(dhd, 0, "pfn_ssid_cfg", (char *)&cfg,
+			sizeof(wl_pfn_ssid_cfg_t), NULL, 0, TRUE);
+	if (err != BCME_OK) {
+		DHD_ERROR(("%s : Failed to execute pfn_ssid_cfg %d\n", __FUNCTION__, err));
+	}
+	return err;
+}
+
+int
+dhd_pno_flush_fw_epno(dhd_pub_t *dhd)
+{
+	int err;
+
+	NULL_CHECK(dhd, "dhd is NULL\n", err);
+
+	err = dhd_set_epno_params(dhd, NULL, FALSE);
+	if (err < 0) {
+		DHD_ERROR(("failed to set ePNO params %d\n", err));
+		return err;
+	}
+	err = _dhd_pno_flush_ssid(dhd);
+	return err;
+}
+
+int
+dhd_pno_set_epno(dhd_pub_t *dhd)
+{
+	int err = BCME_OK;
+	dhd_pno_params_t *params;
+	dhd_pno_status_info_t *_pno_state;
+
+	struct dhd_pno_gscan_params *gscan_params;
+
+	NULL_CHECK(dhd, "dhd is NULL\n", err);
+	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
+	_pno_state = PNO_GET_PNOSTATE(dhd);
+	params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
+	gscan_params = &params->params_gscan;
+
+	if (gscan_params->epno_cfg.num_epno_ssid) {
+		DHD_PNO(("num_epno_ssid %d\n", gscan_params->epno_cfg.num_epno_ssid));
+		if ((err = _dhd_pno_add_ssid(dhd, &gscan_params->epno_cfg.epno_ssid_list,
+				gscan_params->epno_cfg.num_epno_ssid)) < 0) {
+			DHD_ERROR(("failed to add ssid list (err %d) to firmware\n", err));
+			return err;
+		}
+		err = dhd_set_epno_params(dhd, &gscan_params->epno_cfg.params, TRUE);
+		if (err < 0) {
+			DHD_ERROR(("failed to set ePNO params %d\n", err));
+		}
+	}
+	return err;
+}
+
 static void
-dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params,
+dhd_pno_reset_cfg_gscan(dhd_pub_t *dhd, dhd_pno_params_t *_params,
             dhd_pno_status_info_t *_pno_state, uint8 flags)
 {
-	DHD_ERROR(("%s enter\n", __FUNCTION__));
+	DHD_PNO(("%s enter\n", __FUNCTION__));
 
 	if (flags & GSCAN_FLUSH_SCAN_CFG) {
 		_params->params_gscan.bestn = 0;
@@ -1629,41 +1718,32 @@
 	if (flags & GSCAN_FLUSH_HOTLIST_CFG) {
 		struct dhd_pno_bssid *iter, *next;
 		if (_params->params_gscan.nbssid_hotlist > 0) {
+			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 			list_for_each_entry_safe(iter, next,
 				&_params->params_gscan.hotlist_bssid_list, list) {
+				GCC_DIAGNOSTIC_POP();
 				list_del(&iter->list);
-				kfree(iter);
+				MFREE(dhd->osh, iter, sizeof(struct dhd_pno_bssid));
 			}
 		}
 		_params->params_gscan.nbssid_hotlist = 0;
 		DHD_PNO(("Flush Hotlist Config\n"));
 	}
-	if (flags & GSCAN_FLUSH_SIGNIFICANT_CFG) {
-		dhd_pno_significant_bssid_t *iter, *next;
-
-		if (_params->params_gscan.nbssid_significant_change > 0) {
-			list_for_each_entry_safe(iter, next,
-				&_params->params_gscan.significant_bssid_list, list) {
-				list_del(&iter->list);
-				kfree(iter);
-			}
-		}
-		_params->params_gscan.nbssid_significant_change = 0;
-		DHD_PNO(("Flush Significant Change Config\n"));
-	}
 	if (flags & GSCAN_FLUSH_EPNO_CFG) {
-		dhd_epno_params_t *iter, *next;
+		dhd_pno_ssid_t *iter, *next;
+		dhd_epno_ssid_cfg_t *epno_cfg = &_params->params_gscan.epno_cfg;
 
-		if (_params->params_gscan.num_epno_ssid > 0) {
+		if (epno_cfg->num_epno_ssid > 0) {
+			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 			list_for_each_entry_safe(iter, next,
-				&_params->params_gscan.epno_ssid_list, list) {
+				&epno_cfg->epno_ssid_list, list) {
+				GCC_DIAGNOSTIC_POP();
 				list_del(&iter->list);
-				kfree(iter);
+				MFREE(dhd->osh, iter, sizeof(struct dhd_pno_bssid));
 			}
+			epno_cfg->num_epno_ssid = 0;
 		}
-		_params->params_gscan.num_epno_ssid = 0;
-		_params->params_gscan.num_visible_epno_ssid = 0;
-		_params->params_gscan.ssid_ext_last_used_index = 0;
+		memset(&epno_cfg->params, 0, sizeof(wl_ssid_ext_params_t));
 		DHD_PNO(("Flushed ePNO Config\n"));
 	}
 
@@ -1739,162 +1819,9 @@
 	return err;
 }
 
-static void *
-dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len)
-{
-	gscan_results_cache_t *iter, *results;
-	dhd_pno_status_info_t *_pno_state;
-	dhd_pno_params_t *_params;
-	uint16 num_scan_ids = 0, num_results = 0;
-
-	_pno_state = PNO_GET_PNOSTATE(dhd);
-	_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
-
-	iter = results = _params->params_gscan.gscan_batch_cache;
-	while (iter) {
-		num_results += iter->tot_count - iter->tot_consumed;
-		num_scan_ids++;
-		iter = iter->next;
-	}
-
-	*len = ((num_results << 16) | (num_scan_ids));
-	return results;
-}
-
-void *
-dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
-         void *info, uint32 *len)
-{
-	void *ret = NULL;
-	dhd_pno_gscan_capabilities_t *ptr;
-	dhd_epno_params_t *epno_params;
-	dhd_pno_params_t *_params;
-	dhd_pno_status_info_t *_pno_state;
-
-	if (!dhd || !dhd->pno_state) {
-		DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__));
-		return NULL;
-	}
-	_pno_state = PNO_GET_PNOSTATE(dhd);
-	_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
-	if (!len) {
-		DHD_ERROR(("%s: len is NULL\n", __FUNCTION__));
-		return NULL;
-	}
-	switch (type) {
-		case DHD_PNO_GET_CAPABILITIES:
-			ptr = (dhd_pno_gscan_capabilities_t *)
-			kmalloc(sizeof(dhd_pno_gscan_capabilities_t), GFP_KERNEL);
-			if (!ptr)
-				break;
-			/* Hardcoding these values for now, need to get
-			 * these values from FW, will change in a later check-in
-			 */
-			ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE;
-			ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS;
-			ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN;
-			ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX;
-			ptr->max_scan_reporting_threshold = 100;
-			ptr->max_hotlist_aps = PFN_HOTLIST_MAX_NUM_APS;
-			ptr->max_significant_wifi_change_aps = PFN_SWC_MAX_NUM_APS;
-			ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM;
-			ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID;
-			ptr->max_white_list_ssid = MAX_WHITELIST_SSID;
-			ret = (void *)ptr;
-			*len = sizeof(dhd_pno_gscan_capabilities_t);
-			break;
-
-		case DHD_PNO_GET_BATCH_RESULTS:
-			ret = dhd_get_gscan_batch_results(dhd, len);
-			break;
-		case DHD_PNO_GET_CHANNEL_LIST:
-			if (info) {
-				uint16 ch_list[WL_NUMCHANNELS];
-				uint32 *ptr, mem_needed, i;
-				int32 err, nchan = WL_NUMCHANNELS;
-				uint32 *gscan_band = (uint32 *) info;
-				uint8 band = 0;
-
-				/* No band specified?, nothing to do */
-				if ((*gscan_band & GSCAN_BAND_MASK) == 0) {
-					DHD_PNO(("No band specified\n"));
-					*len = 0;
-					break;
-				}
-
-				/* HAL and DHD use different bits for 2.4G and
-				 * 5G in bitmap. Hence translating it here...
-				 */
-				if (*gscan_band & GSCAN_BG_BAND_MASK) {
-					band |= WLC_BAND_2G;
-				}
-				if (*gscan_band & GSCAN_A_BAND_MASK) {
-					band |= WLC_BAND_5G;
-				}
-
-				err = _dhd_pno_get_channels(dhd, ch_list, &nchan,
-				                          (band & GSCAN_ABG_BAND_MASK),
-				                          !(*gscan_band & GSCAN_DFS_MASK));
-
-				if (err < 0) {
-					DHD_ERROR(("%s: failed to get valid channel list\n",
-						__FUNCTION__));
-					*len = 0;
-				} else {
-					mem_needed = sizeof(uint32) * nchan;
-					ptr = (uint32 *) kmalloc(mem_needed, GFP_KERNEL);
-					if (!ptr) {
-						DHD_ERROR(("%s: Unable to malloc %d bytes\n",
-							__FUNCTION__, mem_needed));
-						break;
-					}
-					for (i = 0; i < nchan; i++) {
-						ptr[i] = wf_channel2mhz(ch_list[i],
-							(ch_list[i] <= CH_MAX_2G_CHANNEL?
-							WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
-					}
-					ret = ptr;
-					*len = mem_needed;
-				}
-			} else {
-				*len = 0;
-				DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__));
-			}
-			break;
-		case DHD_PNO_GET_EPNO_SSID_ELEM:
-			if (_params->params_gscan.num_epno_ssid >=
-			   (MAX_EPNO_SSID_NUM + MAX_EPNO_HIDDEN_SSID)) {
-				DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n",
-				     _params->params_gscan.num_epno_ssid));
-				return NULL;
-			}
-
-			if (!_params->params_gscan.num_epno_ssid)
-				INIT_LIST_HEAD(&_params->params_gscan.epno_ssid_list);
-
-			epno_params = kzalloc(sizeof(dhd_epno_params_t), GFP_KERNEL);
-			if (!epno_params) {
-				DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes",
-				sizeof(dhd_epno_params_t)));
-				return NULL;
-			}
-			_params->params_gscan.num_epno_ssid++;
-			epno_params->index = DHD_EPNO_DEFAULT_INDEX;
-			list_add_tail(&epno_params->list, &_params->params_gscan.epno_ssid_list);
-			ret = epno_params;
-			break;
-		default:
-			DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type));
-			break;
-	}
-
-	return ret;
-
-}
-
 int
 dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
-    void *buf, uint8 flush)
+    void *buf, bool flush)
 {
 	int err = BCME_OK;
 	dhd_pno_params_t *_params;
@@ -1911,22 +1838,23 @@
 	mutex_lock(&_pno_state->pno_mutex);
 
 	switch (type) {
-		case DHD_PNO_BATCH_SCAN_CFG_ID:
+	case DHD_PNO_BATCH_SCAN_CFG_ID:
 		{
 			gscan_batch_params_t *ptr = (gscan_batch_params_t *)buf;
 			_params->params_gscan.bestn = ptr->bestn;
 			_params->params_gscan.mscan = ptr->mscan;
 			_params->params_gscan.buffer_threshold = ptr->buffer_threshold;
-			break;
 		}
+		break;
 		case DHD_PNO_GEOFENCE_SCAN_CFG_ID:
 		{
 			gscan_hotlist_scan_params_t *ptr = (gscan_hotlist_scan_params_t *)buf;
 			struct dhd_pno_bssid *_pno_bssid;
 			struct bssid_t *bssid_ptr;
 			int8 flags;
+
 			if (flush) {
-				dhd_pno_reset_cfg_gscan(_params, _pno_state,
+				dhd_pno_reset_cfg_gscan(dhd, _params, _pno_state,
 				    GSCAN_FLUSH_HOTLIST_CFG);
 			}
 
@@ -1936,18 +1864,19 @@
 			if (!_params->params_gscan.nbssid_hotlist) {
 				INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list);
 			}
+
 			if ((_params->params_gscan.nbssid_hotlist +
-			          ptr->nbssid) > PFN_SWC_MAX_NUM_APS) {
+					ptr->nbssid) > PFN_SWC_MAX_NUM_APS) {
 				DHD_ERROR(("Excessive number of hotlist APs programmed %d\n",
-				     (_params->params_gscan.nbssid_hotlist +
-				      ptr->nbssid)));
+					(_params->params_gscan.nbssid_hotlist +
+					ptr->nbssid)));
 				err = BCME_RANGE;
 				goto exit;
 			}
 
 			for (i = 0, bssid_ptr = ptr->bssid; i < ptr->nbssid; i++, bssid_ptr++) {
-				_pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL);
-
+				_pno_bssid = (struct dhd_pno_bssid *)MALLOCZ(dhd->osh,
+					sizeof(struct dhd_pno_bssid));
 				if (!_pno_bssid) {
 					DHD_ERROR(("_pno_bssid is NULL, cannot kalloc %zd bytes",
 					       sizeof(struct dhd_pno_bssid)));
@@ -1964,65 +1893,11 @@
 
 			_params->params_gscan.nbssid_hotlist += ptr->nbssid;
 			_params->params_gscan.lost_ap_window = ptr->lost_ap_window;
-			break;
 		}
-		case DHD_PNO_SIGNIFICANT_SCAN_CFG_ID:
+		break;
+	case DHD_PNO_SCAN_CFG_ID:
 		{
-			gscan_swc_params_t *ptr = (gscan_swc_params_t *)buf;
-			dhd_pno_significant_bssid_t *_pno_significant_change_bssid;
-			wl_pfn_significant_bssid_t *significant_bssid_ptr;
-
-			if (flush) {
-				dhd_pno_reset_cfg_gscan(_params, _pno_state,
-				   GSCAN_FLUSH_SIGNIFICANT_CFG);
-			}
-
-			if (!ptr->nbssid) {
-				break;
-			}
-			if (!_params->params_gscan.nbssid_significant_change) {
-				INIT_LIST_HEAD(&_params->params_gscan.significant_bssid_list);
-			}
-			if ((_params->params_gscan.nbssid_significant_change +
-			          ptr->nbssid) > PFN_SWC_MAX_NUM_APS) {
-				DHD_ERROR(("Excessive number of SWC APs programmed %d\n",
-				     (_params->params_gscan.nbssid_significant_change +
-				      ptr->nbssid)));
-				err = BCME_RANGE;
-				goto exit;
-			}
-
-			for (i = 0, significant_bssid_ptr = ptr->bssid_elem_list;
-			     i < ptr->nbssid; i++, significant_bssid_ptr++) {
-				_pno_significant_change_bssid =
-				      kzalloc(sizeof(dhd_pno_significant_bssid_t),
-				      GFP_KERNEL);
-
-				if (!_pno_significant_change_bssid) {
-					DHD_ERROR(("SWC bssidptr is NULL, cannot kalloc %zd bytes",
-					sizeof(dhd_pno_significant_bssid_t)));
-					err = BCME_NOMEM;
-					goto exit;
-				}
-				memcpy(&_pno_significant_change_bssid->BSSID,
-				    &significant_bssid_ptr->macaddr, ETHER_ADDR_LEN);
-				_pno_significant_change_bssid->rssi_low_threshold =
-				    significant_bssid_ptr->rssi_low_threshold;
-				_pno_significant_change_bssid->rssi_high_threshold =
-				    significant_bssid_ptr->rssi_high_threshold;
-				list_add_tail(&_pno_significant_change_bssid->list,
-				    &_params->params_gscan.significant_bssid_list);
-			}
-
-			_params->params_gscan.swc_nbssid_threshold = ptr->swc_threshold;
-			_params->params_gscan.swc_rssi_window_size = ptr->rssi_window;
-			_params->params_gscan.lost_ap_window = ptr->lost_ap_window;
-			_params->params_gscan.nbssid_significant_change += ptr->nbssid;
-			break;
-		}
-		case DHD_PNO_SCAN_CFG_ID:
-		{
-			int i, k;
+			int k;
 			uint16 band;
 			gscan_scan_params_t *ptr = (gscan_scan_params_t *)buf;
 			struct dhd_pno_gscan_channel_bucket *ch_bucket;
@@ -2046,13 +1921,15 @@
 					/* HAL and DHD use different bits for 2.4G and
 					 * 5G in bitmap. Hence translating it here...
 					 */
-					if (band & GSCAN_BG_BAND_MASK)
+					if (band & GSCAN_BG_BAND_MASK) {
 						ch_bucket[i].band |= WLC_BAND_2G;
-					if (band & GSCAN_A_BAND_MASK)
+					}
+					if (band & GSCAN_A_BAND_MASK) {
 						ch_bucket[i].band |= WLC_BAND_5G;
-					if (band & GSCAN_DFS_MASK)
+					}
+					if (band & GSCAN_DFS_MASK) {
 						ch_bucket[i].band |= GSCAN_DFS_MASK;
-
+					}
 					DHD_PNO(("band %d report_flag %d\n", ch_bucket[i].band,
 					          ch_bucket[i].report_flag));
 				}
@@ -2063,8 +1940,8 @@
 					ch_bucket[i].bucket_max_multiple =
 					ch_bucket[i].bucket_max_multiple/ptr->scan_fr;
 					DHD_PNO(("mult %d max_mult %d\n",
-						ch_bucket[i].bucket_freq_multiple,
-						ch_bucket[i].bucket_max_multiple));
+					                 ch_bucket[i].bucket_freq_multiple,
+					                 ch_bucket[i].bucket_max_multiple));
 				}
 				_params->params_gscan.scan_fr = ptr->scan_fr;
 
@@ -2073,27 +1950,34 @@
 			} else {
 				err = BCME_BADARG;
 			}
-			break;
-		}
-	case DHD_PNO_EPNO_CFG_ID:
-		if (flush) {
-			dhd_pno_reset_cfg_gscan(_params, _pno_state,
-			   GSCAN_FLUSH_EPNO_CFG);
-		} else {
-			_params->params_gscan.num_visible_epno_ssid += *((uint16 *)buf);
 		}
 		break;
-		default:
-			err = BCME_BADARG;
-			DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type));
-			break;
+	case DHD_PNO_EPNO_CFG_ID:
+		if (flush) {
+			dhd_pno_reset_cfg_gscan(dhd, _params, _pno_state,
+				GSCAN_FLUSH_EPNO_CFG);
+		}
+		break;
+	case DHD_PNO_EPNO_PARAMS_ID:
+		if (flush) {
+			memset(&_params->params_gscan.epno_cfg.params, 0,
+				sizeof(wl_ssid_ext_params_t));
+		}
+		if (buf) {
+			memcpy(&_params->params_gscan.epno_cfg.params, buf,
+				sizeof(wl_ssid_ext_params_t));
+		}
+		break;
+	default:
+		err = BCME_BADARG;
+		DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type));
+		break;
 	}
 exit:
 	mutex_unlock(&_pno_state->pno_mutex);
 	return err;
 
 }
-
 
 static bool
 validate_gscan_params(struct dhd_pno_gscan_params *gscan_params)
@@ -2125,20 +2009,17 @@
 dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params)
 {
 	int err = BCME_OK;
-	int mode, i = 0, k;
+	int mode, i = 0;
 	uint16 _chan_list[WL_NUMCHANNELS];
 	int tot_nchan = 0;
 	int num_buckets_to_fw, tot_num_buckets, gscan_param_size = 0;
 	dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
 	wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL;
 	wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL;
-	wl_pfn_significant_bssid_t *p_pfn_significant_bssid = NULL;
 	wl_pfn_bssid_t *p_pfn_bssid = NULL;
-	wlc_ssid_ext_t *pssid_list = NULL;
-	dhd_pno_params_t	*params_legacy;
 	dhd_pno_params_t	*_params;
+	bool fw_flushed = FALSE;
 
-	params_legacy = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS];
 	_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
 
 	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
@@ -2161,7 +2042,7 @@
 		err = BCME_BADARG;
 		goto exit;
 	}
-	/* Create channel list based on channel buckets */
+
 	if (!(ch_bucket = dhd_pno_gscan_create_channel_list(dhd, _pno_state,
 	    _chan_list, &tot_num_buckets, &num_buckets_to_fw))) {
 		goto exit;
@@ -2181,23 +2062,21 @@
 			mutex_unlock(&_pno_state->pno_mutex);
 			goto exit;
 		}
+		fw_flushed = TRUE;
 		/* restore the previous mode */
 		_pno_state->pno_mode = mode;
 	}
 	_pno_state->pno_mode |= DHD_PNO_GSCAN_MODE;
 	mutex_unlock(&_pno_state->pno_mutex);
 
-	if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
-		pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
+	if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) &&
+		!gscan_params->epno_cfg.num_epno_ssid) {
+		struct dhd_pno_legacy_params *params_legacy;
+		params_legacy =
+			&(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
 
-		if (!pssid_list) {
-			err = BCME_NOMEM;
-			DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
-			goto exit;
-		}
-
-		if ((err = _dhd_pno_add_ssid(dhd, pssid_list,
-			params_legacy->params_legacy.nssid)) < 0) {
+		if ((err = _dhd_pno_add_ssid(dhd, &params_legacy->ssid_list,
+			params_legacy->nssid)) < 0) {
 			DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err));
 			goto exit;
 		}
@@ -2210,7 +2089,7 @@
 
 	gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) +
 	          (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t);
-	pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOC(dhd->osh, gscan_param_size);
+	pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size);
 
 	if (!pfn_gscan_cfg_t) {
 		DHD_ERROR(("%s: failed to malloc memory of size %d\n",
@@ -2220,40 +2099,28 @@
 	}
 
 	pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION;
-	if (gscan_params->mscan) {
+	if (gscan_params->mscan)
 		pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold;
-	} else {
+	else
 		pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET;
-	}
-	if (gscan_params->nbssid_significant_change) {
-		pfn_gscan_cfg_t->swc_nbssid_threshold = gscan_params->swc_nbssid_threshold;
-		pfn_gscan_cfg_t->swc_rssi_window_size = gscan_params->swc_rssi_window_size;
-		pfn_gscan_cfg_t->lost_ap_window	= gscan_params->lost_ap_window;
-	} else {
-		pfn_gscan_cfg_t->swc_nbssid_threshold = 0;
-		pfn_gscan_cfg_t->swc_rssi_window_size = 0;
-		pfn_gscan_cfg_t->lost_ap_window	= 0;
-	}
 
 	pfn_gscan_cfg_t->flags =
 	         (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK);
+	pfn_gscan_cfg_t->flags |= GSCAN_ALL_BUCKETS_IN_FIRST_SCAN_MASK;
 	pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw;
 	pfn_gscan_cfg_t->retry_threshold = GSCAN_RETRY_THRESHOLD;
 
-	for (i = 0, k = 0; i < tot_num_buckets; i++) {
-		if (ch_bucket[i].bucket_end_index  != CHANNEL_BUCKET_EMPTY_INDEX) {
-			pfn_gscan_cfg_t->channel_bucket[k].bucket_end_index =
-			           ch_bucket[i].bucket_end_index;
-			pfn_gscan_cfg_t->channel_bucket[k].bucket_freq_multiple =
-			           ch_bucket[i].bucket_freq_multiple;
-			pfn_gscan_cfg_t->channel_bucket[k].max_freq_multiple =
-			           ch_bucket[i].max_freq_multiple;
-			pfn_gscan_cfg_t->channel_bucket[k].repeat =
-			           ch_bucket[i].repeat;
-			pfn_gscan_cfg_t->channel_bucket[k].flag =
-			           ch_bucket[i].flag;
-			k++;
-		}
+	for (i = 0; i < num_buckets_to_fw; i++) {
+		pfn_gscan_cfg_t->channel_bucket[i].bucket_end_index =
+		           ch_bucket[i].bucket_end_index;
+		pfn_gscan_cfg_t->channel_bucket[i].bucket_freq_multiple =
+		           ch_bucket[i].bucket_freq_multiple;
+		pfn_gscan_cfg_t->channel_bucket[i].max_freq_multiple =
+		           ch_bucket[i].max_freq_multiple;
+		pfn_gscan_cfg_t->channel_bucket[i].repeat =
+		           ch_bucket[i].repeat;
+		pfn_gscan_cfg_t->channel_bucket[i].flag =
+		           ch_bucket[i].flag;
 	}
 
 	tot_nchan = pfn_gscan_cfg_t->channel_bucket[num_buckets_to_fw - 1].bucket_end_index + 1;
@@ -2271,43 +2138,16 @@
 			__FUNCTION__, err));
 		goto exit;
 	}
-	if (gscan_params->nbssid_significant_change) {
-		dhd_pno_significant_bssid_t *iter, *next;
-
-		p_pfn_significant_bssid = kzalloc(sizeof(wl_pfn_significant_bssid_t) *
-		                   gscan_params->nbssid_significant_change, GFP_KERNEL);
-		if (p_pfn_significant_bssid == NULL) {
-			DHD_ERROR(("%s : failed to allocate memory %zd\n",
-				__FUNCTION__,
-				sizeof(wl_pfn_significant_bssid_t) *
-				gscan_params->nbssid_significant_change));
-			err = BCME_NOMEM;
-			goto exit;
-		}
-		i = 0;
-		/* convert dhd_pno_significant_bssid_t to wl_pfn_significant_bssid_t */
-		list_for_each_entry_safe(iter, next, &gscan_params->significant_bssid_list, list) {
-			p_pfn_significant_bssid[i].rssi_low_threshold = iter->rssi_low_threshold;
-			p_pfn_significant_bssid[i].rssi_high_threshold = iter->rssi_high_threshold;
-			memcpy(&p_pfn_significant_bssid[i].macaddr, &iter->BSSID, ETHER_ADDR_LEN);
-			i++;
-		}
-		DHD_PNO(("nbssid_significant_change %d \n",
-				gscan_params->nbssid_significant_change));
-		err = _dhd_pno_add_significant_bssid(dhd, p_pfn_significant_bssid,
-		                     gscan_params->nbssid_significant_change);
-		if (err < 0) {
-			DHD_ERROR(("%s : failed to call _dhd_pno_add_significant_bssid(err :%d)\n",
-				__FUNCTION__, err));
-			goto exit;
-		}
+	/* Reprogram ePNO cfg from dhd cache if FW has been flushed */
+	if (fw_flushed) {
+		dhd_pno_set_epno(dhd);
 	}
 
 	if (gscan_params->nbssid_hotlist) {
 		struct dhd_pno_bssid *iter, *next;
 		wl_pfn_bssid_t *ptr;
-		p_pfn_bssid = (wl_pfn_bssid_t *)kzalloc(sizeof(wl_pfn_bssid_t) *
-		       gscan_params->nbssid_hotlist, GFP_KERNEL);
+		p_pfn_bssid = (wl_pfn_bssid_t *)MALLOCZ(dhd->osh,
+			sizeof(wl_pfn_bssid_t) * gscan_params->nbssid_hotlist);
 		if (p_pfn_bssid == NULL) {
 			DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array"
 			" (count: %d)",
@@ -2319,10 +2159,15 @@
 		ptr = p_pfn_bssid;
 		/* convert dhd_pno_bssid to wl_pfn_bssid */
 		DHD_PNO(("nhotlist %d\n", gscan_params->nbssid_hotlist));
+		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 		list_for_each_entry_safe(iter, next,
 		          &gscan_params->hotlist_bssid_list, list) {
+			char buffer_hotlist[64];
+			GCC_DIAGNOSTIC_POP();
 			memcpy(&ptr->macaddr,
 			&iter->macaddr, ETHER_ADDR_LEN);
+			BCM_REFERENCE(buffer_hotlist);
+			DHD_PNO(("%s\n", bcm_ether_ntoa(&ptr->macaddr, buffer_hotlist)));
 			ptr->flags = iter->flags;
 			ptr++;
 		}
@@ -2331,15 +2176,6 @@
 		if (err < 0) {
 			DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n",
 				__FUNCTION__, err));
-			goto exit;
-		}
-	}
-
-	if (gscan_params->num_epno_ssid > 0) {
-		DHD_ERROR(("num_epno_ssid %d\n", gscan_params->num_epno_ssid));
-		err = dhd_epno_set_ssid(dhd, _pno_state);
-		if (err  < 0) {
-			DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err));
 			goto exit;
 		}
 	}
@@ -2360,9 +2196,8 @@
 			_pno_state->pno_mode &= ~DHD_PNO_GSCAN_MODE;
 		}
 	}
-	kfree(pssid_list);
-	kfree(p_pfn_significant_bssid);
-	kfree(p_pfn_bssid);
+	MFREE(dhd->osh, p_pfn_bssid,
+		sizeof(wl_pfn_bssid_t) * gscan_params->nbssid_hotlist);
 	if (pfn_gscan_cfg_t) {
 		MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size);
 	}
@@ -2385,12 +2220,16 @@
 	uint16 *ptr = chan_list, max;
 	wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket;
 	dhd_pno_params_t *_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
-	bool is_pno_legacy_running = _pno_state->pno_mode & DHD_PNO_LEGACY_MODE;
+	bool is_pno_legacy_running;
 	dhd_pno_gscan_channel_bucket_t *gscan_buckets = _params->params_gscan.channel_bucket;
+
+	/* ePNO and Legacy PNO do not co-exist */
+	is_pno_legacy_running = ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) &&
+		!_params->params_gscan.epno_cfg.num_epno_ssid);
 
 	if (is_pno_legacy_running)
 		*num_buckets = _params->params_gscan.nchannel_buckets + 1;
-	 else
+	else
 		*num_buckets = _params->params_gscan.nchannel_buckets;
 
 	*num_buckets_to_fw = 0;
@@ -2463,7 +2302,7 @@
 		/* If no space is left then only gscan buckets will be sent to FW */
 		if (nchan) {
 			common_freq = gcd(_params->params_gscan.scan_fr,
-					_params1->params_legacy.scan_fr);
+			                  _params1->params_legacy.scan_fr);
 			max = gscan_buckets[0].bucket_freq_multiple;
 			/* GSCAN buckets */
 			for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) {
@@ -2474,11 +2313,11 @@
 			}
 			/* Legacy PNO bucket */
 			ch_bucket[legacy_bucket_idx].bucket_freq_multiple =
-					_params1->params_legacy.scan_fr;
+			           _params1->params_legacy.scan_fr;
 			ch_bucket[legacy_bucket_idx].bucket_freq_multiple /=
-					common_freq;
+			           common_freq;
 			_params->params_gscan.max_ch_bucket_freq = MAX(max,
-				ch_bucket[legacy_bucket_idx].bucket_freq_multiple);
+			         ch_bucket[legacy_bucket_idx].bucket_freq_multiple);
 			ch_bucket[legacy_bucket_idx].flag = CH_BUCKET_REPORT_REGULAR;
 			/* Now add channels to the legacy scan bucket */
 			for (i = 0; i < _params1->params_legacy.nchan && nchan; i++, nchan--) {
@@ -2488,8 +2327,8 @@
 			ch_bucket[legacy_bucket_idx].bucket_end_index = num_channels - 1;
 			*num_buckets_to_fw = *num_buckets_to_fw + 1;
 			DHD_PNO(("end_idx  %d freq_mult - %d\n",
-					ch_bucket[legacy_bucket_idx].bucket_end_index,
-					ch_bucket[legacy_bucket_idx].bucket_freq_multiple));
+			            ch_bucket[legacy_bucket_idx].bucket_end_index,
+			            ch_bucket[legacy_bucket_idx].bucket_freq_multiple));
 		}
 	}
 	return ch_bucket;
@@ -2501,7 +2340,6 @@
 	int err = BCME_OK;
 	int mode;
 	dhd_pno_status_info_t *_pno_state;
-	wlc_ssid_ext_t *pssid_list = NULL;
 
 	_pno_state = PNO_GET_PNOSTATE(dhd);
 	DHD_PNO(("%s enter\n", __FUNCTION__));
@@ -2538,7 +2376,6 @@
 	}
 	_pno_state->pno_mode = mode;
 	mutex_unlock(&_pno_state->pno_mutex);
-	_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.ssid_ext_last_used_index = 0;
 
 	/* Reprogram Legacy PNO if it was running */
 	if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
@@ -2547,20 +2384,13 @@
 
 		params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
 		_pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
-		pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
-		if (!pssid_list) {
-			err = BCME_NOMEM;
-			DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
-			goto exit;
-		}
 
 		DHD_PNO(("Restarting Legacy PNO SSID scan...\n"));
 		memcpy(chan_list, params_legacy->chan_list,
-		    (params_legacy->nchan * sizeof(uint16)));
-		err = dhd_pno_set_for_ssid(dhd, pssid_list, params_legacy->nssid,
-			params_legacy->scan_fr, params_legacy->pno_repeat,
-			params_legacy->pno_freq_expo_max, chan_list,
-			params_legacy->nchan);
+			(params_legacy->nchan * sizeof(uint16)));
+		err = dhd_pno_set_legacy_pno(dhd, params_legacy->scan_fr,
+			params_legacy->pno_repeat, params_legacy->pno_freq_expo_max,
+			chan_list, params_legacy->nchan);
 		if (err < 0) {
 			DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n",
 				__FUNCTION__, err));
@@ -2570,7 +2400,6 @@
 	}
 
 exit:
-	kfree(pssid_list);
 	return err;
 }
 
@@ -2596,7 +2425,7 @@
 	} else {
 		if (flush) {
 			mutex_lock(&_pno_state->pno_mutex);
-			dhd_pno_reset_cfg_gscan(params, _pno_state, GSCAN_FLUSH_ALL_CFG);
+			dhd_pno_reset_cfg_gscan(dhd, params, _pno_state, GSCAN_FLUSH_ALL_CFG);
 			mutex_unlock(&_pno_state->pno_mutex);
 		}
 		/* Need to stop all gscan */
@@ -2637,13 +2466,14 @@
 	if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
 	    if (old_flag != gscan_params->send_all_results_flag) {
 			wl_pfn_gscan_cfg_t gscan_cfg;
+
 			gscan_cfg.version = WL_GSCAN_CFG_VERSION;
 			gscan_cfg.flags = (gscan_params->send_all_results_flag &
-				GSCAN_SEND_ALL_RESULTS_MASK);
+			                           GSCAN_SEND_ALL_RESULTS_MASK);
 			gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK;
 
 			if ((err = _dhd_pno_gscan_cfg(dhd, &gscan_cfg,
-				sizeof(wl_pfn_gscan_cfg_t))) < 0) {
+			            sizeof(wl_pfn_gscan_cfg_t))) < 0) {
 				DHD_ERROR(("%s : pno_gscan_cfg failed (err %d) in firmware\n",
 					__FUNCTION__, err));
 				goto exit_mutex_unlock;
@@ -2661,7 +2491,7 @@
 }
 
 /* Cleanup any consumed results
- * Return TRUE if all results consumed, else FALSE
+ * Return TRUE if all results consumed else FALSE
  */
 int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd)
 {
@@ -2679,7 +2509,9 @@
 	while (iter) {
 		if (iter->tot_consumed == iter->tot_count) {
 			tmp = iter->next;
-			kfree(iter);
+			MFREE(dhd->osh, iter,
+				((iter->tot_count - 1) * sizeof(wifi_gscan_result_t))
+				+ sizeof(gscan_results_cache_t));
 			iter = tmp;
 		} else
 			break;
@@ -2696,14 +2528,29 @@
 	uint32 timestamp = 0, ts = 0, i, j, timediff;
 	dhd_pno_params_t *params;
 	dhd_pno_status_info_t *_pno_state;
-	wl_pfn_lnet_info_t *plnetinfo;
+	wl_pfn_lnet_info_v1_t *plnetinfo;
+	wl_pfn_lnet_info_v2_t *plnetinfo_v2;
 	struct dhd_pno_gscan_params *gscan_params;
-	wl_pfn_lscanresults_t *plbestnet = NULL;
+	wl_pfn_lscanresults_v1_t *plbestnet_v1 = NULL;
+	wl_pfn_lscanresults_v2_t *plbestnet_v2 = NULL;
 	gscan_results_cache_t *iter, *tail;
 	wifi_gscan_result_t *result;
 	uint8 *nAPs_per_scan = NULL;
 	uint8 num_scans_in_cur_iter;
 	uint16 count;
+	uint16 fwcount;
+	uint16 fwstatus = PFN_INCOMPLETE;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
+	struct timespec64 tm_spec;
+#else
+	struct timespec tm_spec;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */
+
+	/* Static asserts in _dhd_pno_get_for_batch() below guarantee the v1 and v2
+	 * net_info and subnet_info structures are compatible in size and SSID offset,
+	 * allowing v1 to be safely used in the code below except for lscanresults
+	 * fields themselves (status, count, offset to netinfo).
+	 */
 
 	NULL_CHECK(dhd, "dhd is NULL\n", err);
 	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
@@ -2731,7 +2578,14 @@
 		goto exit;
 	}
 
-	plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN);
+	plbestnet_v1 = (wl_pfn_lscanresults_v1_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN);
+	if (!plbestnet_v1) {
+		DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__,
+		      (int)PNO_BESTNET_LEN));
+		err = BCME_NOMEM;
+		goto exit;
+	}
+	plbestnet_v2 = (wl_pfn_lscanresults_v2_t *)plbestnet_v1;
 
 	mutex_lock(&_pno_state->pno_mutex);
 
@@ -2746,136 +2600,284 @@
 	timediff = timediff >> 1;
 
 	/* Ok, now lets start getting results from the FW */
-	plbestnet->status = PFN_INCOMPLETE;
 	tail = gscan_params->gscan_batch_cache;
-	while (plbestnet->status != PFN_COMPLETE) {
-		memset(plbestnet, 0, PNO_BESTNET_LEN);
-		err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN,
-			FALSE);
+	do {
+		err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet_v1, PNO_BESTNET_LEN,
+				FALSE);
 		if (err < 0) {
 			DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n",
 				__FUNCTION__, err));
 			goto exit_mutex_unlock;
 		}
-		DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version,
-			plbestnet->status, plbestnet->count));
-		if (plbestnet->version != PFN_SCANRESULT_VERSION) {
-			err = BCME_VERSION;
-			DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n",
-				plbestnet->version, PFN_SCANRESULT_VERSION));
-			goto exit_mutex_unlock;
-		}
-		if (plbestnet->count == 0) {
-			DHD_PNO(("No more batch results\n"));
-			goto exit_mutex_unlock;
-		}
-		num_scans_in_cur_iter = 0;
-		timestamp = plbestnet->netinfo[0].timestamp;
-		/* find out how many scans' results did we get in this batch of FW results */
-		for (i = 0, count = 0; i < plbestnet->count; i++, count++) {
-			plnetinfo = &plbestnet->netinfo[i];
-			/* Unlikely to happen, but just in case the results from
-			 * FW doesnt make sense..... Assume its part of one single scan
-			 */
-			if (num_scans_in_cur_iter > gscan_params->mscan) {
-				num_scans_in_cur_iter = 0;
-				count = plbestnet->count;
-				break;
-			}
-			if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) {
-				nAPs_per_scan[num_scans_in_cur_iter] = count;
-				count = 0;
-				num_scans_in_cur_iter++;
-			}
-			timestamp = plnetinfo->timestamp;
-		}
-		nAPs_per_scan[num_scans_in_cur_iter] = count;
-		num_scans_in_cur_iter++;
 
-		DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter));
-		plnetinfo = &plbestnet->netinfo[0];
+		get_monotonic_boottime(&tm_spec);
+		if (plbestnet_v1->version == PFN_LBEST_SCAN_RESULT_VERSION_V1) {
+			fwstatus = plbestnet_v1->status;
+			fwcount = plbestnet_v1->count;
+			plnetinfo = &plbestnet_v1->netinfo[0];
 
-		for (i = 0; i < num_scans_in_cur_iter; i++) {
-			iter = (gscan_results_cache_t *)
-			kmalloc(((nAPs_per_scan[i] - 1) * sizeof(wifi_gscan_result_t)) +
-			              sizeof(gscan_results_cache_t), GFP_KERNEL);
-			if (!iter) {
-				DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n",
-				 __FUNCTION__, gscan_params->mscan));
-				err = BCME_NOMEM;
+			DHD_PNO(("ver %d, status : %d, count %d\n",
+				plbestnet_v1->version, fwstatus, fwcount));
+
+			if (fwcount == 0) {
+				DHD_PNO(("No more batch results\n"));
 				goto exit_mutex_unlock;
 			}
-			/* Need this check because the new set of results from FW
-			 * maybe a continuation of previous sets' scan results
+			if (fwcount > BESTN_MAX) {
+				DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n",
+					__FUNCTION__, fwcount, (int)BESTN_MAX));
+				/* Process only BESTN_MAX number of results per batch */
+				fwcount = BESTN_MAX;
+			}
+			num_scans_in_cur_iter = 0;
+
+			timestamp = plnetinfo->timestamp;
+			/* find out how many scans' results did we get in
+			 * this batch of FW results
 			 */
-			if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) {
-				iter->scan_id = ++gscan_params->scan_id;
-			} else {
-				iter->scan_id = gscan_params->scan_id;
-			}
-			DHD_PNO(("scan_id %d tot_count %d\n", gscan_params->scan_id,
-			      nAPs_per_scan[i]));
-			iter->tot_count = nAPs_per_scan[i];
-			iter->tot_consumed = 0;
-			iter->flag = 0;
-			if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) {
-				DHD_PNO(("This scan is aborted\n"));
-				iter->flag = (ENABLE << PNO_STATUS_ABORT);
-			} else if (gscan_params->reason) {
-				iter->flag = (ENABLE << gscan_params->reason);
-			}
-
-			if (!tail) {
-				gscan_params->gscan_batch_cache = iter;
-			} else {
-				tail->next = iter;
-			}
-			tail = iter;
-			iter->next = NULL;
-			for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) {
-				result = &iter->results[j];
-
-				result->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel,
-					(plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL?
-					WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
-				result->rssi = (int32) plnetinfo->RSSI;
-				/* Info not available & not expected */
-				result->beacon_period = 0;
-				result->capability = 0;
-				result->ie_length = 0;
-				result->rtt = (uint64) plnetinfo->rtt0;
-				result->rtt_sd = (uint64) plnetinfo->rtt1;
-				result->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp);
-				ts = plnetinfo->timestamp;
-				if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
-					DHD_ERROR(("%s: Invalid SSID length %d\n",
-					      __FUNCTION__, plnetinfo->pfnsubnet.SSID_len));
-					plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
+			for (i = 0, count = 0; i < fwcount; i++, count++, plnetinfo++) {
+				/* Unlikely to happen, but just in case the results from
+				 * FW doesnt make sense..... Assume its part of one single scan
+				 */
+				if (num_scans_in_cur_iter >= gscan_params->mscan) {
+					num_scans_in_cur_iter = 0;
+					count = fwcount;
+					break;
 				}
-				memcpy(result->ssid, plnetinfo->pfnsubnet.SSID,
-					plnetinfo->pfnsubnet.SSID_len);
-				result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0';
-				memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID,
-				    ETHER_ADDR_LEN);
-
-				DHD_PNO(("\tSSID : "));
-				DHD_PNO(("\n"));
-					DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n",
-					result->macaddr.octet[0],
-					result->macaddr.octet[1],
-					result->macaddr.octet[2],
-					result->macaddr.octet[3],
-					result->macaddr.octet[4],
-					result->macaddr.octet[5]));
-				DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
-					plnetinfo->pfnsubnet.channel,
-					plnetinfo->RSSI, plnetinfo->timestamp));
-				DHD_PNO(("\tRTT0 : %d, RTT1: %d\n",
-				    plnetinfo->rtt0, plnetinfo->rtt1));
-
+				if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) {
+					nAPs_per_scan[num_scans_in_cur_iter] = count;
+					count = 0;
+					num_scans_in_cur_iter++;
+				}
+				timestamp = plnetinfo->timestamp;
 			}
+			if (num_scans_in_cur_iter < gscan_params->mscan) {
+				nAPs_per_scan[num_scans_in_cur_iter] = count;
+				num_scans_in_cur_iter++;
+			}
+
+			DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter));
+			/* reset plnetinfo to the first item for the next loop */
+			plnetinfo -= i;
+
+			for (i = 0; i < num_scans_in_cur_iter; i++) {
+				iter = (gscan_results_cache_t *)
+					MALLOCZ(dhd->osh, ((nAPs_per_scan[i] - 1) *
+					sizeof(wifi_gscan_result_t)) +
+					sizeof(gscan_results_cache_t));
+				if (!iter) {
+					DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n",
+						__FUNCTION__, gscan_params->mscan));
+					err = BCME_NOMEM;
+					goto exit_mutex_unlock;
+				}
+				/* Need this check because the new set of results from FW
+				 * maybe a continuation of previous sets' scan results
+				 */
+				if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) {
+					iter->scan_id = ++gscan_params->scan_id;
+				} else {
+					iter->scan_id = gscan_params->scan_id;
+				}
+				DHD_PNO(("scan_id %d tot_count %d \n",
+					gscan_params->scan_id, nAPs_per_scan[i]));
+				iter->tot_count = nAPs_per_scan[i];
+				iter->tot_consumed = 0;
+				iter->flag = 0;
+				if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) {
+					DHD_PNO(("This scan is aborted\n"));
+					iter->flag = (ENABLE << PNO_STATUS_ABORT);
+				} else if (gscan_params->reason) {
+					iter->flag = (ENABLE << gscan_params->reason);
+				}
+
+				if (!tail) {
+					gscan_params->gscan_batch_cache = iter;
+				} else {
+					tail->next = iter;
+				}
+				tail = iter;
+				iter->next = NULL;
+				for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) {
+					result = &iter->results[j];
+
+					result->channel =
+						wf_channel2mhz(plnetinfo->pfnsubnet.channel,
+						(plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL?
+						WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
+					result->rssi = (int32) plnetinfo->RSSI;
+					result->beacon_period = 0;
+					result->capability = 0;
+					result->rtt = (uint64) plnetinfo->rtt0;
+					result->rtt_sd = (uint64) plnetinfo->rtt1;
+					result->ts = convert_fw_rel_time_to_systime(&tm_spec,
+							plnetinfo->timestamp);
+					ts = plnetinfo->timestamp;
+					if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
+						DHD_ERROR(("%s: Invalid SSID length %d\n",
+							__FUNCTION__,
+							plnetinfo->pfnsubnet.SSID_len));
+						plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
+					}
+					memcpy(result->ssid, plnetinfo->pfnsubnet.SSID,
+						plnetinfo->pfnsubnet.SSID_len);
+					result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0';
+					memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID,
+						ETHER_ADDR_LEN);
+
+					DHD_PNO(("\tSSID : "));
+					DHD_PNO(("\n"));
+					DHD_PNO(("\tBSSID: "MACDBG"\n",
+						MAC2STRDBG(result->macaddr.octet)));
+					DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
+						plnetinfo->pfnsubnet.channel,
+						plnetinfo->RSSI, plnetinfo->timestamp));
+					DHD_PNO(("\tRTT0 : %d, RTT1: %d\n",
+						plnetinfo->rtt0, plnetinfo->rtt1));
+
+				}
+			}
+
+		} else if (plbestnet_v2->version == PFN_LBEST_SCAN_RESULT_VERSION_V2) {
+			fwstatus = plbestnet_v2->status;
+			fwcount = plbestnet_v2->count;
+			plnetinfo_v2 = (wl_pfn_lnet_info_v2_t*)&plbestnet_v2->netinfo[0];
+
+			DHD_PNO(("ver %d, status : %d, count %d\n",
+				plbestnet_v2->version, fwstatus, fwcount));
+
+			if (fwcount == 0) {
+				DHD_PNO(("No more batch results\n"));
+				goto exit_mutex_unlock;
+			}
+			if (fwcount > BESTN_MAX) {
+				DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n",
+					__FUNCTION__, fwcount, (int)BESTN_MAX));
+				/* Process only BESTN_MAX number of results per batch */
+				fwcount = BESTN_MAX;
+			}
+			num_scans_in_cur_iter = 0;
+
+			timestamp = plnetinfo_v2->timestamp;
+			/* find out how many scans' results did we get
+			 * in this batch of FW results
+			 */
+			for (i = 0, count = 0; i < fwcount; i++, count++, plnetinfo_v2++) {
+				/* Unlikely to happen, but just in case the results from
+				 * FW doesnt make sense..... Assume its part of one single scan
+				 */
+				if (num_scans_in_cur_iter >= gscan_params->mscan) {
+					num_scans_in_cur_iter = 0;
+					count = fwcount;
+					break;
+				}
+				if (TIME_DIFF_MS(timestamp, plnetinfo_v2->timestamp) > timediff) {
+					nAPs_per_scan[num_scans_in_cur_iter] = count;
+					count = 0;
+					num_scans_in_cur_iter++;
+				}
+				timestamp = plnetinfo_v2->timestamp;
+			}
+			if (num_scans_in_cur_iter < gscan_params->mscan) {
+				nAPs_per_scan[num_scans_in_cur_iter] = count;
+				num_scans_in_cur_iter++;
+			}
+
+			DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter));
+			/* reset plnetinfo to the first item for the next loop */
+			plnetinfo_v2 -= i;
+
+			for (i = 0; i < num_scans_in_cur_iter; i++) {
+				iter = (gscan_results_cache_t *)
+					MALLOCZ(dhd->osh, ((nAPs_per_scan[i] - 1) *
+					sizeof(wifi_gscan_result_t)) +
+					sizeof(gscan_results_cache_t));
+				if (!iter) {
+					DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n",
+						__FUNCTION__, gscan_params->mscan));
+					err = BCME_NOMEM;
+					goto exit_mutex_unlock;
+				}
+				/* Need this check because the new set of results from FW
+				 * maybe a continuation of previous sets' scan results
+				 */
+				if (TIME_DIFF_MS(ts, plnetinfo_v2->timestamp) > timediff) {
+					iter->scan_id = ++gscan_params->scan_id;
+				} else {
+					iter->scan_id = gscan_params->scan_id;
+				}
+				DHD_PNO(("scan_id %d tot_count %d ch_bucket %x\n",
+					gscan_params->scan_id, nAPs_per_scan[i],
+					plbestnet_v2->scan_ch_buckets[i]));
+				iter->tot_count = nAPs_per_scan[i];
+				iter->scan_ch_bucket = plbestnet_v2->scan_ch_buckets[i];
+				iter->tot_consumed = 0;
+				iter->flag = 0;
+				if (plnetinfo_v2->flags & PFN_PARTIAL_SCAN_MASK) {
+					DHD_PNO(("This scan is aborted\n"));
+					iter->flag = (ENABLE << PNO_STATUS_ABORT);
+				} else if (gscan_params->reason) {
+					iter->flag = (ENABLE << gscan_params->reason);
+				}
+
+				if (!tail) {
+					gscan_params->gscan_batch_cache = iter;
+				} else {
+					tail->next = iter;
+				}
+				tail = iter;
+				iter->next = NULL;
+				for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo_v2++) {
+					result = &iter->results[j];
+
+					result->channel =
+						wf_channel2mhz(plnetinfo_v2->pfnsubnet.channel,
+						(plnetinfo_v2->pfnsubnet.channel <=
+						CH_MAX_2G_CHANNEL?
+						WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
+					result->rssi = (int32) plnetinfo_v2->RSSI;
+					/* Info not available & not expected */
+					result->beacon_period = 0;
+					result->capability = 0;
+					result->rtt = (uint64) plnetinfo_v2->rtt0;
+					result->rtt_sd = (uint64) plnetinfo_v2->rtt1;
+					result->ts = convert_fw_rel_time_to_systime(&tm_spec,
+						plnetinfo_v2->timestamp);
+					ts = plnetinfo_v2->timestamp;
+					if (plnetinfo_v2->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
+						DHD_ERROR(("%s: Invalid SSID length %d\n",
+							__FUNCTION__,
+							plnetinfo_v2->pfnsubnet.SSID_len));
+						plnetinfo_v2->pfnsubnet.SSID_len =
+							DOT11_MAX_SSID_LEN;
+					}
+					memcpy(result->ssid, plnetinfo_v2->pfnsubnet.u.SSID,
+						plnetinfo_v2->pfnsubnet.SSID_len);
+					result->ssid[plnetinfo_v2->pfnsubnet.SSID_len] = '\0';
+					memcpy(&result->macaddr, &plnetinfo_v2->pfnsubnet.BSSID,
+						ETHER_ADDR_LEN);
+
+					DHD_PNO(("\tSSID : "));
+					DHD_PNO(("\n"));
+					DHD_PNO(("\tBSSID: "MACDBG"\n",
+						MAC2STRDBG(result->macaddr.octet)));
+					DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
+						plnetinfo_v2->pfnsubnet.channel,
+						plnetinfo_v2->RSSI, plnetinfo_v2->timestamp));
+					DHD_PNO(("\tRTT0 : %d, RTT1: %d\n",
+						plnetinfo_v2->rtt0, plnetinfo_v2->rtt1));
+
+				}
+			}
+
+		} else {
+			err = BCME_VERSION;
+			DHD_ERROR(("bestnet fw version %d not supported\n",
+				plbestnet_v1->version));
+			goto exit_mutex_unlock;
 		}
-	}
+	} while (fwstatus == PFN_INCOMPLETE);
+
 exit_mutex_unlock:
 	mutex_unlock(&_pno_state->pno_mutex);
 exit:
@@ -2883,15 +2885,175 @@
 	smp_wmb();
 	wake_up_interruptible(&_pno_state->batch_get_wait);
 	if (nAPs_per_scan) {
-		MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan);
+		MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan * sizeof(uint8));
 	}
-	if (plbestnet) {
-		MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN);
+	if (plbestnet_v1) {
+		MFREE(dhd->osh, plbestnet_v1, PNO_BESTNET_LEN);
 	}
 	DHD_PNO(("Batch retrieval done!\n"));
 	return err;
 }
 #endif /* GSCAN_SUPPORT */
+
+#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
+static void *
+dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len)
+{
+	gscan_results_cache_t *iter, *results;
+	dhd_pno_status_info_t *_pno_state;
+	dhd_pno_params_t *_params;
+	uint16 num_scan_ids = 0, num_results = 0;
+
+	_pno_state = PNO_GET_PNOSTATE(dhd);
+	_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
+
+	iter = results = _params->params_gscan.gscan_batch_cache;
+	while (iter) {
+		num_results += iter->tot_count - iter->tot_consumed;
+		num_scan_ids++;
+		iter = iter->next;
+	}
+
+	*len = ((num_results << 16) | (num_scan_ids));
+	return results;
+}
+
+void *
+dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
+         void *info, uint32 *len)
+{
+	void *ret = NULL;
+	dhd_pno_gscan_capabilities_t *ptr;
+	dhd_pno_ssid_t *ssid_elem;
+	dhd_pno_params_t *_params;
+	dhd_epno_ssid_cfg_t *epno_cfg;
+	dhd_pno_status_info_t *_pno_state;
+
+	if (!dhd || !dhd->pno_state) {
+		DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__));
+		return NULL;
+	}
+
+	_pno_state = PNO_GET_PNOSTATE(dhd);
+	_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
+
+	if (!len) {
+		DHD_ERROR(("%s: len is NULL\n", __FUNCTION__));
+		return NULL;
+	}
+
+	switch (type) {
+		case DHD_PNO_GET_CAPABILITIES:
+			ptr = (dhd_pno_gscan_capabilities_t *)
+			MALLOCZ(dhd->osh, sizeof(dhd_pno_gscan_capabilities_t));
+			if (!ptr)
+				break;
+			/* Hardcoding these values for now, need to get
+			 * these values from FW, will change in a later check-in
+			 */
+			ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE;
+			ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS;
+			ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN;
+			ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX;
+			ptr->max_scan_reporting_threshold = 100;
+			ptr->max_hotlist_bssids = PFN_HOTLIST_MAX_NUM_APS;
+			ptr->max_hotlist_ssids = 0;
+			ptr->max_significant_wifi_change_aps = 0;
+			ptr->max_bssid_history_entries = 0;
+			ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM;
+			ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID;
+			ptr->max_white_list_ssid = MAX_WHITELIST_SSID;
+			ret = (void *)ptr;
+			*len = sizeof(dhd_pno_gscan_capabilities_t);
+			break;
+
+		case DHD_PNO_GET_BATCH_RESULTS:
+			ret = dhd_get_gscan_batch_results(dhd, len);
+			break;
+		case DHD_PNO_GET_CHANNEL_LIST:
+			if (info) {
+				uint16 ch_list[WL_NUMCHANNELS];
+				uint32 *p, mem_needed, i;
+				int32 err, nchan = WL_NUMCHANNELS;
+				uint32 *gscan_band = (uint32 *) info;
+				uint8 band = 0;
+
+				/* No band specified?, nothing to do */
+				if ((*gscan_band & GSCAN_BAND_MASK) == 0) {
+					DHD_PNO(("No band specified\n"));
+					*len = 0;
+					break;
+				}
+
+				/* HAL and DHD use different bits for 2.4G and
+				 * 5G in bitmap. Hence translating it here...
+				 */
+				if (*gscan_band & GSCAN_BG_BAND_MASK) {
+					band |= WLC_BAND_2G;
+				}
+				if (*gscan_band & GSCAN_A_BAND_MASK) {
+					band |= WLC_BAND_5G;
+				}
+
+				err = _dhd_pno_get_channels(dhd, ch_list, &nchan,
+				                          (band & GSCAN_ABG_BAND_MASK),
+				                          !(*gscan_band & GSCAN_DFS_MASK));
+
+				if (err < 0) {
+					DHD_ERROR(("%s: failed to get valid channel list\n",
+						__FUNCTION__));
+					*len = 0;
+				} else {
+					mem_needed = sizeof(uint32) * nchan;
+					p = (uint32 *)MALLOC(dhd->osh, mem_needed);
+					if (!p) {
+						DHD_ERROR(("%s: Unable to malloc %d bytes\n",
+							__FUNCTION__, mem_needed));
+						break;
+					}
+					for (i = 0; i < nchan; i++) {
+						p[i] = wf_channel2mhz(ch_list[i],
+							(ch_list[i] <= CH_MAX_2G_CHANNEL?
+							WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
+					}
+					ret = p;
+					*len = mem_needed;
+				}
+			} else {
+				*len = 0;
+				DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__));
+			}
+			break;
+		case DHD_PNO_GET_NEW_EPNO_SSID_ELEM:
+			epno_cfg = &_params->params_gscan.epno_cfg;
+			if (epno_cfg->num_epno_ssid >=
+					MAX_EPNO_SSID_NUM) {
+				DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n",
+					epno_cfg->num_epno_ssid));
+				return NULL;
+			}
+			if (!epno_cfg->num_epno_ssid) {
+				INIT_LIST_HEAD(&epno_cfg->epno_ssid_list);
+			}
+			ssid_elem = MALLOCZ(dhd->osh, sizeof(dhd_pno_ssid_t));
+			if (!ssid_elem) {
+				DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes",
+					sizeof(dhd_pno_ssid_t)));
+				return NULL;
+			}
+			epno_cfg->num_epno_ssid++;
+			list_add_tail(&ssid_elem->list, &epno_cfg->epno_ssid_list);
+			ret = ssid_elem;
+			break;
+		default:
+			DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type));
+			break;
+	}
+
+	return ret;
+
+}
+#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
 
 static int
 _dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason)
@@ -2901,20 +3063,38 @@
 	uint32 timestamp = 0;
 	dhd_pno_params_t *_params = NULL;
 	dhd_pno_status_info_t *_pno_state = NULL;
-	wl_pfn_lscanresults_t *plbestnet = NULL;
-	wl_pfn_lnet_info_t *plnetinfo;
+	wl_pfn_lscanresults_v1_t *plbestnet_v1 = NULL;
+	wl_pfn_lscanresults_v2_t *plbestnet_v2 = NULL;
+	wl_pfn_lnet_info_v1_t *plnetinfo;
+	wl_pfn_lnet_info_v2_t *plnetinfo_v2;
 	dhd_pno_bestnet_entry_t *pbestnet_entry;
 	dhd_pno_best_header_t *pbestnetheader = NULL;
 	dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext;
 	bool allocate_header = FALSE;
+	uint16 fwstatus = PFN_INCOMPLETE;
+	uint16 fwcount;
+
 	NULL_CHECK(dhd, "dhd is NULL", err);
 	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
+
+	/* The static asserts below guarantee the v1 and v2 net_info and subnet_info
+	 * structures are compatible in size and SSID offset, allowing v1 to be safely
+	 * used in the code below except for lscanresults fields themselves
+	 * (status, count, offset to netinfo).
+	 */
+	STATIC_ASSERT(sizeof(wl_pfn_net_info_v1_t) == sizeof(wl_pfn_net_info_v2_t));
+	STATIC_ASSERT(sizeof(wl_pfn_lnet_info_v1_t) == sizeof(wl_pfn_lnet_info_v2_t));
+	STATIC_ASSERT(sizeof(wl_pfn_subnet_info_v1_t) == sizeof(wl_pfn_subnet_info_v2_t));
+	STATIC_ASSERT(OFFSETOF(wl_pfn_subnet_info_v1_t, SSID) ==
+	              OFFSETOF(wl_pfn_subnet_info_v2_t, u.SSID));
+
+	DHD_PNO(("%s enter\n", __FUNCTION__));
+	_pno_state = PNO_GET_PNOSTATE(dhd);
+
 	if (!dhd_support_sta_mode(dhd)) {
 		err = BCME_BADOPTION;
 		goto exit_no_unlock;
 	}
-	DHD_PNO(("%s enter\n", __FUNCTION__));
-	_pno_state = PNO_GET_PNOSTATE(dhd);
 
 	if (!WLS_SUPPORTED(_pno_state)) {
 		DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__));
@@ -2939,8 +3119,10 @@
 			/* this is a first try to get batching results */
 			if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) {
 				/* move the scan_results_list to expired_scan_results_lists */
+				GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 				list_for_each_entry_safe(siter, snext,
 					&_params->params_batch.get_batch.scan_results_list, list) {
+					GCC_DIAGNOSTIC_POP();
 					list_move_tail(&siter->list,
 					&_params->params_batch.get_batch.expired_scan_results_list);
 				}
@@ -2975,14 +3157,15 @@
 		list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list);
 
 	}
-	plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN);
-	NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err);
+
+	plbestnet_v1 = (wl_pfn_lscanresults_v1_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN);
+	NULL_CHECK(plbestnet_v1, "failed to allocate buffer for bestnet", err);
+	plbestnet_v2 = (wl_pfn_lscanresults_v2_t*)plbestnet_v1;
+
 	DHD_PNO(("%s enter\n", __FUNCTION__));
-	memset(plbestnet, 0, PNO_BESTNET_LEN);
-	while (plbestnet->status != PFN_COMPLETE) {
-		memset(plbestnet, 0, PNO_BESTNET_LEN);
-		err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN,
-			FALSE);
+	do {
+		err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet_v1, PNO_BESTNET_LEN,
+				FALSE);
 		if (err < 0) {
 			if (err == BCME_EPERM) {
 				DHD_ERROR(("we cannot get the batching data "
@@ -2995,107 +3178,229 @@
 				goto exit;
 			}
 		}
-		DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version,
-			plbestnet->status, plbestnet->count));
-		if (plbestnet->version != PFN_SCANRESULT_VERSION) {
-			err = BCME_VERSION;
-			DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n",
-				plbestnet->version, PFN_SCANRESULT_VERSION));
-			goto exit;
-		}
-		plnetinfo = plbestnet->netinfo;
-		for (i = 0; i < plbestnet->count; i++) {
-			pbestnet_entry = (dhd_pno_bestnet_entry_t *)
-			MALLOC(dhd->osh, BESTNET_ENTRY_SIZE);
-			if (pbestnet_entry == NULL) {
-				err = BCME_NOMEM;
-				DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n"));
+
+		if (plbestnet_v1->version == PFN_LBEST_SCAN_RESULT_VERSION_V1) {
+			fwstatus = plbestnet_v1->status;
+			fwcount = plbestnet_v1->count;
+			plnetinfo = &plbestnet_v1->netinfo[0];
+			if (fwcount == 0) {
+				DHD_PNO(("No more batch results\n"));
 				goto exit;
 			}
-			memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE);
-			pbestnet_entry->recorded_time = jiffies; /* record the current time */
-			/* create header for the first entry */
-			allocate_header = (i == 0)? TRUE : FALSE;
-			/* check whether the new generation is started or not */
-			if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp)
-				> TIME_MIN_DIFF))
-				allocate_header = TRUE;
-			timestamp = plnetinfo->timestamp;
-			if (allocate_header) {
-				pbestnetheader = (dhd_pno_best_header_t *)
-				MALLOC(dhd->osh, BEST_HEADER_SIZE);
-				if (pbestnetheader == NULL) {
+			if (fwcount > BESTN_MAX) {
+				DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n",
+					__FUNCTION__, fwcount, (int)BESTN_MAX));
+				/* Process only BESTN_MAX number of results per batch */
+				fwcount = BESTN_MAX;
+			}
+			for (i = 0; i < fwcount; i++) {
+				pbestnet_entry = (dhd_pno_bestnet_entry_t *)
+					MALLOC(dhd->osh, BESTNET_ENTRY_SIZE);
+				if (pbestnet_entry == NULL) {
 					err = BCME_NOMEM;
-					if (pbestnet_entry)
-						MFREE(dhd->osh, pbestnet_entry,
-						BESTNET_ENTRY_SIZE);
 					DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n"));
 					goto exit;
 				}
-				/* increase total cnt of bestnet header */
-				pscan_results->cnt_header++;
-				/* need to record the reason to call dhd_pno_get_for_bach */
-				if (reason)
-					pbestnetheader->reason = (ENABLE << reason);
-				memset(pbestnetheader, 0, BEST_HEADER_SIZE);
-				/* initialize the head of linked list */
-				INIT_LIST_HEAD(&(pbestnetheader->entry_list));
-				/* link the pbestnet heaer into existed list */
-				if (pscan_results->bestnetheader == NULL)
-					/* In case of header */
-					pscan_results->bestnetheader = pbestnetheader;
-				else {
-					dhd_pno_best_header_t *head = pscan_results->bestnetheader;
-					pscan_results->bestnetheader = pbestnetheader;
-					pbestnetheader->next = head;
+				memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE);
+				/* record the current time */
+				pbestnet_entry->recorded_time = jiffies;
+				/* create header for the first entry */
+				allocate_header = (i == 0)? TRUE : FALSE;
+				/* check whether the new generation is started or not */
+				if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp)
+					> TIME_MIN_DIFF))
+					allocate_header = TRUE;
+				timestamp = plnetinfo->timestamp;
+				if (allocate_header) {
+					pbestnetheader = (dhd_pno_best_header_t *)
+						MALLOC(dhd->osh, BEST_HEADER_SIZE);
+					if (pbestnetheader == NULL) {
+						err = BCME_NOMEM;
+						if (pbestnet_entry)
+							MFREE(dhd->osh, pbestnet_entry,
+								BESTNET_ENTRY_SIZE);
+						DHD_ERROR(("failed to allocate"
+							" dhd_pno_bestnet_entry\n"));
+						goto exit;
+					}
+					/* increase total cnt of bestnet header */
+					pscan_results->cnt_header++;
+					/* need to record the reason to call dhd_pno_get_for_bach */
+					if (reason)
+						pbestnetheader->reason = (ENABLE << reason);
+					memset(pbestnetheader, 0, BEST_HEADER_SIZE);
+					/* initialize the head of linked list */
+					INIT_LIST_HEAD(&(pbestnetheader->entry_list));
+					/* link the pbestnet heaer into existed list */
+					if (pscan_results->bestnetheader == NULL)
+						/* In case of header */
+						pscan_results->bestnetheader = pbestnetheader;
+					else {
+						dhd_pno_best_header_t *head =
+							pscan_results->bestnetheader;
+						pscan_results->bestnetheader = pbestnetheader;
+						pbestnetheader->next = head;
+					}
 				}
+				pbestnet_entry->channel = plnetinfo->pfnsubnet.channel;
+				pbestnet_entry->RSSI = plnetinfo->RSSI;
+				if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) {
+					/* if RSSI is positive value, we assume that
+					 * this scan is aborted by other scan
+					 */
+					DHD_PNO(("This scan is aborted\n"));
+					pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT);
+				}
+				pbestnet_entry->rtt0 = plnetinfo->rtt0;
+				pbestnet_entry->rtt1 = plnetinfo->rtt1;
+				pbestnet_entry->timestamp = plnetinfo->timestamp;
+				if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
+					DHD_ERROR(("%s: Invalid SSID length"
+						" %d: trimming it to max\n",
+						__FUNCTION__, plnetinfo->pfnsubnet.SSID_len));
+					plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
+				}
+				pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len;
+				memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID,
+						pbestnet_entry->SSID_len);
+				memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID,
+						ETHER_ADDR_LEN);
+				/* add the element into list */
+				list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list);
+				/* increase best entry count */
+				pbestnetheader->tot_cnt++;
+				pbestnetheader->tot_size += BESTNET_ENTRY_SIZE;
+				DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1));
+				DHD_PNO(("\tSSID : "));
+				for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++)
+					DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j]));
+				DHD_PNO(("\n"));
+				DHD_PNO(("\tBSSID: "MACDBG"\n",
+					MAC2STRDBG(plnetinfo->pfnsubnet.BSSID.octet)));
+				DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
+					plnetinfo->pfnsubnet.channel,
+					plnetinfo->RSSI, plnetinfo->timestamp));
+				DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0,
+					plnetinfo->rtt1));
+				plnetinfo++;
 			}
-			/* fills the best network info */
-			pbestnet_entry->channel = plnetinfo->pfnsubnet.channel;
-			pbestnet_entry->RSSI = plnetinfo->RSSI;
-			if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) {
-				/* if RSSI is positive value, we assume that
-				 * this scan is aborted by other scan
-				 */
-				DHD_PNO(("This scan is aborted\n"));
-				pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT);
+		} else if (plbestnet_v2->version == PFN_LBEST_SCAN_RESULT_VERSION_V2) {
+			fwstatus = plbestnet_v2->status;
+			fwcount = plbestnet_v2->count;
+			plnetinfo_v2 = (wl_pfn_lnet_info_v2_t*)&plbestnet_v2->netinfo[0];
+			if (fwcount == 0) {
+				DHD_PNO(("No more batch results\n"));
+				goto exit;
 			}
-			pbestnet_entry->rtt0 = plnetinfo->rtt0;
-			pbestnet_entry->rtt1 = plnetinfo->rtt1;
-			pbestnet_entry->timestamp = plnetinfo->timestamp;
-			if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
-				DHD_ERROR(("%s: Invalid SSID length %d: trimming it to max\n",
-				      __FUNCTION__, plnetinfo->pfnsubnet.SSID_len));
-				plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
+			if (fwcount > BESTN_MAX) {
+				DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n",
+					__FUNCTION__, fwcount, (int)BESTN_MAX));
+				/* Process only BESTN_MAX number of results per batch */
+				fwcount = BESTN_MAX;
 			}
-			pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len;
-			memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID,
-				pbestnet_entry->SSID_len);
-			memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN);
-			/* add the element into list */
-			list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list);
-			/* increase best entry count */
-			pbestnetheader->tot_cnt++;
-			pbestnetheader->tot_size += BESTNET_ENTRY_SIZE;
-			DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1));
-			DHD_PNO(("\tSSID : "));
-			for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++)
-				DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j]));
-			DHD_PNO(("\n"));
-			DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n",
-				plnetinfo->pfnsubnet.BSSID.octet[0],
-				plnetinfo->pfnsubnet.BSSID.octet[1],
-				plnetinfo->pfnsubnet.BSSID.octet[2],
-				plnetinfo->pfnsubnet.BSSID.octet[3],
-				plnetinfo->pfnsubnet.BSSID.octet[4],
-				plnetinfo->pfnsubnet.BSSID.octet[5]));
-			DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
-				plnetinfo->pfnsubnet.channel,
-				plnetinfo->RSSI, plnetinfo->timestamp));
-			DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1));
-			plnetinfo++;
+			DHD_PNO(("ver %d, status : %d, count %d\n",
+				plbestnet_v2->version, fwstatus, fwcount));
+
+			for (i = 0; i < fwcount; i++) {
+				pbestnet_entry = (dhd_pno_bestnet_entry_t *)
+					MALLOC(dhd->osh, BESTNET_ENTRY_SIZE);
+				if (pbestnet_entry == NULL) {
+					err = BCME_NOMEM;
+					DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n"));
+					goto exit;
+				}
+				memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE);
+				/* record the current time */
+				pbestnet_entry->recorded_time = jiffies;
+				/* create header for the first entry */
+				allocate_header = (i == 0)? TRUE : FALSE;
+				/* check whether the new generation is started or not */
+				if (timestamp && (TIME_DIFF(timestamp, plnetinfo_v2->timestamp)
+					> TIME_MIN_DIFF))
+					allocate_header = TRUE;
+				timestamp = plnetinfo_v2->timestamp;
+				if (allocate_header) {
+					pbestnetheader = (dhd_pno_best_header_t *)
+						MALLOC(dhd->osh, BEST_HEADER_SIZE);
+					if (pbestnetheader == NULL) {
+						err = BCME_NOMEM;
+						if (pbestnet_entry)
+							MFREE(dhd->osh, pbestnet_entry,
+								BESTNET_ENTRY_SIZE);
+						DHD_ERROR(("failed to allocate"
+							" dhd_pno_bestnet_entry\n"));
+						goto exit;
+					}
+					/* increase total cnt of bestnet header */
+					pscan_results->cnt_header++;
+					/* need to record the reason to call dhd_pno_get_for_bach */
+					if (reason)
+						pbestnetheader->reason = (ENABLE << reason);
+					memset(pbestnetheader, 0, BEST_HEADER_SIZE);
+					/* initialize the head of linked list */
+					INIT_LIST_HEAD(&(pbestnetheader->entry_list));
+					/* link the pbestnet heaer into existed list */
+					if (pscan_results->bestnetheader == NULL)
+						/* In case of header */
+						pscan_results->bestnetheader = pbestnetheader;
+					else {
+						dhd_pno_best_header_t *head =
+							pscan_results->bestnetheader;
+						pscan_results->bestnetheader = pbestnetheader;
+						pbestnetheader->next = head;
+					}
+				}
+				/* fills the best network info */
+				pbestnet_entry->channel = plnetinfo_v2->pfnsubnet.channel;
+				pbestnet_entry->RSSI = plnetinfo_v2->RSSI;
+				if (plnetinfo_v2->flags & PFN_PARTIAL_SCAN_MASK) {
+					/* if RSSI is positive value, we assume that
+					 * this scan is aborted by other scan
+					 */
+					DHD_PNO(("This scan is aborted\n"));
+					pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT);
+				}
+				pbestnet_entry->rtt0 = plnetinfo_v2->rtt0;
+				pbestnet_entry->rtt1 = plnetinfo_v2->rtt1;
+				pbestnet_entry->timestamp = plnetinfo_v2->timestamp;
+				if (plnetinfo_v2->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
+					DHD_ERROR(("%s: Invalid SSID length"
+						" %d: trimming it to max\n",
+						__FUNCTION__, plnetinfo_v2->pfnsubnet.SSID_len));
+					plnetinfo_v2->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
+				}
+				pbestnet_entry->SSID_len = plnetinfo_v2->pfnsubnet.SSID_len;
+				memcpy(pbestnet_entry->SSID, plnetinfo_v2->pfnsubnet.u.SSID,
+					pbestnet_entry->SSID_len);
+				memcpy(&pbestnet_entry->BSSID, &plnetinfo_v2->pfnsubnet.BSSID,
+					ETHER_ADDR_LEN);
+				/* add the element into list */
+				list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list);
+				/* increase best entry count */
+				pbestnetheader->tot_cnt++;
+				pbestnetheader->tot_size += BESTNET_ENTRY_SIZE;
+				DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1));
+				DHD_PNO(("\tSSID : "));
+				for (j = 0; j < plnetinfo_v2->pfnsubnet.SSID_len; j++)
+					DHD_PNO(("%c", plnetinfo_v2->pfnsubnet.u.SSID[j]));
+				DHD_PNO(("\n"));
+				DHD_PNO(("\tBSSID: "MACDBG"\n",
+					MAC2STRDBG(plnetinfo_v2->pfnsubnet.BSSID.octet)));
+				DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
+					plnetinfo_v2->pfnsubnet.channel,
+					plnetinfo_v2->RSSI, plnetinfo_v2->timestamp));
+				DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo_v2->rtt0,
+					plnetinfo_v2->rtt1));
+				plnetinfo_v2++;
+			}
+		} else {
+			err = BCME_VERSION;
+			DHD_ERROR(("bestnet fw version %d not supported\n",
+				plbestnet_v1->version));
+			goto exit;
 		}
-	}
+	} while (fwstatus != PFN_COMPLETE);
+
 	if (pscan_results->cnt_header == 0) {
 		/* In case that we didn't get any data from the firmware
 		 * Remove the current scan_result list from get_bach.scan_results_list.
@@ -3104,16 +3409,19 @@
 		list_del(&pscan_results->list);
 		MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE);
 		_params->params_batch.get_batch.top_node_cnt--;
+	} else {
+		/* increase total scan count using current scan count */
+		_params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header;
 	}
-	/* increase total scan count using current scan count */
-	_params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header;
 
 	if (buf && bufsize) {
 		/* This is a first try to get batching results */
 		if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) {
 			/* move the scan_results_list to expired_scan_results_lists */
+			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 			list_for_each_entry_safe(siter, snext,
 				&_params->params_batch.get_batch.scan_results_list, list) {
+				GCC_DIAGNOSTIC_POP();
 				list_move_tail(&siter->list,
 					&_params->params_batch.get_batch.expired_scan_results_list);
 			}
@@ -3131,8 +3439,8 @@
 		}
 	}
 exit:
-	if (plbestnet)
-		MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN);
+	if (plbestnet_v1)
+		MFREE(dhd->osh, plbestnet_v1, PNO_BESTNET_LEN);
 	if (_params) {
 		_params->params_batch.get_batch.buf = NULL;
 		_params->params_batch.get_batch.bufsize = 0;
@@ -3140,7 +3448,11 @@
 	}
 	mutex_unlock(&_pno_state->pno_mutex);
 exit_no_unlock:
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
+	if (swait_active(&_pno_state->get_batch_done.wait))
+#else
 	if (waitqueue_active(&_pno_state->get_batch_done.wait))
+#endif/* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) */
 		complete(&_pno_state->get_batch_done);
 	return err;
 }
@@ -3151,12 +3463,16 @@
 	dhd_pub_t *dhd;
 	struct dhd_pno_batch_params *params_batch;
 	DHD_PNO(("%s enter\n", __FUNCTION__));
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 	_pno_state = container_of(work, struct dhd_pno_status_info, work);
+	GCC_DIAGNOSTIC_POP();
+
 	dhd = _pno_state->dhd;
 	if (dhd == NULL) {
 		DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__));
 		return;
 	}
+
 #ifdef GSCAN_SUPPORT
 	_dhd_pno_get_gscan_batch_from_fw(dhd);
 #endif /* GSCAN_SUPPORT */
@@ -3202,13 +3518,13 @@
 			     msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT));
 		}
 	} else
-#endif
+#endif // endif
 	{
 		if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) {
 			DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__));
 			memset(pbuf, 0, bufsize);
-			pbuf += sprintf(pbuf, "scancount=%d\n", 0);
-			sprintf(pbuf, "%s", RESULTS_END_MARKER);
+			pbuf += snprintf(pbuf, bufsize, "scancount=%d\n", 0);
+			snprintf(pbuf, bufsize, "%s", RESULTS_END_MARKER);
 			err = strlen(buf);
 			goto exit;
 		}
@@ -3222,7 +3538,7 @@
 
 #ifdef GSCAN_SUPPORT
 	if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE))
-#endif
+#endif // endif
 	err = params_batch->get_batch.bytes_written;
 exit:
 	return err;
@@ -3237,7 +3553,6 @@
 	dhd_pno_status_info_t *_pno_state;
 	dhd_pno_params_t *_params;
 	wl_pfn_bssid_t *p_pfn_bssid = NULL;
-	wlc_ssid_ext_t *p_ssid_list = NULL;
 	NULL_CHECK(dhd, "dhd is NULL", err);
 	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
 	_pno_state = PNO_GET_PNOSTATE(dhd);
@@ -3258,7 +3573,7 @@
 		DHD_PNO(("Gscan is ongoing, nothing to stop here\n"));
 		return err;
 	}
-#endif
+#endif // endif
 
 	if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) {
 		DHD_ERROR(("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__));
@@ -3267,23 +3582,23 @@
 	_pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE;
 	if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) {
 		mode = _pno_state->pno_mode;
-		dhd_pno_clean(dhd);
+		err = dhd_pno_clean(dhd);
+		if (err < 0) {
+			DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
+				__FUNCTION__, err));
+			goto exit;
+		}
+
 		_pno_state->pno_mode = mode;
 		/* restart Legacy PNO if the Legacy PNO is on */
 		if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
 			struct dhd_pno_legacy_params *_params_legacy;
 			_params_legacy =
 				&(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
-			p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
-			if (!p_ssid_list) {
-				err = BCME_NOMEM;
-				DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
-				goto exit;
-			}
-			err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid,
-				_params_legacy->scan_fr, _params_legacy->pno_repeat,
-				_params_legacy->pno_freq_expo_max, _params_legacy->chan_list,
-				_params_legacy->nchan);
+			err = dhd_pno_set_legacy_pno(dhd, _params_legacy->scan_fr,
+				_params_legacy->pno_repeat,
+				_params_legacy->pno_freq_expo_max,
+				_params_legacy->chan_list, _params_legacy->nchan);
 			if (err < 0) {
 				DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n",
 					__FUNCTION__, err));
@@ -3292,8 +3607,8 @@
 		} else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) {
 			struct dhd_pno_bssid *iter, *next;
 			_params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]);
-			p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) *
-				_params->params_hotlist.nbssid, GFP_KERNEL);
+			p_pfn_bssid = (wl_pfn_bssid_t *)MALLOCZ(dhd->osh,
+				sizeof(wl_pfn_bssid_t) * _params->params_hotlist.nbssid);
 			if (p_pfn_bssid == NULL) {
 				DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array"
 					" (count: %d)",
@@ -3304,8 +3619,10 @@
 			}
 			i = 0;
 			/* convert dhd_pno_bssid to wl_pfn_bssid */
+			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 			list_for_each_entry_safe(iter, next,
 				&_params->params_hotlist.bssid_list, list) {
+				GCC_DIAGNOSTIC_POP();
 				memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN);
 				p_pfn_bssid[i].flags = iter->flags;
 				i++;
@@ -3329,8 +3646,8 @@
 exit:
 	_params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS];
 	_dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE);
-	kfree(p_ssid_list);
-	kfree(p_pfn_bssid);
+	MFREE(dhd->osh, p_pfn_bssid,
+		sizeof(wl_pfn_bssid_t) * _params->params_hotlist.nbssid);
 	return err;
 }
 
@@ -3407,7 +3724,7 @@
 		}
 		DHD_PNO(("\n"));
 }
-#endif
+#endif // endif
 	if (_params->params_hotlist.nchan) {
 		/* copy the channel list into local array */
 		memcpy(_chan_list, _params->params_hotlist.chan_list,
@@ -3465,7 +3782,8 @@
 		}
 	}
 	for (i = 0; i < hotlist_params->nbssid; i++) {
-		_pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL);
+		_pno_bssid = (struct dhd_pno_bssid *)MALLOCZ(dhd->osh,
+			sizeof(struct dhd_pno_bssid));
 		NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err);
 		memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN);
 		_pno_bssid->flags = p_pfn_bssid[i].flags;
@@ -3490,7 +3808,6 @@
 	uint32 mode = 0;
 	dhd_pno_status_info_t *_pno_state;
 	dhd_pno_params_t *_params;
-	wlc_ssid_ext_t *p_ssid_list = NULL;
 	NULL_CHECK(dhd, "dhd is NULL", err);
 	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
 	_pno_state = PNO_GET_PNOSTATE(dhd);
@@ -3527,16 +3844,9 @@
 			struct dhd_pno_legacy_params *_params_legacy;
 			_params_legacy =
 			&(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
-			p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
-			if (!p_ssid_list) {
-				err = BCME_NOMEM;
-				DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
-				goto exit;
-			}
-			err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid,
-				_params_legacy->scan_fr, _params_legacy->pno_repeat,
-				_params_legacy->pno_freq_expo_max, _params_legacy->chan_list,
-				_params_legacy->nchan);
+			err = dhd_pno_set_legacy_pno(dhd, _params_legacy->scan_fr,
+				_params_legacy->pno_repeat, _params_legacy->pno_freq_expo_max,
+				_params_legacy->chan_list, _params_legacy->nchan);
 			if (err < 0) {
 				DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n",
 					__FUNCTION__, err));
@@ -3563,7 +3873,6 @@
 		}
 	}
 exit:
-	kfree(p_ssid_list);
 	return err;
 }
 
@@ -3599,82 +3908,6 @@
 	return err;
 }
 
-/* Handle Significant WiFi Change (SWC) event from FW
- * Send event to HAL when all results arrive from FW
- */
-void *
-dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes)
-{
-	void *ptr = NULL;
-	dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
-	struct dhd_pno_gscan_params *gscan_params;
-	struct dhd_pno_swc_evt_param *params;
-	wl_pfn_swc_results_t *results = (wl_pfn_swc_results_t *)event_data;
-	wl_pfn_significant_net_t *change_array;
-	int i;
-
-	gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
-	params = &(gscan_params->param_significant);
-
-	if (!results->total_count) {
-		*send_evt_bytes = 0;
-		return ptr;
-	}
-
-	if (!params->results_rxed_so_far) {
-		if (!params->change_array) {
-			params->change_array = (wl_pfn_significant_net_t *)
-			kmalloc(sizeof(wl_pfn_significant_net_t) * results->total_count,
-			GFP_KERNEL);
-
-			if (!params->change_array) {
-				DHD_ERROR(("%s Cannot Malloc %zd bytes!!\n", __FUNCTION__,
-				sizeof(wl_pfn_significant_net_t) * results->total_count));
-				*send_evt_bytes = 0;
-				return ptr;
-			}
-		} else {
-			DHD_ERROR(("RX'ed WLC_E_PFN_SWC evt from FW, previous evt not complete!!"));
-			*send_evt_bytes = 0;
-			return ptr;
-		}
-
-	}
-
-	DHD_PNO(("%s: pkt_count %d total_count %d\n", __FUNCTION__,
-	results->pkt_count, results->total_count));
-
-	for (i = 0; i < results->pkt_count; i++) {
-		DHD_PNO(("\t %02x:%02x:%02x:%02x:%02x:%02x\n",
-		results->list[i].BSSID.octet[0],
-		results->list[i].BSSID.octet[1],
-		results->list[i].BSSID.octet[2],
-		results->list[i].BSSID.octet[3],
-		results->list[i].BSSID.octet[4],
-		results->list[i].BSSID.octet[5]));
-	}
-
-	change_array = &params->change_array[params->results_rxed_so_far];
-	memcpy(change_array, results->list, sizeof(wl_pfn_significant_net_t) * results->pkt_count);
-	params->results_rxed_so_far += results->pkt_count;
-
-	if (params->results_rxed_so_far == results->total_count) {
-		params->results_rxed_so_far = 0;
-		*send_evt_bytes = sizeof(wl_pfn_significant_net_t) * results->total_count;
-		/* Pack up change buffer to send up and reset
-		 * results_rxed_so_far, after its done.
-		 */
-		ptr = (void *) params->change_array;
-		/* expecting the callee to free this mem chunk */
-		params->change_array = NULL;
-	}
-	 else {
-		*send_evt_bytes = 0;
-	}
-
-	return ptr;
-}
-
 void
 dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type)
 {
@@ -3697,7 +3930,9 @@
 
 	while (iter) {
 		tmp = iter->next;
-		kfree(iter);
+		MFREE(dhd->osh, iter,
+				((iter->tot_count - 1) * sizeof(wifi_gscan_result_t))
+				+ sizeof(gscan_results_cache_t));
 		iter = tmp;
 	}
 
@@ -3709,40 +3944,40 @@
 {
 	wl_bss_info_t *bi = NULL;
 	wl_gscan_result_t *gscan_result;
-	wifi_gscan_result_t *result = NULL;
+	wifi_gscan_full_result_t *result = NULL;
 	u32 bi_length = 0;
 	uint8 channel;
 	uint32 mem_needed;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
+	struct timespec64 ts;
+#else
 	struct timespec ts;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */
 	u32 bi_ie_length = 0;
 	u32 bi_ie_offset = 0;
 
 	*size = 0;
-
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 	gscan_result = (wl_gscan_result_t *)data;
-
+	GCC_DIAGNOSTIC_POP();
 	if (!gscan_result) {
 		DHD_ERROR(("Invalid gscan result (NULL pointer)\n"));
 		goto exit;
 	}
-	if (!gscan_result->bss_info) {
-		DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n"));
-		goto exit;
-	}
 
 	if ((len < sizeof(*gscan_result)) ||
-		(len < dtoh32(gscan_result->buflen)) ||
-		(dtoh32(gscan_result->buflen) >
-		 (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) {
+	    (len < dtoh32(gscan_result->buflen)) ||
+	    (dtoh32(gscan_result->buflen) >
+	    (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) {
 		DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__,
-					dtoh32(gscan_result->buflen)));
+			dtoh32(gscan_result->buflen)));
 		goto exit;
 	}
 
 	bi = &gscan_result->bss_info[0].info;
 	bi_length = dtoh32(bi->length);
 	if (bi_length != (dtoh32(gscan_result->buflen) -
-		WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) {
+	       WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) {
 		DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length));
 		goto exit;
 	}
@@ -3758,31 +3993,31 @@
 		goto exit;
 	}
 
-	mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi_ie_length;
-	result = kmalloc(mem_needed, GFP_KERNEL);
-
+	mem_needed = OFFSETOF(wifi_gscan_full_result_t, ie_data) + bi->ie_length;
+	result = (wifi_gscan_full_result_t *)MALLOC(dhd->osh, mem_needed);
 	if (!result) {
 		DHD_ERROR(("%s Cannot malloc scan result buffer %d bytes\n",
-		 __FUNCTION__, mem_needed));
+		  __FUNCTION__, mem_needed));
 		goto exit;
 	}
 
-	memcpy(result->ssid, bi->SSID, bi->SSID_len);
-	result->ssid[bi->SSID_len] = '\0';
+	result->scan_ch_bucket = gscan_result->scan_ch_bucket;
+	memcpy(result->fixed.ssid, bi->SSID, bi->SSID_len);
+	result->fixed.ssid[bi->SSID_len] = '\0';
 	channel = wf_chspec_ctlchan(bi->chanspec);
-	result->channel = wf_channel2mhz(channel,
+	result->fixed.channel = wf_channel2mhz(channel,
 		(channel <= CH_MAX_2G_CHANNEL?
 		WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
-	result->rssi = (int32) bi->RSSI;
-	result->rtt = 0;
-	result->rtt_sd = 0;
+	result->fixed.rssi = (int32) bi->RSSI;
+	result->fixed.rtt = 0;
+	result->fixed.rtt_sd = 0;
 	get_monotonic_boottime(&ts);
-	result->ts = (uint64) TIMESPEC_TO_US(ts);
-	result->beacon_period = dtoh16(bi->beacon_period);
-	result->capability = dtoh16(bi->capability);
+	result->fixed.ts = (uint64) TIMESPEC_TO_US(ts);
+	result->fixed.beacon_period = dtoh16(bi->beacon_period);
+	result->fixed.capability = dtoh16(bi->capability);
 	result->ie_length = bi_ie_length;
-	memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN);
-	memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi->ie_length);
+	memcpy(&result->fixed.macaddr, &bi->BSSID, ETHER_ADDR_LEN);
+	memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length);
 	*size = mem_needed;
 exit:
 	return result;
@@ -3803,87 +4038,96 @@
 		return NULL;
 	gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
 
-	if (event == WLC_E_PFN_SSID_EXT) {
-		wl_pfn_ssid_ext_result_t *evt_data;
-		evt_data = (wl_pfn_ssid_ext_result_t *) data;
+	if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) {
+		wl_pfn_scanresults_v1_t *pfn_result = (wl_pfn_scanresults_v1_t *)data;
+		wl_pfn_scanresults_v2_t *pfn_result_v2 = (wl_pfn_scanresults_v2_t *)data;
+		wl_pfn_net_info_v1_t *net;
+		wl_pfn_net_info_v2_t *net_v2;
 
-		if (evt_data->version != PFN_SSID_EXT_VERSION) {
-			DHD_PNO(("ePNO event: Incorrect version %d %d\n", evt_data->version,
-			     PFN_SSID_EXT_VERSION));
+		if (pfn_result->version == PFN_SCANRESULT_VERSION_V1) {
+			if ((pfn_result->count == 0) || (pfn_result->count > EVENT_MAX_NETCNT_V1)) {
+				DHD_ERROR(("%s event %d: wrong pfn v1 results count %d\n",
+						__FUNCTION__, event, pfn_result->count));
+				return NULL;
+			}
+			count = pfn_result->count;
+			mem_needed = sizeof(dhd_epno_results_t) * count;
+			results = (dhd_epno_results_t *)MALLOC(dhd->osh, mem_needed);
+			if (!results) {
+				DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__,
+					mem_needed));
+				return NULL;
+			}
+			for (i = 0; i < count; i++) {
+				net = &pfn_result->netinfo[i];
+				results[i].rssi = net->RSSI;
+				results[i].channel =  wf_channel2mhz(net->pfnsubnet.channel,
+					(net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ?
+					WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
+				results[i].flags = (event == WLC_E_PFN_NET_FOUND) ?
+					WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST;
+				results[i].ssid_len = min(net->pfnsubnet.SSID_len,
+					(uint8)DOT11_MAX_SSID_LEN);
+				bssid = &results[i].bssid;
+				memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN);
+				if (!net->pfnsubnet.SSID_len) {
+					DHD_ERROR(("%s: Gscan results indexing is not"
+						" supported in version 1 \n", __FUNCTION__));
+					MFREE(dhd->osh, results, mem_needed);
+					return NULL;
+				} else {
+					memcpy(results[i].ssid,	net->pfnsubnet.SSID,
+						results[i].ssid_len);
+				}
+				memcpy(ssid, results[i].ssid, results[i].ssid_len);
+				ssid[results[i].ssid_len] = '\0';
+				DHD_PNO(("ssid - %s bssid "MACDBG" ch %d rssi %d flags %d\n",
+					ssid, MAC2STRDBG(bssid->octet), results[i].channel,
+					results[i].rssi, results[i].flags));
+			}
+		} else if (pfn_result_v2->version == PFN_SCANRESULT_VERSION_V2) {
+			if ((pfn_result->count == 0) || (pfn_result->count > EVENT_MAX_NETCNT_V2)) {
+				DHD_ERROR(("%s event %d: wrong pfn v2 results count %d\n",
+						__FUNCTION__, event, pfn_result->count));
+				return NULL;
+			}
+			count = pfn_result_v2->count;
+			mem_needed = sizeof(dhd_epno_results_t) * count;
+			results = (dhd_epno_results_t *)MALLOC(dhd->osh, mem_needed);
+			if (!results) {
+				DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__,
+					mem_needed));
+				return NULL;
+			}
+			for (i = 0; i < count; i++) {
+				net_v2 = &pfn_result_v2->netinfo[i];
+				results[i].rssi = net_v2->RSSI;
+				results[i].channel =  wf_channel2mhz(net_v2->pfnsubnet.channel,
+					(net_v2->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ?
+					WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
+				results[i].flags = (event == WLC_E_PFN_NET_FOUND) ?
+					WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST;
+				results[i].ssid_len = min(net_v2->pfnsubnet.SSID_len,
+					(uint8)DOT11_MAX_SSID_LEN);
+				bssid = &results[i].bssid;
+				memcpy(bssid, &net_v2->pfnsubnet.BSSID, ETHER_ADDR_LEN);
+				if (!net_v2->pfnsubnet.SSID_len) {
+					dhd_pno_idx_to_ssid(gscan_params, &results[i],
+						net_v2->pfnsubnet.u.index);
+				} else {
+					memcpy(results[i].ssid,	net_v2->pfnsubnet.u.SSID,
+						results[i].ssid_len);
+				}
+				memcpy(ssid, results[i].ssid, results[i].ssid_len);
+				ssid[results[i].ssid_len] = '\0';
+				DHD_PNO(("ssid - %s bssid "MACDBG" ch %d rssi %d flags %d\n",
+					ssid, MAC2STRDBG(bssid->octet),	results[i].channel,
+					results[i].rssi, results[i].flags));
+			}
+		} else {
+			DHD_ERROR(("%s event %d: Incorrect version %d , not supported\n",
+				__FUNCTION__, event, pfn_result->version));
 			return NULL;
-		}
-		count = evt_data->count;
-		mem_needed = sizeof(dhd_epno_results_t) * count;
-		results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL);
-		if (!results) {
-			DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__,
-			        mem_needed));
-			return NULL;
-		}
-		DHD_ERROR(("Rx'ed WLC_E_PFN_SSID_EXT event: %d results\n", count));
-		for (i = 0; i < count; i++) {
-			results[i].rssi = evt_data->net[i].rssi;
-			results[i].channel = wf_channel2mhz(evt_data->net[i].channel,
-			                (evt_data->net[i].channel <= CH_MAX_2G_CHANNEL ?
-			                WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
-			results[i].flags = evt_data->net[i].flags;
-			dhd_pno_idx_to_ssid(gscan_params, &results[i],
-			           evt_data->net[i].index);
-			memcpy(ssid, results[i].ssid, results[i].ssid_len);
-			bssid = &results[i].bssid;
-			memcpy(bssid, &evt_data->net[i].bssid, ETHER_ADDR_LEN);
-			ssid[results[i].ssid_len] = '\0';
-			DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x "
-			        "idx %d ch %d rssi %d flags %d\n", ssid,
-			        bssid->octet[0], bssid->octet[1],
-			        bssid->octet[2], bssid->octet[3],
-			        bssid->octet[4], bssid->octet[5],
-			        evt_data->net[i].index, results[i].channel,
-			        results[i].rssi, results[i].flags));
-		}
-	} else if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) {
-		wl_pfn_scanresults_t *pfn_result = (wl_pfn_scanresults_t *)data;
-		wl_pfn_net_info_t *net;
-
-		if (pfn_result->version != PFN_SCANRESULT_VERSION) {
-			DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event,
-			          pfn_result->version, PFN_SCANRESULT_VERSION));
-			return NULL;
-		}
-		if ((pfn_result->count == 0) || (pfn_result->count > EVENT_MAX_NETCNT)) {
-			DHD_ERROR(("%s event %d: wrong pfn results count %d\n",
-				__FUNCTION__, event, pfn_result->count));
-			return NULL;
-		}
-		count = pfn_result->count;
-		mem_needed = sizeof(dhd_epno_results_t) * count;
-		results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL);
-		if (!results) {
-			DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__,
-			        mem_needed));
-			return NULL;
-		}
-		for (i = 0; i < count; i++) {
-			net = &pfn_result->netinfo[i];
-			results[i].rssi = net->RSSI;
-			results[i].channel =  wf_channel2mhz(net->pfnsubnet.channel,
-			                  (net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ?
-			                  WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
-			results[i].flags = (event == WLC_E_PFN_NET_FOUND) ?
-			               WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST;
-			results[i].ssid_len = min(net->pfnsubnet.SSID_len,
-			               (uint8)DOT11_MAX_SSID_LEN);
-			bssid = &results[i].bssid;
-			memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN);
-			memcpy(results[i].ssid, net->pfnsubnet.SSID, results[i].ssid_len);
-			memcpy(ssid, results[i].ssid, results[i].ssid_len);
-			ssid[results[i].ssid_len] = '\0';
-			DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x "
-			        "ch %d rssi %d flags %d\n", ssid,
-			        bssid->octet[0], bssid->octet[1],
-			        bssid->octet[2], bssid->octet[3],
-			        bssid->octet[4], bssid->octet[5],
-			        results[i].channel, results[i].rssi, results[i].flags));
 		}
 	}
 	*size = mem_needed;
@@ -3892,83 +4136,170 @@
 
 void *
 dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data,
-        int *send_evt_bytes, hotlist_type_t type)
+        int *send_evt_bytes, hotlist_type_t type, u32 *buf_len)
 {
 	void *ptr = NULL;
 	dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
 	struct dhd_pno_gscan_params *gscan_params;
-	wl_pfn_scanresults_t *results = (wl_pfn_scanresults_t *)event_data;
+	wl_pfn_scanresults_v1_t *results_v1 = (wl_pfn_scanresults_v1_t *)event_data;
+	wl_pfn_scanresults_v2_t *results_v2 = (wl_pfn_scanresults_v2_t *)event_data;
 	wifi_gscan_result_t *hotlist_found_array;
-	wl_pfn_net_info_t *plnetinfo;
+	wl_pfn_net_info_v1_t *pnetinfo;
+	wl_pfn_net_info_v2_t *pnetinfo_v2;
 	gscan_results_cache_t *gscan_hotlist_cache;
-	int malloc_size = 0, i, total = 0;
+	u32 malloc_size = 0, i, total = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
+	struct timespec64 tm_spec;
+#else
+	struct timespec tm_spec;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */
+	uint16 fwstatus;
+	uint16 fwcount;
 
-	gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
+	/* Static asserts in _dhd_pno_get_for_batch() above guarantee the v1 and v2
+	 * net_info and subnet_info structures are compatible in size and SSID offset,
+	 * allowing v1 to be safely used in the code below except for lscanresults
+	 * fields themselves (status, count, offset to netinfo).
+	 */
 
-	if ((results->count == 0) || (results->count > EVENT_MAX_NETCNT)) {
-		DHD_ERROR(("%s: wrong result count:%d\n", __FUNCTION__, results->count));
-		*send_evt_bytes = 0;
-		return ptr;
-	}
+	*buf_len = 0;
+	if (results_v1->version == PFN_SCANRESULTS_VERSION_V1) {
+		fwstatus = results_v1->status;
+		fwcount = results_v1->count;
+		pnetinfo = &results_v1->netinfo[0];
 
-	malloc_size = sizeof(gscan_results_cache_t) +
-	((results->count - 1) * sizeof(wifi_gscan_result_t));
-	gscan_hotlist_cache = (gscan_results_cache_t *) kmalloc(malloc_size, GFP_KERNEL);
+		gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
 
-	if (!gscan_hotlist_cache) {
-		DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size));
-		*send_evt_bytes = 0;
-		return ptr;
-	}
-
-	if (type == HOTLIST_FOUND) {
-		gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found;
-		gscan_params->gscan_hotlist_found = gscan_hotlist_cache;
-		DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, results->count));
-	} else {
-		gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost;
-		gscan_params->gscan_hotlist_lost = gscan_hotlist_cache;
-		DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, results->count));
-	}
-
-	gscan_hotlist_cache->tot_count = results->count;
-	gscan_hotlist_cache->tot_consumed = 0;
-	plnetinfo = results->netinfo;
-
-	for (i = 0; i < results->count; i++, plnetinfo++) {
-		hotlist_found_array = &gscan_hotlist_cache->results[i];
-		hotlist_found_array->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel,
-			(plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL?
-			WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
-		hotlist_found_array->rssi = (int32) plnetinfo->RSSI;
-		/* Info not available & not expected */
-		hotlist_found_array->beacon_period = 0;
-		hotlist_found_array->capability = 0;
-		hotlist_found_array->ie_length = 0;
-
-		hotlist_found_array->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp);
-		if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
-			DHD_ERROR(("Invalid SSID length %d: trimming it to max\n",
-			          plnetinfo->pfnsubnet.SSID_len));
-			plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
+		if (!fwcount || (fwcount > EVENT_MAX_NETCNT_V1)) {
+			DHD_ERROR(("%s: wrong v1 fwcount:%d\n", __FUNCTION__, fwcount));
+			*send_evt_bytes = 0;
+			return ptr;
 		}
-		memcpy(hotlist_found_array->ssid, plnetinfo->pfnsubnet.SSID,
-			plnetinfo->pfnsubnet.SSID_len);
-		hotlist_found_array->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0';
 
-		memcpy(&hotlist_found_array->macaddr, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN);
-	DHD_PNO(("\t%s %02x:%02x:%02x:%02x:%02x:%02x rssi %d\n", hotlist_found_array->ssid,
-		hotlist_found_array->macaddr.octet[0],
-		hotlist_found_array->macaddr.octet[1],
-		hotlist_found_array->macaddr.octet[2],
-		hotlist_found_array->macaddr.octet[3],
-		hotlist_found_array->macaddr.octet[4],
-		hotlist_found_array->macaddr.octet[5],
-		hotlist_found_array->rssi));
+		get_monotonic_boottime(&tm_spec);
+		malloc_size = sizeof(gscan_results_cache_t) +
+			((fwcount - 1) * sizeof(wifi_gscan_result_t));
+		gscan_hotlist_cache = (gscan_results_cache_t *)MALLOC(dhd->osh, malloc_size);
+		if (!gscan_hotlist_cache) {
+			DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size));
+			*send_evt_bytes = 0;
+			return ptr;
+		}
+
+		*buf_len = malloc_size;
+		if (type == HOTLIST_FOUND) {
+			gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found;
+			gscan_params->gscan_hotlist_found = gscan_hotlist_cache;
+			DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, fwcount));
+		} else {
+			gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost;
+			gscan_params->gscan_hotlist_lost = gscan_hotlist_cache;
+			DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, fwcount));
+		}
+
+		gscan_hotlist_cache->tot_count = fwcount;
+		gscan_hotlist_cache->tot_consumed = 0;
+
+		for (i = 0; i < fwcount; i++, pnetinfo++) {
+			hotlist_found_array = &gscan_hotlist_cache->results[i];
+			memset(hotlist_found_array, 0, sizeof(wifi_gscan_result_t));
+			hotlist_found_array->channel = wf_channel2mhz(pnetinfo->pfnsubnet.channel,
+				(pnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL?
+				WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
+			hotlist_found_array->rssi = (int32) pnetinfo->RSSI;
+
+			hotlist_found_array->ts =
+				convert_fw_rel_time_to_systime(&tm_spec,
+					(pnetinfo->timestamp * 1000));
+			if (pnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
+				DHD_ERROR(("Invalid SSID length %d: trimming it to max\n",
+					pnetinfo->pfnsubnet.SSID_len));
+				pnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
+			}
+			memcpy(hotlist_found_array->ssid, pnetinfo->pfnsubnet.SSID,
+				pnetinfo->pfnsubnet.SSID_len);
+			hotlist_found_array->ssid[pnetinfo->pfnsubnet.SSID_len] = '\0';
+
+			memcpy(&hotlist_found_array->macaddr, &pnetinfo->pfnsubnet.BSSID,
+				ETHER_ADDR_LEN);
+			DHD_PNO(("\t%s "MACDBG" rssi %d\n",
+				hotlist_found_array->ssid,
+				MAC2STRDBG(hotlist_found_array->macaddr.octet),
+				hotlist_found_array->rssi));
+		}
+	} else if (results_v2->version == PFN_SCANRESULTS_VERSION_V2) {
+		fwstatus = results_v2->status;
+		fwcount = results_v2->count;
+		pnetinfo_v2 = (wl_pfn_net_info_v2_t*)&results_v2->netinfo[0];
+
+		gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
+
+		if (!fwcount || (fwcount > EVENT_MAX_NETCNT_V2)) {
+			DHD_ERROR(("%s: wrong v2 fwcount:%d\n", __FUNCTION__, fwcount));
+			*send_evt_bytes = 0;
+			return ptr;
+		}
+
+		get_monotonic_boottime(&tm_spec);
+		malloc_size = sizeof(gscan_results_cache_t) +
+			((fwcount - 1) * sizeof(wifi_gscan_result_t));
+		gscan_hotlist_cache =
+			(gscan_results_cache_t *)MALLOC(dhd->osh, malloc_size);
+		if (!gscan_hotlist_cache) {
+			DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size));
+			*send_evt_bytes = 0;
+			return ptr;
+		}
+		*buf_len = malloc_size;
+		if (type == HOTLIST_FOUND) {
+			gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found;
+			gscan_params->gscan_hotlist_found = gscan_hotlist_cache;
+			DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, fwcount));
+		} else {
+			gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost;
+			gscan_params->gscan_hotlist_lost = gscan_hotlist_cache;
+			DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, fwcount));
+		}
+
+		gscan_hotlist_cache->tot_count = fwcount;
+		gscan_hotlist_cache->tot_consumed = 0;
+		gscan_hotlist_cache->scan_ch_bucket = results_v2->scan_ch_bucket;
+
+		for (i = 0; i < fwcount; i++, pnetinfo_v2++) {
+			hotlist_found_array = &gscan_hotlist_cache->results[i];
+			memset(hotlist_found_array, 0, sizeof(wifi_gscan_result_t));
+			hotlist_found_array->channel =
+				wf_channel2mhz(pnetinfo_v2->pfnsubnet.channel,
+				(pnetinfo_v2->pfnsubnet.channel <= CH_MAX_2G_CHANNEL?
+				WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
+			hotlist_found_array->rssi = (int32) pnetinfo_v2->RSSI;
+
+			hotlist_found_array->ts =
+				convert_fw_rel_time_to_systime(&tm_spec,
+				(pnetinfo_v2->timestamp * 1000));
+			if (pnetinfo_v2->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
+				DHD_ERROR(("Invalid SSID length %d: trimming it to max\n",
+					pnetinfo_v2->pfnsubnet.SSID_len));
+				pnetinfo_v2->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
+			}
+			memcpy(hotlist_found_array->ssid, pnetinfo_v2->pfnsubnet.u.SSID,
+				pnetinfo_v2->pfnsubnet.SSID_len);
+			hotlist_found_array->ssid[pnetinfo_v2->pfnsubnet.SSID_len] = '\0';
+
+			memcpy(&hotlist_found_array->macaddr, &pnetinfo_v2->pfnsubnet.BSSID,
+				ETHER_ADDR_LEN);
+			DHD_PNO(("\t%s "MACDBG" rssi %d\n",
+				hotlist_found_array->ssid,
+				MAC2STRDBG(hotlist_found_array->macaddr.octet),
+				hotlist_found_array->rssi));
+		}
+	} else {
+		DHD_ERROR(("%s: event version %d not supported\n",
+			__FUNCTION__, results_v1->version));
+		*send_evt_bytes = 0;
+		return ptr;
 	}
-
-
-	if (results->status == PFN_COMPLETE) {
+	if (fwstatus == PFN_COMPLETE) {
 		ptr = (void *) gscan_hotlist_cache;
 		while (gscan_hotlist_cache) {
 			total += gscan_hotlist_cache->tot_count;
@@ -3980,11 +4311,12 @@
 	return ptr;
 }
 #endif /* GSCAN_SUPPORT */
+
 int
 dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
 {
 	int err = BCME_OK;
-	uint status, event_type, flags, datalen;
+	uint event_type;
 	dhd_pno_status_info_t *_pno_state;
 	NULL_CHECK(dhd, "dhd is NULL", err);
 	NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
@@ -3995,9 +4327,6 @@
 		goto exit;
 	}
 	event_type = ntoh32(event->event_type);
-	flags = ntoh16(event->flags);
-	status = ntoh32(event->status);
-	datalen = ntoh32(event->datalen);
 	DHD_PNO(("%s enter : event_type :%d\n", __FUNCTION__, event_type));
 	switch (event_type) {
 	case WLC_E_PFN_BSSID_NET_FOUND:
@@ -4009,7 +4338,11 @@
 	{
 		struct dhd_pno_batch_params *params_batch;
 		params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
+		if (!swait_active(&_pno_state->get_batch_done.wait))
+#else
 		if (!waitqueue_active(&_pno_state->get_batch_done.wait)) {
+#endif/* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) */
 			DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__));
 			params_batch->get_batch.buf = NULL;
 			params_batch->get_batch.bufsize = 0;
@@ -4053,13 +4386,13 @@
 #ifdef GSCAN_SUPPORT
 	init_waitqueue_head(&_pno_state->batch_get_wait);
 #endif /* GSCAN_SUPPORT */
-	buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
+	buf = MALLOC(dhd->osh, WLC_IOCTL_SMLEN);
 	if (!buf) {
 		DHD_ERROR((":%s buf alloc err.\n", __FUNCTION__));
 		return BCME_NOMEM;
 	}
 	err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, buf, WLC_IOCTL_SMLEN,
-		FALSE);
+			FALSE);
 	if (err == BCME_UNSUPPORTED) {
 		_pno_state->wls_supported = FALSE;
 		DHD_INFO(("Current firmware doesn't support"
@@ -4069,10 +4402,9 @@
 			__FUNCTION__));
 	}
 exit:
-	kfree(buf);
+	MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN);
 	return err;
 }
-
 int dhd_pno_deinit(dhd_pub_t *dhd)
 {
 	int err = BCME_OK;
@@ -4093,7 +4425,7 @@
 	if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
 		_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
 		mutex_lock(&_pno_state->pno_mutex);
-		dhd_pno_reset_cfg_gscan(_params, _pno_state, GSCAN_FLUSH_ALL_CFG);
+		dhd_pno_reset_cfg_gscan(dhd, _params, _pno_state, GSCAN_FLUSH_ALL_CFG);
 		mutex_unlock(&_pno_state->pno_mutex);
 	}
 #endif /* GSCAN_SUPPORT */
@@ -4108,4 +4440,5 @@
 	dhd->pno_state = NULL;
 	return err;
 }
+#endif /* OEM_ANDROID */
 #endif /* PNO_SUPPORT */

--
Gitblit v1.6.2