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_rtt.c | 3028 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 2,501 insertions(+), 527 deletions(-)

diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_rtt.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_rtt.c
index 28717b5..ccb53b3 100644
--- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_rtt.c
+++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_rtt.c
@@ -1,15 +1,16 @@
-/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Broadcom Dongle Host Driver (DHD), RTT
  *
- * 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
@@ -17,12 +18,15 @@
  * 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.
  *
- * $Id: dhd_rtt.c 674349 2017-10-19 07:59:24Z $
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id$
  */
 #include <typedefs.h>
 #include <osl.h>
@@ -38,13 +42,24 @@
 #include <linux/sort.h>
 #include <dngl_stats.h>
 #include <wlioctl.h>
+#include <bcmwifi_rspec.h>
 
-#include <proto/bcmevent.h>
+#include <bcmevent.h>
 #include <dhd.h>
+#include <dhd_linux.h>
 #include <dhd_rtt.h>
 #include <dhd_dbg.h>
-#define GET_RTTSTATE(dhd) ((rtt_status_info_t *)dhd->rtt_state)
+#include <dhd_bus.h>
+#include <wldev_common.h>
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif /* WL_CFG80211 */
+#ifdef WL_NAN
+#include <wl_cfgnan.h>
+#endif /* WL_NAN */
+
 static DEFINE_SPINLOCK(noti_list_lock);
+#ifndef NULL_CHECK
 #define NULL_CHECK(p, s, err)  \
 			do { \
 				if (!(p)) { \
@@ -53,11 +68,15 @@
 					return err; \
 				} \
 			} while (0)
+#endif // endif
 
-#define RTT_IS_ENABLED(rtt_status) (rtt_status->status == RTT_ENABLED)
-#define RTT_IS_STOPPED(rtt_status) (rtt_status->status == RTT_STOPPED)
 #define TIMESPEC_TO_US(ts)  (((uint64)(ts).tv_sec * USEC_PER_SEC) + \
 							(ts).tv_nsec / NSEC_PER_USEC)
+
+#undef DHD_RTT_MEM
+#undef DHD_RTT_ERR
+#define DHD_RTT_MEM DHD_LOG_MEM
+#define DHD_RTT_ERR DHD_ERROR
 
 #define FTM_IOC_BUFSZ  2048	/* ioc buffsize for our module (> BCM_XTLV_HDR_SIZE) */
 #define FTM_AVAIL_MAX_SLOTS		32
@@ -66,9 +85,11 @@
 #define FTM_DEFAULT_SESSION 1
 #define FTM_BURST_TIMEOUT_UNIT 250 /* 250 ns */
 #define FTM_INVALID -1
-#define	FTM_DEFAULT_CNT_20M		12
-#define FTM_DEFAULT_CNT_40M		10
-#define FTM_DEFAULT_CNT_80M		5
+#define	FTM_DEFAULT_CNT_20M		24u
+#define FTM_DEFAULT_CNT_40M		16u
+#define FTM_DEFAULT_CNT_80M		11u
+/* To handle congestion env, set max dur/timeout */
+#define FTM_MAX_BURST_DUR_TMO_MS	128u
 
 /* convenience macros */
 #define FTM_TU2MICRO(_tu) ((uint64)(_tu) << 10)
@@ -84,6 +105,14 @@
 
 /* broadcom specific set to have more accurate data */
 #define ENABLE_VHT_ACK
+#define CH_MIN_5G_CHANNEL 34
+
+/* CUR ETH became obsolete with this major version onwards */
+#define RTT_IOV_CUR_ETH_OBSOLETE 12
+
+/* PROXD TIMEOUT */
+#define DHD_RTT_TIMER_INTERVAL_MS	5000u
+#define DHD_NAN_RTT_TIMER_INTERVAL_MS	10000u
 
 struct rtt_noti_callback {
 	struct list_head list;
@@ -91,30 +120,10 @@
 	dhd_rtt_compl_noti_fn noti_fn;
 };
 
-typedef struct rtt_status_info {
-	dhd_pub_t *dhd;
-	int8 status;   /* current status for the current entry */
-	int8 txchain; /* current device tx chain */
-	int8 mpc; /* indicate we change mpc mode */
-	int8 cur_idx; /* current entry to do RTT */
-	bool all_cancel; /* cancel all request once we got the cancel requet */
-	struct capability {
-		int32 proto	:8;
-		int32 feature	:8;
-		int32 preamble	:8;
-		int32 bw	:8;
-	} rtt_capa; /* rtt capability */
-	struct mutex rtt_mutex;
-	rtt_config_params_t rtt_config;
-	struct work_struct work;
-	struct list_head noti_fn_list;
-	struct list_head rtt_results_cache; /* store results for RTT */
-} rtt_status_info_t;
-
 /* bitmask indicating which command groups; */
 typedef enum {
 	FTM_SUBCMD_FLAG_METHOD	= 0x01,	/* FTM method command */
-	FTM_SUBCMD_FLAG_SESSION	= 0x02,	/* FTM session command */
+	FTM_SUBCMD_FLAG_SESSION = 0x02,	/* FTM session command */
 	FTM_SUBCMD_FLAG_ALL = FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION
 } ftm_subcmd_flag_t;
 
@@ -125,7 +134,6 @@
 	FTM_CONFIG_CAT_AVAIL = 3,	/* 'config avail' */
 } ftm_config_category_t;
 
-
 typedef struct ftm_subcmd_info {
 	int16				version;    /* FTM version (optional) */
 	char				*name;		/* cmd-name string as cmdline input */
@@ -134,9 +142,8 @@
 	ftm_subcmd_flag_t	cmdflag; /* CMD flag (optional)  */
 } ftm_subcmd_info_t;
 
-
 typedef struct ftm_config_options_info {
-	uint32 flags;		/* wl_proxd_flags_t/wl_proxd_session_flags_t */
+	uint32 flags;				/* wl_proxd_flags_t/wl_proxd_session_flags_t */
 	bool enable;
 } ftm_config_options_info_t;
 
@@ -149,157 +156,118 @@
 		uint32 data32;
 		uint16 data16;
 		uint8 data8;
+		uint32 event_mask;
 	};
 } ftm_config_param_info_t;
 
 /*
 * definition for id-string mapping.
-* This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string
-* for debug-display or cmd-log-display
+*   This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string
+*   for debug-display or cmd-log-display
 */
 typedef struct ftm_strmap_entry {
 	int32		id;
 	char		*text;
 } ftm_strmap_entry_t;
 
-
 typedef struct ftm_status_map_host_entry {
 	wl_proxd_status_t proxd_status;
 	rtt_reason_t rtt_reason;
 } ftm_status_map_host_entry_t;
 
+static uint16
+rtt_result_ver(uint16 tlvid, const uint8 *p_data);
+
 static int
-dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len);
+dhd_rtt_convert_results_to_host_v1(rtt_result_t *rtt_result, const uint8 *p_data,
+	uint16 tlvid, uint16 len);
+
+static int
+dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data,
+	uint16 tlvid, uint16 len);
 
 static wifi_rate_t
 dhd_rtt_convert_rate_to_host(uint32 ratespec);
 
+#if defined(WL_CFG80211) && defined(RTT_DEBUG)
+const char *
+ftm_cmdid_to_str(uint16 cmdid);
+#endif /* WL_CFG80211 && RTT_DEBUG */
+
+#ifdef WL_CFG80211
 static int
 dhd_rtt_start(dhd_pub_t *dhd);
+static int dhd_rtt_create_failure_result(rtt_status_info_t *rtt_status,
+	struct ether_addr *addr);
+static void dhd_rtt_handle_rtt_session_end(dhd_pub_t *dhd);
+static void dhd_rtt_timeout_work(struct work_struct *work);
+#endif /* WL_CFG80211 */
 static const int burst_duration_idx[]  = {0, 0, 1, 2, 4, 8, 16, 32, 64, 128, 0, 0};
 
 /* ftm status mapping to host status */
 static const ftm_status_map_host_entry_t ftm_status_map_info[] = {
-	{WL_PROXD_E_INCOMPLETE, RTT_REASON_FAILURE},
-	{WL_PROXD_E_OVERRIDDEN, RTT_REASON_FAILURE},
-	{WL_PROXD_E_ASAP_FAILED, RTT_REASON_FAILURE},
-	{WL_PROXD_E_NOTSTARTED, RTT_REASON_FAIL_NOT_SCHEDULED_YET},
-	{WL_PROXD_E_INVALIDAVB, RTT_REASON_FAIL_INVALID_TS},
-	{WL_PROXD_E_INCAPABLE, RTT_REASON_FAIL_NO_CAPABILITY},
-	{WL_PROXD_E_MISMATCH, RTT_REASON_FAILURE},
-	{WL_PROXD_E_DUP_SESSION, RTT_REASON_FAILURE},
-	{WL_PROXD_E_REMOTE_FAIL, RTT_REASON_FAILURE},
-	{WL_PROXD_E_REMOTE_INCAPABLE, RTT_REASON_FAILURE},
-	{WL_PROXD_E_SCHED_FAIL, RTT_REASON_FAIL_SCHEDULE},
-	{WL_PROXD_E_PROTO, RTT_REASON_FAIL_PROTOCOL},
-	{WL_PROXD_E_EXPIRED, RTT_REASON_FAILURE},
-	{WL_PROXD_E_TIMEOUT, RTT_REASON_FAIL_TM_TIMEOUT},
-	{WL_PROXD_E_NOACK, RTT_REASON_FAIL_NO_RSP},
-	{WL_PROXD_E_DEFERRED, RTT_REASON_FAILURE},
-	{WL_PROXD_E_INVALID_SID, RTT_REASON_FAILURE},
-	{WL_PROXD_E_REMOTE_CANCEL, RTT_REASON_FAILURE},
-	{WL_PROXD_E_CANCELED, RTT_REASON_ABORTED},
-	{WL_PROXD_E_INVALID_SESSION, RTT_REASON_FAILURE},
-	{WL_PROXD_E_BAD_STATE, RTT_REASON_FAILURE},
-	{WL_PROXD_E_ERROR, RTT_REASON_FAILURE},
-	{WL_PROXD_E_OK, RTT_REASON_SUCCESS}
-};
-
-/* ftm tlv-id mapping */
-static const ftm_strmap_entry_t ftm_tlvid_loginfo[] = {
-	/* { WL_PROXD_TLV_ID_xxx,				"text for WL_PROXD_TLV_ID_xxx" }, */
-	{ WL_PROXD_TLV_ID_NONE,					"none" },
-	{ WL_PROXD_TLV_ID_METHOD,				"method" },
-	{ WL_PROXD_TLV_ID_FLAGS,				"flags" },
-	{ WL_PROXD_TLV_ID_CHANSPEC,				"chanspec" },
-	{ WL_PROXD_TLV_ID_TX_POWER,				"tx power" },
-	{ WL_PROXD_TLV_ID_RATESPEC,				"ratespec" },
-	{ WL_PROXD_TLV_ID_BURST_DURATION,		"burst duration" },
-	{ WL_PROXD_TLV_ID_BURST_PERIOD,			"burst period" },
-	{ WL_PROXD_TLV_ID_BURST_FTM_SEP,		"burst ftm sep" },
-	{ WL_PROXD_TLV_ID_BURST_NUM_FTM,		"burst num ftm" },
-	{ WL_PROXD_TLV_ID_NUM_BURST,			"num burst" },
-	{ WL_PROXD_TLV_ID_FTM_RETRIES,			"ftm retries" },
-	{ WL_PROXD_TLV_ID_BSS_INDEX,			"BSS index" },
-	{ WL_PROXD_TLV_ID_BSSID,				"bssid" },
-	{ WL_PROXD_TLV_ID_INIT_DELAY,			"burst init delay" },
-	{ WL_PROXD_TLV_ID_BURST_TIMEOUT,		"burst timeout" },
-	{ WL_PROXD_TLV_ID_EVENT_MASK,			"event mask" },
-	{ WL_PROXD_TLV_ID_FLAGS_MASK,			"flags mask" },
-	{ WL_PROXD_TLV_ID_PEER_MAC,				"peer addr" },
-	{ WL_PROXD_TLV_ID_FTM_REQ,				"ftm req" },
-	{ WL_PROXD_TLV_ID_LCI_REQ,				"lci req" },
-	{ WL_PROXD_TLV_ID_LCI,					"lci" },
-	{ WL_PROXD_TLV_ID_CIVIC_REQ,			"civic req" },
-	{ WL_PROXD_TLV_ID_CIVIC,				"civic" },
-	{ WL_PROXD_TLV_ID_AVAIL,				"availability" },
-	{ WL_PROXD_TLV_ID_SESSION_FLAGS,		"session flags" },
-	{ WL_PROXD_TLV_ID_SESSION_FLAGS_MASK,	"session flags mask" },
-	{ WL_PROXD_TLV_ID_RX_MAX_BURST,			"rx max bursts" },
-	{ WL_PROXD_TLV_ID_RANGING_INFO,			"ranging info" },
-	{ WL_PROXD_TLV_ID_RANGING_FLAGS,		"ranging flags" },
-	{ WL_PROXD_TLV_ID_RANGING_FLAGS_MASK,	"ranging flags mask" },
-	/* output - 512 + x */
-	{ WL_PROXD_TLV_ID_STATUS,				"status" },
-	{ WL_PROXD_TLV_ID_COUNTERS,				"counters" },
-	{ WL_PROXD_TLV_ID_INFO,					"info" },
-	{ WL_PROXD_TLV_ID_RTT_RESULT,			"rtt result" },
-	{ WL_PROXD_TLV_ID_AOA_RESULT,			"aoa result" },
-	{ WL_PROXD_TLV_ID_SESSION_INFO,			"session info" },
-	{ WL_PROXD_TLV_ID_SESSION_STATUS,		"session status" },
-	{ WL_PROXD_TLV_ID_SESSION_ID_LIST,		"session ids" },
-	/* debug tlvs can be added starting 1024 */
-	{ WL_PROXD_TLV_ID_DEBUG_MASK,			"debug mask" },
-	{ WL_PROXD_TLV_ID_COLLECT,				"collect" },
-	{ WL_PROXD_TLV_ID_STRBUF,				"result" }
+	{WL_PROXD_E_INCOMPLETE, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_OVERRIDDEN, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_ASAP_FAILED, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_NOTSTARTED, RTT_STATUS_FAIL_NOT_SCHEDULED_YET},
+	{WL_PROXD_E_INVALIDMEAS, RTT_STATUS_FAIL_INVALID_TS},
+	{WL_PROXD_E_INCAPABLE, RTT_STATUS_FAIL_NO_CAPABILITY},
+	{WL_PROXD_E_MISMATCH, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_DUP_SESSION, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_REMOTE_FAIL, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_REMOTE_INCAPABLE, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_SCHED_FAIL, RTT_STATUS_FAIL_SCHEDULE},
+	{WL_PROXD_E_PROTO, RTT_STATUS_FAIL_PROTOCOL},
+	{WL_PROXD_E_EXPIRED, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_TIMEOUT, RTT_STATUS_FAIL_TM_TIMEOUT},
+	{WL_PROXD_E_NOACK, RTT_STATUS_FAIL_NO_RSP},
+	{WL_PROXD_E_DEFERRED, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_INVALID_SID, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_REMOTE_CANCEL, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_CANCELED, RTT_STATUS_ABORTED},
+	{WL_PROXD_E_INVALID_SESSION, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_BAD_STATE, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_ERROR, RTT_STATUS_FAILURE},
+	{WL_PROXD_E_OK, RTT_STATUS_SUCCESS}
 };
 
 static const ftm_strmap_entry_t ftm_event_type_loginfo[] = {
-	/* wl_proxd_event_type_t,			text-string */
-	{ WL_PROXD_EVENT_NONE,				"none" },
+	/* wl_proxd_event_type_t,		text-string */
+	{ WL_PROXD_EVENT_NONE,			"none" },
 	{ WL_PROXD_EVENT_SESSION_CREATE,	"session create" },
 	{ WL_PROXD_EVENT_SESSION_START,		"session start" },
-	{ WL_PROXD_EVENT_FTM_REQ,			"FTM req" },
+	{ WL_PROXD_EVENT_FTM_REQ,		"FTM req" },
 	{ WL_PROXD_EVENT_BURST_START,		"burst start" },
-	{ WL_PROXD_EVENT_BURST_END,			"burst end" },
+	{ WL_PROXD_EVENT_BURST_END,		"burst end" },
 	{ WL_PROXD_EVENT_SESSION_END,		"session end" },
 	{ WL_PROXD_EVENT_SESSION_RESTART,	"session restart" },
 	{ WL_PROXD_EVENT_BURST_RESCHED,		"burst rescheduled" },
 	{ WL_PROXD_EVENT_SESSION_DESTROY,	"session destroy" },
-	{ WL_PROXD_EVENT_RANGE_REQ,			"range request" },
-	{ WL_PROXD_EVENT_FTM_FRAME,			"FTM frame" },
-	{ WL_PROXD_EVENT_DELAY,				"delay" },
+	{ WL_PROXD_EVENT_RANGE_REQ,		"range request" },
+	{ WL_PROXD_EVENT_FTM_FRAME,		"FTM frame" },
+	{ WL_PROXD_EVENT_DELAY,			"delay" },
 	{ WL_PROXD_EVENT_VS_INITIATOR_RPT,	"initiator-report " }, /* rx initiator-rpt */
-	{ WL_PROXD_EVENT_RANGING,			"ranging " },
+	{ WL_PROXD_EVENT_RANGING,		"ranging " },
+	{ WL_PROXD_EVENT_COLLECT,		"collect" },
+	{ WL_PROXD_EVENT_MF_STATS,		"mf_stats" },
 };
 
 /*
 * session-state --> text string mapping
 */
 static const ftm_strmap_entry_t ftm_session_state_value_loginfo[] = {
-	/* wl_proxd_session_state_t,			text string */
-	{ WL_PROXD_SESSION_STATE_CREATED,		"created" },
+	/* wl_proxd_session_state_t,		text string */
+	{ WL_PROXD_SESSION_STATE_CREATED,	"created" },
 	{ WL_PROXD_SESSION_STATE_CONFIGURED,	"configured" },
-	{ WL_PROXD_SESSION_STATE_STARTED,		"started" },
-	{ WL_PROXD_SESSION_STATE_DELAY,			"delay" },
-	{ WL_PROXD_SESSION_STATE_USER_WAIT,		"user-wait" },
+	{ WL_PROXD_SESSION_STATE_STARTED,	"started" },
+	{ WL_PROXD_SESSION_STATE_DELAY,		"delay" },
+	{ WL_PROXD_SESSION_STATE_USER_WAIT,	"user-wait" },
 	{ WL_PROXD_SESSION_STATE_SCHED_WAIT,	"sched-wait" },
-	{ WL_PROXD_SESSION_STATE_BURST,			"burst" },
-	{ WL_PROXD_SESSION_STATE_STOPPING,		"stopping" },
-	{ WL_PROXD_SESSION_STATE_ENDED,			"ended" },
+	{ WL_PROXD_SESSION_STATE_BURST,		"burst" },
+	{ WL_PROXD_SESSION_STATE_STOPPING,	"stopping" },
+	{ WL_PROXD_SESSION_STATE_ENDED,		"ended" },
 	{ WL_PROXD_SESSION_STATE_DESTROYING,	"destroying" },
-	{ WL_PROXD_SESSION_STATE_NONE,			"none" }
-};
-
-/*
-* ranging-state --> text string mapping
-*/
-static const ftm_strmap_entry_t ftm_ranging_state_value_loginfo [] = {
-	/* wl_proxd_ranging_state_t,			text string */
-		{ WL_PROXD_RANGING_STATE_NONE, "none" },
-		{ WL_PROXD_RANGING_STATE_NOTSTARTED, "nonstarted" },
-		{ WL_PROXD_RANGING_STATE_INPROGRESS, "inprogress" },
-		{ WL_PROXD_RANGING_STATE_DONE, "done" },
+	{ WL_PROXD_SESSION_STATE_NONE,		"none" }
 };
 
 /*
@@ -310,61 +278,39 @@
 	{ WL_PROXD_E_OVERRIDDEN,		"overridden" },
 	{ WL_PROXD_E_ASAP_FAILED,		"ASAP failed" },
 	{ WL_PROXD_E_NOTSTARTED,		"not started" },
-	{ WL_PROXD_E_INVALIDAVB,		"invalid AVB" },
-	{ WL_PROXD_E_INCAPABLE,		"incapable" },
-	{ WL_PROXD_E_MISMATCH,		"mismatch"},
+	{ WL_PROXD_E_INVALIDMEAS,		"invalid measurement" },
+	{ WL_PROXD_E_INCAPABLE,			"incapable" },
+	{ WL_PROXD_E_MISMATCH,			"mismatch"},
 	{ WL_PROXD_E_DUP_SESSION,		"dup session" },
 	{ WL_PROXD_E_REMOTE_FAIL,		"remote fail" },
-	{ WL_PROXD_E_REMOTE_INCAPABLE,	"remote incapable" },
+	{ WL_PROXD_E_REMOTE_INCAPABLE,		"remote incapable" },
 	{ WL_PROXD_E_SCHED_FAIL,		"sched failure" },
 	{ WL_PROXD_E_PROTO,			"protocol error" },
 	{ WL_PROXD_E_EXPIRED,			"expired" },
 	{ WL_PROXD_E_TIMEOUT,			"timeout" },
 	{ WL_PROXD_E_NOACK,			"no ack" },
-	{ WL_PROXD_E_DEFERRED,		"deferred" },
+	{ WL_PROXD_E_DEFERRED,			"deferred" },
 	{ WL_PROXD_E_INVALID_SID,		"invalid session id" },
 	{ WL_PROXD_E_REMOTE_CANCEL,		"remote cancel" },
-	{ WL_PROXD_E_CANCELED,		"canceled" },
-	{ WL_PROXD_E_INVALID_SESSION,	"invalid session" },
-	{ WL_PROXD_E_BAD_STATE,		"bad state" },
+	{ WL_PROXD_E_CANCELED,			"canceled" },
+	{ WL_PROXD_E_INVALID_SESSION,		"invalid session" },
+	{ WL_PROXD_E_BAD_STATE,			"bad state" },
 	{ WL_PROXD_E_ERROR,			"error" },
-	{ WL_PROXD_E_OK,				"OK" }
+	{ WL_PROXD_E_OK,			"OK" }
 };
 
 /*
 * time interval unit --> text string mapping
 */
 static const ftm_strmap_entry_t ftm_tmu_value_loginfo[] = {
-	/* wl_proxd_tmu_t,			text-string */
-	{ WL_PROXD_TMU_TU,			"TU" },
-	{ WL_PROXD_TMU_SEC,			"sec" },
+	/* wl_proxd_tmu_t,		text-string */
+	{ WL_PROXD_TMU_TU,		"TU" },
+	{ WL_PROXD_TMU_SEC,		"sec" },
 	{ WL_PROXD_TMU_MILLI_SEC,	"ms" },
 	{ WL_PROXD_TMU_MICRO_SEC,	"us" },
 	{ WL_PROXD_TMU_NANO_SEC,	"ns" },
 	{ WL_PROXD_TMU_PICO_SEC,	"ps" }
 };
-
-#define RSPEC_BW(rspec)         ((rspec) & WL_RSPEC_BW_MASK)
-#define RSPEC_IS20MHZ(rspec)	(RSPEC_BW(rspec) == WL_RSPEC_BW_20MHZ)
-#define RSPEC_IS40MHZ(rspec)	(RSPEC_BW(rspec) == WL_RSPEC_BW_40MHZ)
-#define RSPEC_IS80MHZ(rspec)    (RSPEC_BW(rspec) == WL_RSPEC_BW_80MHZ)
-#define RSPEC_IS160MHZ(rspec)   (RSPEC_BW(rspec) == WL_RSPEC_BW_160MHZ)
-
-#define IS_MCS(rspec)     	(((rspec) & WL_RSPEC_ENCODING_MASK) != WL_RSPEC_ENCODE_RATE)
-#define IS_STBC(rspec)     	(((((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) ||	\
-	(((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)) &&	\
-	(((rspec) & WL_RSPEC_STBC) == WL_RSPEC_STBC))
-#define RSPEC_ISSGI(rspec)      (((rspec) & WL_RSPEC_SGI) != 0)
-#define RSPEC_ISLDPC(rspec)     (((rspec) & WL_RSPEC_LDPC) != 0)
-#define RSPEC_ISSTBC(rspec)     (((rspec) & WL_RSPEC_STBC) != 0)
-#define RSPEC_ISTXBF(rspec)     (((rspec) & WL_RSPEC_TXBF) != 0)
-#define RSPEC_ISVHT(rspec)    	(((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)
-#define RSPEC_ISHT(rspec)	(((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT)
-#define RSPEC_ISLEGACY(rspec)   (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE)
-#define RSPEC2RATE(rspec)	(RSPEC_ISLEGACY(rspec) ? \
-				 ((rspec) & RSPEC_RATE_MASK) : rate_rspec2rate(rspec))
-/* return rate in unit of 500Kbps -- for internal use in wlc_rate_sel.c */
-#define RSPEC2KBPS(rspec)	rate_rspec2rate(rspec)
 
 struct ieee_80211_mcs_rate_info {
 	uint8 constellation_bits;
@@ -449,10 +395,10 @@
 } /* wlc_rate_mcs2rate */
 
 /** take a well formed ratespec_t arg and return phy rate in [Kbps] units */
-int
+static uint32
 rate_rspec2rate(uint32 rspec)
 {
-	int rate = -1;
+	int rate = 0;
 
 	if (RSPEC_ISLEGACY(rspec)) {
 		rate = 500 * (rspec & WL_RSPEC_RATE_MASK);
@@ -469,16 +415,17 @@
 	} else if (RSPEC_ISVHT(rspec)) {
 		uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK);
 		uint nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
-
-		ASSERT(mcs <= 9);
-		ASSERT(nss <= 8);
+		if (mcs > 9 || nss > 8) {
+			DHD_RTT(("%s: Invalid mcs %d or nss %d\n", __FUNCTION__, mcs, nss));
+			goto exit;
+		}
 
 		rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec));
 	} else {
-		ASSERT(0);
+		DHD_RTT(("%s: wrong rspec:%d\n", __FUNCTION__, rspec));
 	}
-
-	return (rate == 0) ? -1 : rate;
+exit:
+	return rate;
 }
 
 char resp_buf[WLC_IOCTL_SMLEN];
@@ -536,7 +483,7 @@
 		}
 		p_entry++;		/* next entry */
 	}
-	return RTT_REASON_FAILURE; /* not found */
+	return RTT_STATUS_FAILURE; /* not found */
 }
 /*
 * lookup 'id' (as a key) from a table
@@ -578,9 +525,7 @@
 	return "invalid";
 }
 
-
-#ifdef RTT_DEBUG
-
+#if defined(WL_CFG80211) && defined(RTT_DEBUG)
 /* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */
 #define DEF_STRMAP_ENTRY(id) { (id), #id }
 
@@ -613,13 +558,12 @@
 /*
 * map a ftm cmd-id to a text-string for display
 */
-static const char *
+const char *
 ftm_cmdid_to_str(uint16 cmdid)
 {
 	return ftm_map_id_to_str((int32) cmdid, &ftm_cmdid_map[0], ARRAYSIZE(ftm_cmdid_map));
 }
-#endif /* RTT_DEBUG */
-
+#endif /* WL_CFG80211 && RTT_DEBUG */
 
 /*
 * convert BCME_xxx error codes into related error strings
@@ -674,7 +618,7 @@
 		ARRAYSIZE(ftm_session_state_value_loginfo));
 }
 
-
+#ifdef WL_CFG80211
 /*
 * send 'proxd' iovar for all ftm get-related commands
 */
@@ -690,7 +634,7 @@
 	status = dhd_getiovar(dhd, 0, "proxd", (char *)p_proxd_iov,
 			proxd_iovsize, (char **)&p_iovresp, WLC_IOCTL_SMLEN);
 	if (status != BCME_OK) {
-		DHD_ERROR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n",
+		DHD_RTT_ERR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n",
 			__FUNCTION__, p_subcmd_info->cmdid, status));
 		return status;
 	}
@@ -702,7 +646,7 @@
 
 	tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE;
 	if (tlvs_len < 0) {
-		DHD_ERROR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n",
+		DHD_RTT_ERR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n",
 			__FUNCTION__, ltoh16(p_iovresp->len), (int) WL_PROXD_IOV_HDR_SIZE));
 		tlvs_len = 0;
 	}
@@ -716,13 +660,12 @@
 	return status;
 }
 
-
 static wl_proxd_iov_t *
 rtt_alloc_getset_buf(wl_proxd_method_t method, wl_proxd_session_id_t session_id,
 	wl_proxd_cmd_t cmdid, uint16 tlvs_bufsize, uint16 *p_out_bufsize)
 {
 	uint16 proxd_iovsize;
-	uint16 kflags;
+	uint32 kflags;
 	wl_proxd_tlv_t *p_tlv;
 	wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) NULL;
 
@@ -733,7 +676,7 @@
 
 	p_proxd_iov = kzalloc(proxd_iovsize, kflags);
 	if (p_proxd_iov == NULL) {
-		DHD_ERROR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize));
+		DHD_RTT_ERR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize));
 		return NULL;
 	}
 
@@ -754,7 +697,6 @@
 	return p_proxd_iov;
 }
 
-
 static int
 dhd_rtt_common_get_handler(dhd_pub_t *dhd, ftm_subcmd_info_t *p_subcmd_info,
 		wl_proxd_method_t method,
@@ -767,7 +709,7 @@
 	DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
 		__FUNCTION__, method, session_id, p_subcmd_info->cmdid,
 		ftm_cmdid_to_str(p_subcmd_info->cmdid)));
-#endif
+#endif // endif
 	/* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */
 	p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid,
 		0, &proxd_iovsize);
@@ -809,10 +751,11 @@
 	int ret;
 
 #ifdef RTT_DEBUG
-	DHD_ERROR(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
+	DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
 		__FUNCTION__, method, session_id, p_subcmd_info->cmdid,
 		ftm_cmdid_to_str(p_subcmd_info->cmdid)));
-#endif
+#endif // endif
+
 	/* allocate and initialize a temp buffer for 'set proxd' iovar */
 	proxd_iovsize = 0;
 	p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid,
@@ -824,38 +767,269 @@
 	ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, proxd_iovsize, NULL, 0, TRUE);
 #ifdef RTT_DEBUG
 	if (ret != BCME_OK) {
-		DHD_ERROR(("error: Proxd IOVAR failed, status=%d\n", ret));
+		DHD_RTT(("error: IOVAR failed, status=%d\n", ret));
 	}
-#endif
+#endif // endif
 	/* clean up */
 	kfree(p_proxd_iov);
+
+	return ret;
+}
+#endif /* WL_CFG80211 */
+
+/* gets the length and returns the version
+ * of the wl_proxd_collect_event_t version
+ */
+static uint
+rtt_collect_data_event_ver(uint16 len)
+{
+	if (len > sizeof(wl_proxd_collect_event_data_v3_t)) {
+		return WL_PROXD_COLLECT_EVENT_DATA_VERSION_MAX;
+	} else if (len == sizeof(wl_proxd_collect_event_data_v3_t)) {
+		return WL_PROXD_COLLECT_EVENT_DATA_VERSION_3;
+	} else if (len == sizeof(wl_proxd_collect_event_data_v2_t)) {
+		return WL_PROXD_COLLECT_EVENT_DATA_VERSION_2;
+	} else {
+		return WL_PROXD_COLLECT_EVENT_DATA_VERSION_1;
+	}
+}
+
+static void
+rtt_collect_event_data_display(uint8 ver, void *ctx, const uint8 *p_data, uint16 len)
+{
+	int i;
+	wl_proxd_collect_event_data_v1_t *p_collect_data_v1 = NULL;
+	wl_proxd_collect_event_data_v2_t *p_collect_data_v2 = NULL;
+	wl_proxd_collect_event_data_v3_t *p_collect_data_v3 = NULL;
+
+	if (!ctx || !p_data) {
+		return;
+	}
+
+	switch (ver) {
+	case WL_PROXD_COLLECT_EVENT_DATA_VERSION_1:
+		DHD_RTT(("\tVERSION_1\n"));
+		memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v1_t));
+		p_collect_data_v1 = (wl_proxd_collect_event_data_v1_t *)ctx;
+		DHD_RTT(("\tH_RX\n"));
+		for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
+			p_collect_data_v1->H_RX[i] = ltoh32_ua(&p_collect_data_v1->H_RX[i]);
+			DHD_RTT(("\t%u\n", p_collect_data_v1->H_RX[i]));
+		}
+		DHD_RTT(("\n"));
+		DHD_RTT(("\tH_LB\n"));
+		for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
+			p_collect_data_v1->H_LB[i] = ltoh32_ua(&p_collect_data_v1->H_LB[i]);
+			DHD_RTT(("\t%u\n", p_collect_data_v1->H_LB[i]));
+		}
+		DHD_RTT(("\n"));
+		DHD_RTT(("\tri_rr\n"));
+		for (i = 0; i < FTM_TPK_RI_RR_LEN; i++) {
+			DHD_RTT(("\t%u\n", p_collect_data_v1->ri_rr[i]));
+		}
+		p_collect_data_v1->phy_err_mask = ltoh32_ua(&p_collect_data_v1->phy_err_mask);
+		DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data_v1->phy_err_mask));
+		break;
+	case WL_PROXD_COLLECT_EVENT_DATA_VERSION_2:
+		memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v2_t));
+		p_collect_data_v2 = (wl_proxd_collect_event_data_v2_t *)ctx;
+		DHD_RTT(("\tH_RX\n"));
+		for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
+			p_collect_data_v2->H_RX[i] = ltoh32_ua(&p_collect_data_v2->H_RX[i]);
+			DHD_RTT(("\t%u\n", p_collect_data_v2->H_RX[i]));
+		}
+		DHD_RTT(("\n"));
+		DHD_RTT(("\tH_LB\n"));
+		for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
+			p_collect_data_v2->H_LB[i] = ltoh32_ua(&p_collect_data_v2->H_LB[i]);
+			DHD_RTT(("\t%u\n", p_collect_data_v2->H_LB[i]));
+		}
+		DHD_RTT(("\n"));
+		DHD_RTT(("\tri_rr\n"));
+		for (i = 0; i < FTM_TPK_RI_RR_LEN_SECURE_2_0; i++) {
+			DHD_RTT(("\t%u\n", p_collect_data_v2->ri_rr[i]));
+		}
+		p_collect_data_v2->phy_err_mask = ltoh32_ua(&p_collect_data_v2->phy_err_mask);
+		DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data_v2->phy_err_mask));
+		break;
+	case WL_PROXD_COLLECT_EVENT_DATA_VERSION_3:
+		memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v3_t));
+		p_collect_data_v3 = (wl_proxd_collect_event_data_v3_t *)ctx;
+		switch (p_collect_data_v3->version) {
+		case WL_PROXD_COLLECT_EVENT_DATA_VERSION_3:
+			if (p_collect_data_v3->length !=
+				(len - OFFSETOF(wl_proxd_collect_event_data_v3_t, H_LB))) {
+				DHD_RTT(("\tversion/length mismatch\n"));
+				break;
+			}
+			DHD_RTT(("\tH_RX\n"));
+			for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
+				p_collect_data_v3->H_RX[i] =
+					ltoh32_ua(&p_collect_data_v3->H_RX[i]);
+				DHD_RTT(("\t%u\n", p_collect_data_v3->H_RX[i]));
+			}
+			DHD_RTT(("\n"));
+			DHD_RTT(("\tH_LB\n"));
+			for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
+				p_collect_data_v3->H_LB[i] =
+					ltoh32_ua(&p_collect_data_v3->H_LB[i]);
+				DHD_RTT(("\t%u\n", p_collect_data_v3->H_LB[i]));
+			}
+			DHD_RTT(("\n"));
+			DHD_RTT(("\tri_rr\n"));
+			for (i = 0; i < FTM_TPK_RI_RR_LEN_SECURE_2_0; i++) {
+				DHD_RTT(("\t%u\n", p_collect_data_v3->ri_rr[i]));
+			}
+			p_collect_data_v3->phy_err_mask =
+				ltoh32_ua(&p_collect_data_v3->phy_err_mask);
+			DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data_v3->phy_err_mask));
+			break;
+		/* future case */
+		}
+		break;
+	}
+}
+
+static uint16
+rtt_result_ver(uint16 tlvid, const uint8 *p_data)
+{
+	uint16 ret = BCME_OK;
+	const wl_proxd_rtt_result_v2_t *r_v2 = NULL;
+
+	switch (tlvid) {
+	case WL_PROXD_TLV_ID_RTT_RESULT:
+		BCM_REFERENCE(p_data);
+		ret = WL_PROXD_RTT_RESULT_VERSION_1;
+		break;
+	case WL_PROXD_TLV_ID_RTT_RESULT_V2:
+		if (p_data) {
+			r_v2 = (const wl_proxd_rtt_result_v2_t *)p_data;
+			if (r_v2->version == WL_PROXD_RTT_RESULT_VERSION_2) {
+				ret = WL_PROXD_RTT_RESULT_VERSION_2;
+			}
+		}
+		break;
+	default:
+		DHD_RTT_ERR(("%s: > Unsupported TLV ID %d\n",
+			__FUNCTION__, tlvid));
+		break;
+	}
 	return ret;
 }
 
+/* pretty hex print a contiguous buffer */
+static void
+rtt_prhex(const char *msg, const uint8 *buf, uint nbytes)
+{
+	char line[128], *p;
+	int len = sizeof(line);
+	int nchar;
+	uint i;
+
+	if (msg && (msg[0] != '\0'))
+		DHD_RTT(("%s:\n", msg));
+
+	p = line;
+	for (i = 0; i < nbytes; i++) {
+		if (i % 16 == 0) {
+			nchar = snprintf(p, len, "  %04d: ", i);	/* line prefix */
+			p += nchar;
+			len -= nchar;
+		}
+		if (len > 0) {
+			nchar = snprintf(p, len, "%02x ", buf[i]);
+			p += nchar;
+			len -= nchar;
+		}
+
+		if (i % 16 == 15) {
+			DHD_RTT(("%s\n", line));	/* flush line */
+			p = line;
+			len = sizeof(line);
+		}
+	}
+
+	/* flush last partial line */
+	if (p != line)
+		DHD_RTT(("%s\n", line));
+}
+
 static int
-rtt_unpack_xtlv_cbfn(void *ctx, uint8 *p_data, uint16 tlvid, uint16 len)
+rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len)
 {
 	int ret = BCME_OK;
-	wl_proxd_ftm_session_status_t *p_data_info;
+	int i;
+	wl_proxd_ftm_session_status_t *p_data_info = NULL;
+	uint32 chan_data_entry = 0;
+	uint16 expected_rtt_result_ver = 0;
+
+	BCM_REFERENCE(p_data_info);
+
 	switch (tlvid) {
 	case WL_PROXD_TLV_ID_RTT_RESULT:
-		ret = dhd_rtt_convert_results_to_host((rtt_report_t *)ctx,
-				p_data, tlvid, len);
+	case WL_PROXD_TLV_ID_RTT_RESULT_V2:
+		DHD_RTT(("WL_PROXD_TLV_ID_RTT_RESULT\n"));
+		expected_rtt_result_ver = rtt_result_ver(tlvid, p_data);
+		switch (expected_rtt_result_ver) {
+		case WL_PROXD_RTT_RESULT_VERSION_1:
+			ret = dhd_rtt_convert_results_to_host_v1((rtt_result_t *)ctx,
+					p_data, tlvid, len);
+			break;
+		case WL_PROXD_RTT_RESULT_VERSION_2:
+			ret = dhd_rtt_convert_results_to_host_v2((rtt_result_t *)ctx,
+					p_data, tlvid, len);
+			break;
+		default:
+			DHD_RTT_ERR((" > Unsupported RTT_RESULT version\n"));
+			ret = BCME_UNSUPPORTED;
+			break;
+		}
 		break;
 	case WL_PROXD_TLV_ID_SESSION_STATUS:
+		DHD_RTT(("WL_PROXD_TLV_ID_SESSION_STATUS\n"));
 		memcpy(ctx, p_data, sizeof(wl_proxd_ftm_session_status_t));
 		p_data_info = (wl_proxd_ftm_session_status_t *)ctx;
+		p_data_info->sid = ltoh16_ua(&p_data_info->sid);
 		p_data_info->state = ltoh16_ua(&p_data_info->state);
 		p_data_info->status = ltoh32_ua(&p_data_info->status);
+		p_data_info->burst_num = ltoh16_ua(&p_data_info->burst_num);
+		DHD_RTT(("\tsid=%u, state=%d, status=%d, burst_num=%u\n",
+			p_data_info->sid, p_data_info->state,
+			p_data_info->status, p_data_info->burst_num));
+
+		break;
+	case WL_PROXD_TLV_ID_COLLECT_DATA:
+		DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_DATA\n"));
+		rtt_collect_event_data_display(
+			rtt_collect_data_event_ver(len),
+			ctx, p_data, len);
+		break;
+	case WL_PROXD_TLV_ID_COLLECT_CHAN_DATA:
+		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+		DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_CHAN_DATA\n"));
+		DHD_RTT(("\tchan est %u\n", (uint32) (len / sizeof(uint32))));
+		for (i = 0; i < (len/sizeof(chan_data_entry)); i++) {
+			uint32 *p = (uint32*)p_data;
+			chan_data_entry = ltoh32_ua(p + i);
+			DHD_RTT(("\t%u\n", chan_data_entry));
+		}
+		GCC_DIAGNOSTIC_POP();
+		break;
+	case WL_PROXD_TLV_ID_MF_STATS_DATA:
+		DHD_RTT(("WL_PROXD_TLV_ID_MF_STATS_DATA\n"));
+		DHD_RTT(("\tmf stats len=%u\n", len));
+		rtt_prhex("", p_data, len);
 		break;
 	default:
-		DHD_ERROR(("> Unsupported TLV ID %d\n", tlvid));
+		DHD_RTT_ERR(("> Unsupported TLV ID %d\n", tlvid));
 		ret = BCME_ERROR;
 		break;
 	}
 
 	return ret;
 }
+
+#ifdef WL_CFG80211
 static int
 rtt_handle_config_options(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv,
 	uint16 *p_buf_space_left, ftm_config_options_info_t *ftm_configs, int ftm_cfg_cnt)
@@ -885,9 +1059,9 @@
 	flags_mask = htol32(flags_mask);
 	/* setup flags_mask TLV */
 	ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left,
-		type, sizeof(uint32), &flags_mask, BCM_XTLV_OPTION_ALIGN32);
+		type, sizeof(uint32), (uint8 *)&flags_mask, BCM_XTLV_OPTION_ALIGN32);
 	if (ret != BCME_OK) {
-		DHD_ERROR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n",
+		DHD_RTT_ERR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n",
 			__FUNCTION__, ret));
 		goto exit;
 	}
@@ -896,12 +1070,12 @@
 		WL_PROXD_TLV_ID_FLAGS : WL_PROXD_TLV_ID_SESSION_FLAGS;
 	/* setup flags TLV */
 	ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left,
-			type, sizeof(uint32), &flags, BCM_XTLV_OPTION_ALIGN32);
+			type, sizeof(uint32), (uint8 *)&flags, BCM_XTLV_OPTION_ALIGN32);
 		if (ret != BCME_OK) {
-//#ifdef RTT_DEBUG
+#ifdef RTT_DEBUG
 			DHD_RTT(("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n",
 				__FUNCTION__, ret));
-//#endif
+#endif // endif
 		}
 exit:
 	return ret;
@@ -947,6 +1121,7 @@
 				break;
 			case WL_PROXD_TLV_ID_BSSID: /* mac address */
 			case WL_PROXD_TLV_ID_PEER_MAC:
+			case WL_PROXD_TLV_ID_CUR_ETHER_ADDR:
 				p_src_data = &p_config_param_info->mac_addr;
 				src_data_size = sizeof(struct ether_addr);
 				break;
@@ -963,36 +1138,22 @@
 				break;
 			}
 			if (ret != BCME_OK) {
-				DHD_ERROR(("%s bad TLV ID : %d\n",
+				DHD_RTT_ERR(("%s bad TLV ID : %d\n",
 					__FUNCTION__, p_config_param_info->tlvid));
 				break;
 			}
 
 			ret = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left,
-				p_config_param_info->tlvid, src_data_size, p_src_data,
+				p_config_param_info->tlvid, src_data_size, (uint8 *)p_src_data,
 				BCM_XTLV_OPTION_ALIGN32);
 			if (ret != BCME_OK) {
-				DHD_ERROR(("%s: bcm_pack_xltv_entry() failed,"
+				DHD_RTT_ERR(("%s: bcm_pack_xltv_entry() failed,"
 					" status=%d\n", __FUNCTION__, ret));
 				break;
 			}
 
 		}
 	}
-	return ret;
-}
-
-static int
-dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version)
-{
-	int ret;
-	ftm_subcmd_info_t subcmd_info;
-	subcmd_info.name = "ver";
-	subcmd_info.cmdid = WL_PROXD_CMD_GET_VERSION;
-	subcmd_info.handler = NULL;
-	ret = dhd_rtt_common_get_handler(dhd, &subcmd_info,
-			WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL);
-	*out_version = (ret == BCME_OK) ? subcmd_info.version : 0;
 	return ret;
 }
 
@@ -1028,6 +1189,119 @@
 	return dhd_rtt_common_set_handler(dhd, &subcmd_info,
 			WL_PROXD_METHOD_FTM, session_id);
 }
+#ifdef WL_NAN
+int
+dhd_rtt_delete_nan_session(dhd_pub_t *dhd)
+{
+	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
+	struct wireless_dev *wdev = ndev_to_wdev(dev);
+	struct wiphy *wiphy = wdev->wiphy;
+	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+	wl_cfgnan_terminate_directed_rtt_sessions(dev, cfg);
+	return BCME_OK;
+}
+#endif /* WL_NAN */
+/* API to find out if the given Peer Mac from FTM events
+* is nan-peer. Based on this we will handle the SESSION_END
+* event. For nan-peer FTM_SESSION_END event is ignored and handled in
+* nan-ranging-cancel or nan-ranging-end event.
+*/
+static bool
+dhd_rtt_is_nan_peer(dhd_pub_t *dhd, struct ether_addr *peer_mac)
+{
+#ifdef WL_NAN
+	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
+	struct wireless_dev *wdev = ndev_to_wdev(dev);
+	struct wiphy *wiphy = wdev->wiphy;
+	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+	nan_ranging_inst_t *ranging_inst = NULL;
+	bool ret = FALSE;
+
+	if (cfg->nan_enable == FALSE || ETHER_ISNULLADDR(peer_mac)) {
+		goto exit;
+	}
+
+	ranging_inst = wl_cfgnan_check_for_ranging(cfg, peer_mac);
+	if (ranging_inst) {
+		DHD_RTT((" RTT peer is of type NAN\n"));
+		ret = TRUE;
+		goto exit;
+	}
+exit:
+	return ret;
+#else
+	return FALSE;
+#endif /* WL_NAN */
+}
+
+#ifdef WL_NAN
+static int
+dhd_rtt_nan_start_session(dhd_pub_t *dhd, rtt_target_info_t *rtt_target)
+{
+	s32 err = BCME_OK;
+	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
+	struct wireless_dev *wdev = ndev_to_wdev(dev);
+	struct wiphy *wiphy = wdev->wiphy;
+	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+	wl_nan_ev_rng_rpt_ind_t range_res;
+	nan_ranging_inst_t *ranging_inst = NULL;
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+
+	NAN_MUTEX_LOCK();
+
+	bzero(&range_res, sizeof(range_res));
+
+	if (!rtt_status) {
+		err = BCME_NOTENABLED;
+		goto done;
+	}
+
+	if (!cfg->nan_enable) { /* If nan is not enabled report error */
+		err = BCME_NOTENABLED;
+		goto done;
+	}
+
+	/* check if new ranging session allowed */
+	if (!wl_cfgnan_ranging_allowed(cfg)) {
+		/* responder should be in progress because initiator requests are
+		* queued in DHD. Since initiator has more proef cancel responder
+		* sessions
+		*/
+		wl_cfgnan_cancel_rng_responders(dev, cfg);
+	}
+
+	ranging_inst = wl_cfgnan_get_ranging_inst(cfg,
+			&rtt_target->addr, NAN_RANGING_ROLE_INITIATOR);
+	if (!ranging_inst) {
+		err = BCME_NORESOURCE;
+		goto done;
+	}
+
+	DHD_RTT(("Trigger nan based range request\n"));
+	err = wl_cfgnan_trigger_ranging(bcmcfg_to_prmry_ndev(cfg),
+			cfg, ranging_inst, NULL, NAN_RANGE_REQ_CMD, TRUE);
+	if (unlikely(err)) {
+		goto done;
+	}
+	ranging_inst->range_type = RTT_TYPE_NAN_DIRECTED;
+	ranging_inst->range_role = NAN_RANGING_ROLE_INITIATOR;
+	/* schedule proxd timeout */
+	schedule_delayed_work(&rtt_status->proxd_timeout,
+		msecs_to_jiffies(DHD_NAN_RTT_TIMER_INTERVAL_MS));
+done:
+	if (err) { /* notify failure RTT event to host */
+		DHD_RTT_ERR(("Failed to issue Nan Ranging Request err %d\n", err));
+		dhd_rtt_handle_nan_rtt_session_end(dhd, &rtt_target->addr);
+		/* try to reset geofence */
+		if (ranging_inst) {
+			wl_cfgnan_reset_geofence_ranging(cfg, ranging_inst,
+				RTT_SCHED_DIR_TRIGGER_FAIL);
+		}
+	}
+	NAN_MUTEX_UNLOCK();
+	return err;
+}
+#endif /* WL_NAN */
 
 static int
 dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id,
@@ -1042,6 +1316,7 @@
 	uint16 buf_space_left;
 	uint16 all_tlvsize;
 	int ret = BCME_OK;
+
 	subcmd_info.name = "config";
 	subcmd_info.cmdid = WL_PROXD_CMD_CONFIG;
 
@@ -1049,7 +1324,7 @@
 		FTM_IOC_BUFSZ, &proxd_iovsize);
 
 	if (p_proxd_iov == NULL) {
-		DHD_ERROR(("%s : failed to allocate the iovar (size :%d)\n",
+		DHD_RTT_ERR(("%s : failed to allocate the iovar (size :%d)\n",
 			__FUNCTION__, FTM_IOC_BUFSZ));
 		return BCME_NOMEM;
 	}
@@ -1072,13 +1347,29 @@
 		ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov,
 				all_tlvsize + WL_PROXD_IOV_HDR_SIZE, NULL, 0, TRUE);
 		if (ret != BCME_OK) {
-			DHD_ERROR(("%s : failed to set config \n", __FUNCTION__));
+			DHD_RTT_ERR(("%s : failed to set config\n", __FUNCTION__));
 		}
 	}
 	/* clean up */
 	kfree(p_proxd_iov);
 	return ret;
 }
+
+static int
+dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version)
+{
+	int ret;
+	ftm_subcmd_info_t subcmd_info;
+	subcmd_info.name = "ver";
+	subcmd_info.cmdid = WL_PROXD_CMD_GET_VERSION;
+	subcmd_info.handler = NULL;
+	ret = dhd_rtt_common_get_handler(dhd, &subcmd_info,
+			WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL);
+	*out_version = (ret == BCME_OK) ? subcmd_info.version : 0;
+	return ret;
+}
+#endif /* WL_CFG80211 */
+
 chanspec_t
 dhd_rtt_convert_to_chspec(wifi_channel_info_t channel)
 {
@@ -1108,7 +1399,7 @@
 		chanspec = wf_chspec_80(center_chan, primary_chan);
 		break;
 	default:
-		DHD_ERROR(("doesn't support this bandwith : %d", channel.width));
+		DHD_RTT_ERR(("doesn't support this bandwith : %d", channel.width));
 		bw = -1;
 		break;
 	}
@@ -1129,27 +1420,50 @@
 {
 	int err = BCME_OK;
 	int idx;
-	rtt_status_info_t *rtt_status;
-	NULL_CHECK(params, "params is NULL", err);
+	rtt_status_info_t *rtt_status = NULL;
+	struct net_device *dev = NULL;
 
+	NULL_CHECK(params, "params is NULL", err);
 	NULL_CHECK(dhd, "dhd is NULL", err);
+
+	dev = dhd_linux_get_primary_netdev(dhd);
 	rtt_status = GET_RTTSTATE(dhd);
 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
+	NULL_CHECK(dev, "dev is NULL", err);
+
 	if (!HAS_11MC_CAP(rtt_status->rtt_capa.proto)) {
-		DHD_ERROR(("doesn't support RTT \n"));
-		return BCME_ERROR;
+		DHD_RTT_ERR(("doesn't support RTT \n"));
+		err = BCME_ERROR;
+		goto exit;
 	}
-	if (rtt_status->status != RTT_STOPPED) {
-		DHD_ERROR(("rtt is already started\n"));
-		return BCME_BUSY;
-	}
+
 	DHD_RTT(("%s enter\n", __FUNCTION__));
 
+	if (params->rtt_target_cnt > 0) {
+#ifdef WL_NAN
+		/* cancel ongoing geofence RTT if there */
+		if ((err = wl_cfgnan_suspend_geofence_rng_session(dev,
+			NULL, RTT_GEO_SUSPN_HOST_DIR_RTT_TRIG, 0)) != BCME_OK) {
+			goto exit;
+		}
+#endif /* WL_NAN */
+	} else {
+		err = BCME_BADARG;
+		goto exit;
+	}
+
+	mutex_lock(&rtt_status->rtt_mutex);
+	if (rtt_status->status != RTT_STOPPED) {
+		DHD_RTT_ERR(("rtt is already started\n"));
+		err = BCME_BUSY;
+		goto exit;
+	}
 	memset(rtt_status->rtt_config.target_info, 0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
 	rtt_status->rtt_config.rtt_target_cnt = params->rtt_target_cnt;
 	memcpy(rtt_status->rtt_config.target_info,
 		params->target_info, TARGET_INFO_SIZE(params->rtt_target_cnt));
 	rtt_status->status = RTT_STARTED;
+	DHD_RTT_MEM(("dhd_rtt_set_cfg: RTT Started, target_cnt = %d\n", params->rtt_target_cnt));
 	/* start to measure RTT from first device */
 	/* find next target to trigger RTT */
 	for (idx = rtt_status->cur_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
@@ -1164,15 +1478,511 @@
 	}
 	if (idx < rtt_status->rtt_config.rtt_target_cnt) {
 		DHD_RTT(("rtt_status->cur_idx : %d\n", rtt_status->cur_idx));
+		rtt_status->rtt_sched_reason = RTT_SCHED_HOST_TRIGGER;
 		schedule_work(&rtt_status->work);
 	}
+exit:
+	mutex_unlock(&rtt_status->rtt_mutex);
 	return err;
+}
+
+#define GEOFENCE_RTT_LOCK(rtt_status) mutex_lock(&(rtt_status)->geofence_mutex)
+#define GEOFENCE_RTT_UNLOCK(rtt_status) mutex_unlock(&(rtt_status)->geofence_mutex)
+
+#ifdef WL_NAN
+/* sets geofence role concurrency state TRUE/FALSE */
+void
+dhd_rtt_set_role_concurrency_state(dhd_pub_t *dhd, bool state)
+{
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+	if (!rtt_status) {
+		return;
+	}
+	GEOFENCE_RTT_LOCK(rtt_status);
+	rtt_status->geofence_cfg.role_concurr_state = state;
+	GEOFENCE_RTT_UNLOCK(rtt_status);
+}
+
+/* returns TRUE if geofence role concurrency constraint exists */
+bool
+dhd_rtt_get_role_concurrency_state(dhd_pub_t *dhd)
+{
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+	if (!rtt_status) {
+		return FALSE;
+	}
+	return rtt_status->geofence_cfg.role_concurr_state;
+}
+
+int8
+dhd_rtt_get_geofence_target_cnt(dhd_pub_t *dhd)
+{
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+	if (!rtt_status) {
+		return 0;
+	}
+	return rtt_status->geofence_cfg.geofence_target_cnt;
+}
+
+/* sets geofence rtt state TRUE/FALSE */
+void
+dhd_rtt_set_geofence_rtt_state(dhd_pub_t *dhd, bool state)
+{
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+	if (!rtt_status) {
+		return;
+	}
+	GEOFENCE_RTT_LOCK(rtt_status);
+	rtt_status->geofence_cfg.rtt_in_progress = state;
+	GEOFENCE_RTT_UNLOCK(rtt_status);
+}
+
+/* returns TRUE if geofence rtt is in progress */
+bool
+dhd_rtt_get_geofence_rtt_state(dhd_pub_t *dhd)
+{
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+
+	if (!rtt_status) {
+		return FALSE;
+	}
+
+	return rtt_status->geofence_cfg.rtt_in_progress;
+}
+
+/* returns geofence RTT target list Head */
+rtt_geofence_target_info_t*
+dhd_rtt_get_geofence_target_head(dhd_pub_t *dhd)
+{
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+	rtt_geofence_target_info_t* head = NULL;
+
+	if (!rtt_status) {
+		return NULL;
+	}
+
+	if (rtt_status->geofence_cfg.geofence_target_cnt) {
+		head = &rtt_status->geofence_cfg.geofence_target_info[0];
+	}
+
+	return head;
+}
+
+int8
+dhd_rtt_get_geofence_cur_target_idx(dhd_pub_t *dhd)
+{
+	int8 target_cnt = 0, cur_idx = DHD_RTT_INVALID_TARGET_INDEX;
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+
+	if (!rtt_status) {
+		goto exit;
+	}
+
+	target_cnt = rtt_status->geofence_cfg.geofence_target_cnt;
+	if (target_cnt == 0) {
+		goto exit;
+	}
+
+	cur_idx = rtt_status->geofence_cfg.cur_target_idx;
+	ASSERT(cur_idx <= target_cnt);
+
+exit:
+	return cur_idx;
+}
+
+void
+dhd_rtt_move_geofence_cur_target_idx_to_next(dhd_pub_t *dhd)
+{
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+
+	if (!rtt_status) {
+		return;
+	}
+
+	if (rtt_status->geofence_cfg.geofence_target_cnt == 0) {
+		/* Invalidate current idx if no targets */
+		rtt_status->geofence_cfg.cur_target_idx =
+			DHD_RTT_INVALID_TARGET_INDEX;
+		/* Cancel pending retry timer if any */
+		if (delayed_work_pending(&rtt_status->rtt_retry_timer)) {
+			cancel_delayed_work(&rtt_status->rtt_retry_timer);
+		}
+		return;
+	}
+	rtt_status->geofence_cfg.cur_target_idx++;
+
+	if (rtt_status->geofence_cfg.cur_target_idx >=
+		rtt_status->geofence_cfg.geofence_target_cnt) {
+		/* Reset once all targets done */
+		rtt_status->geofence_cfg.cur_target_idx = 0;
+	}
+}
+
+/* returns geofence current RTT target */
+rtt_geofence_target_info_t*
+dhd_rtt_get_geofence_current_target(dhd_pub_t *dhd)
+{
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+	rtt_geofence_target_info_t* cur_target = NULL;
+	int cur_idx = 0;
+
+	if (!rtt_status) {
+		return NULL;
+	}
+
+	cur_idx = dhd_rtt_get_geofence_cur_target_idx(dhd);
+	if (cur_idx >= 0) {
+		cur_target = &rtt_status->geofence_cfg.geofence_target_info[cur_idx];
+	}
+
+	return cur_target;
+}
+
+/* returns geofence target from list for the peer */
+rtt_geofence_target_info_t*
+dhd_rtt_get_geofence_target(dhd_pub_t *dhd, struct ether_addr* peer_addr, int8 *index)
+{
+	int8 i;
+	rtt_status_info_t *rtt_status;
+	int target_cnt;
+	rtt_geofence_target_info_t *geofence_target_info, *tgt = NULL;
+
+	rtt_status = GET_RTTSTATE(dhd);
+
+	if (!rtt_status) {
+		return NULL;
+	}
+
+	target_cnt = rtt_status->geofence_cfg.geofence_target_cnt;
+	geofence_target_info = rtt_status->geofence_cfg.geofence_target_info;
+
+	/* Loop through to find target */
+	for (i = 0; i < target_cnt; i++) {
+		if (geofence_target_info[i].valid == FALSE) {
+			break;
+		}
+		if (!memcmp(peer_addr, &geofence_target_info[i].peer_addr,
+				ETHER_ADDR_LEN)) {
+			*index = i;
+			tgt = &geofence_target_info[i];
+		}
+	}
+	if (!tgt) {
+		DHD_RTT(("dhd_rtt_get_geofence_target: Target not found in list,"
+			" MAC ADDR: "MACDBG" \n", MAC2STRDBG(peer_addr)));
+	}
+	return tgt;
+}
+
+/* add geofence target to the target list */
+int
+dhd_rtt_add_geofence_target(dhd_pub_t *dhd, rtt_geofence_target_info_t *target)
+{
+	int err = BCME_OK;
+	rtt_status_info_t *rtt_status;
+	rtt_geofence_target_info_t  *geofence_target_info;
+	int8 geofence_target_cnt, index;
+
+	NULL_CHECK(dhd, "dhd is NULL", err);
+	rtt_status = GET_RTTSTATE(dhd);
+	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
+
+	GEOFENCE_RTT_LOCK(rtt_status);
+
+	/* Get the geofence_target via peer addr, index param is dumm here */
+	geofence_target_info = dhd_rtt_get_geofence_target(dhd, &target->peer_addr, &index);
+	if (geofence_target_info) {
+		DHD_RTT(("Duplicate geofencing RTT add request dropped\n"));
+		err = BCME_OK;
+		goto exit;
+	}
+
+	geofence_target_cnt = rtt_status->geofence_cfg.geofence_target_cnt;
+	if (geofence_target_cnt >= RTT_MAX_GEOFENCE_TARGET_CNT) {
+		DHD_RTT(("Queue full, Geofencing RTT add request dropped\n"));
+		err = BCME_NORESOURCE;
+		goto exit;
+	}
+
+	/* Add Geofence RTT request and increment target count */
+	geofence_target_info = rtt_status->geofence_cfg.geofence_target_info;
+	/* src and dest buffer len same, pointers of same DS statically allocated */
+	(void)memcpy_s(&geofence_target_info[geofence_target_cnt],
+		sizeof(geofence_target_info[geofence_target_cnt]), target,
+		sizeof(*target));
+	geofence_target_info[geofence_target_cnt].valid = TRUE;
+	rtt_status->geofence_cfg.geofence_target_cnt++;
+	if (rtt_status->geofence_cfg.geofence_target_cnt == 1) {
+		/* Adding first target */
+		rtt_status->geofence_cfg.cur_target_idx = 0;
+	}
+
+exit:
+	GEOFENCE_RTT_UNLOCK(rtt_status);
+	return err;
+}
+
+/* removes geofence target from the target list */
+int
+dhd_rtt_remove_geofence_target(dhd_pub_t *dhd, struct ether_addr *peer_addr)
+{
+	int err = BCME_OK;
+	rtt_status_info_t *rtt_status;
+	rtt_geofence_target_info_t  *geofence_target_info;
+	int8 geofence_target_cnt, j, index = 0;
+
+	NULL_CHECK(dhd, "dhd is NULL", err);
+	rtt_status = GET_RTTSTATE(dhd);
+	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
+
+	GEOFENCE_RTT_LOCK(rtt_status);
+
+	geofence_target_cnt = dhd_rtt_get_geofence_target_cnt(dhd);
+	if (geofence_target_cnt == 0) {
+		DHD_RTT(("Queue Empty, Geofencing RTT remove request dropped\n"));
+		ASSERT(0);
+		goto exit;
+	}
+
+	/* Get the geofence_target via peer addr */
+	geofence_target_info = dhd_rtt_get_geofence_target(dhd, peer_addr, &index);
+	if (geofence_target_info == NULL) {
+		DHD_RTT(("Geofencing RTT target not found, remove request dropped\n"));
+		err = BCME_NOTFOUND;
+		goto exit;
+	}
+
+	/* left shift all the valid entries, as we dont keep holes in list */
+	for (j = index; (j+1) < geofence_target_cnt; j++) {
+		if (geofence_target_info[j].valid == TRUE) {
+			/*
+			 * src and dest buffer len same, pointers of same DS
+			 * statically allocated
+			 */
+			(void)memcpy_s(&geofence_target_info[j], sizeof(geofence_target_info[j]),
+				&geofence_target_info[j + 1],
+				sizeof(geofence_target_info[j + 1]));
+		} else {
+			break;
+		}
+	}
+	rtt_status->geofence_cfg.geofence_target_cnt--;
+	if ((rtt_status->geofence_cfg.geofence_target_cnt == 0) ||
+		(index == rtt_status->geofence_cfg.cur_target_idx)) {
+		/* Move cur_idx to next target */
+		dhd_rtt_move_geofence_cur_target_idx_to_next(dhd);
+	} else if (index < rtt_status->geofence_cfg.cur_target_idx) {
+		/* Decrement cur index if cur target position changed */
+		rtt_status->geofence_cfg.cur_target_idx--;
+	}
+
+exit:
+	GEOFENCE_RTT_UNLOCK(rtt_status);
+	return err;
+}
+
+/* deletes/empty geofence target list */
+int
+dhd_rtt_delete_geofence_target_list(dhd_pub_t *dhd)
+{
+	rtt_status_info_t *rtt_status;
+
+	int err = BCME_OK;
+
+	NULL_CHECK(dhd, "dhd is NULL", err);
+	rtt_status = GET_RTTSTATE(dhd);
+	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
+	GEOFENCE_RTT_LOCK(rtt_status);
+	memset_s(&rtt_status->geofence_cfg, sizeof(rtt_geofence_cfg_t),
+		0, sizeof(rtt_geofence_cfg_t));
+	GEOFENCE_RTT_UNLOCK(rtt_status);
+	return err;
+}
+
+int
+dhd_rtt_sched_geofencing_target(dhd_pub_t *dhd)
+{
+	rtt_geofence_target_info_t  *geofence_target_info;
+	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
+	int ret = BCME_OK;
+	bool geofence_state;
+	bool role_concurrency_state;
+	u8 rtt_invalid_reason = RTT_STATE_VALID;
+	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+
+	NAN_MUTEX_LOCK();
+
+	if ((cfg->nan_init_state == FALSE) ||
+		(cfg->nan_enable == FALSE)) {
+		ret = BCME_NOTENABLED;
+		goto done;
+	}
+	geofence_state = dhd_rtt_get_geofence_rtt_state(dhd);
+	role_concurrency_state = dhd_rtt_get_role_concurrency_state(dhd);
+
+	DHD_RTT_ERR(("dhd_rtt_sched_geofencing_target: sched_reason = %d\n",
+		rtt_status->rtt_sched_reason));
+
+	if (geofence_state == TRUE || role_concurrency_state == TRUE) {
+		ret = BCME_ERROR;
+		DHD_RTT_ERR(("geofencing constraint , sched request dropped,"
+			" geofence_state = %d, role_concurrency_state = %d\n",
+			geofence_state, role_concurrency_state));
+		goto done;
+	}
+
+	/* Get current geofencing target */
+	geofence_target_info = dhd_rtt_get_geofence_current_target(dhd);
+
+	/* call cfg API for trigerring geofencing RTT */
+	if (geofence_target_info) {
+		/* check for dp/others concurrency */
+		rtt_invalid_reason = dhd_rtt_invalid_states(dev,
+				&geofence_target_info->peer_addr);
+		if (rtt_invalid_reason != RTT_STATE_VALID) {
+			ret = BCME_BUSY;
+			DHD_RTT_ERR(("DRV State is not valid for RTT, "
+				"invalid_state = %d\n", rtt_invalid_reason));
+			goto done;
+		}
+
+		ret = wl_cfgnan_trigger_geofencing_ranging(dev,
+				&geofence_target_info->peer_addr);
+		if (ret == BCME_OK) {
+			dhd_rtt_set_geofence_rtt_state(dhd, TRUE);
+		}
+	} else {
+		DHD_RTT(("No RTT target to schedule\n"));
+		ret = BCME_NOTFOUND;
+	}
+
+done:
+	NAN_MUTEX_UNLOCK();
+	return ret;
+}
+#endif /* WL_NAN */
+
+#ifdef WL_CFG80211
+#ifdef WL_NAN
+static void
+dhd_rtt_retry(dhd_pub_t *dhd)
+{
+	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
+	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+	rtt_geofence_target_info_t  *geofence_target = NULL;
+	nan_ranging_inst_t *ranging_inst = NULL;
+
+	geofence_target = dhd_rtt_get_geofence_current_target(dhd);
+	if (!geofence_target) {
+		DHD_RTT(("dhd_rtt_retry: geofence target null\n"));
+		goto exit;
+	}
+	ranging_inst = wl_cfgnan_get_ranging_inst(cfg,
+		&geofence_target->peer_addr, NAN_RANGING_ROLE_INITIATOR);
+	if (!ranging_inst) {
+		DHD_RTT(("dhd_rtt_retry: ranging instance null\n"));
+		goto exit;
+	}
+	wl_cfgnan_reset_geofence_ranging(cfg,
+		ranging_inst, RTT_SCHED_RTT_RETRY_GEOFENCE);
+
+exit:
+	return;
+}
+
+static void
+dhd_rtt_retry_work(struct work_struct *work)
+{
+	rtt_status_info_t *rtt_status = NULL;
+	dhd_pub_t *dhd = NULL;
+	struct net_device *dev = NULL;
+	struct bcm_cfg80211 *cfg = NULL;
+
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif // endif
+	rtt_status = container_of(work, rtt_status_info_t, proxd_timeout.work);
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif // endif
+
+	dhd = rtt_status->dhd;
+	if (dhd == NULL) {
+		DHD_RTT_ERR(("%s : dhd is NULL\n", __FUNCTION__));
+		goto exit;
+	}
+	dev = dhd_linux_get_primary_netdev(dhd);
+	cfg = wl_get_cfg(dev);
+
+	NAN_MUTEX_LOCK();
+	mutex_lock(&rtt_status->rtt_mutex);
+	(void) dhd_rtt_retry(dhd);
+	mutex_unlock(&rtt_status->rtt_mutex);
+	NAN_MUTEX_UNLOCK();
+
+exit:
+	return;
+}
+#endif /* WL_NAN */
+
+/*
+ * Return zero (0)
+ * for valid RTT state
+ * means if RTT is applicable
+ */
+uint8
+dhd_rtt_invalid_states(struct net_device *ndev, struct ether_addr *peer_addr)
+{
+	uint8 invalid_reason = RTT_STATE_VALID;
+	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
+
+	UNUSED_PARAMETER(cfg);
+	UNUSED_PARAMETER(invalid_reason);
+
+	/* Make sure peer addr is not NULL in caller */
+	ASSERT(peer_addr);
+	/*
+	 * Keep adding prohibited drv states here
+	 * Only generic conditions which block
+	 * All RTTs like NDP connection
+	 */
+
+#ifdef WL_NAN
+	if (wl_cfgnan_data_dp_exists_with_peer(cfg, peer_addr)) {
+		invalid_reason = RTT_STATE_INV_REASON_NDP_EXIST;
+		DHD_RTT(("NDP in progress/connected, RTT prohibited\n"));
+		goto exit;
+	}
+#endif /* WL_NAN */
+
+	/* Remove below #defines once more exit calls come */
+#ifdef WL_NAN
+exit:
+#endif /* WL_NAN */
+	return invalid_reason;
+}
+#endif /* WL_CFG80211 */
+
+void
+dhd_rtt_schedule_rtt_work_thread(dhd_pub_t *dhd, int sched_reason)
+{
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+	if (rtt_status == NULL) {
+		ASSERT(0);
+	} else {
+		rtt_status->rtt_sched_reason = sched_reason;
+		schedule_work(&rtt_status->work);
+	}
+	return;
 }
 
 int
 dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt)
 {
 	int err = BCME_OK;
+#ifdef WL_CFG80211
 	int i = 0, j = 0;
 	rtt_status_info_t *rtt_status;
 	rtt_results_header_t *entry, *next;
@@ -1183,7 +1993,7 @@
 	rtt_status = GET_RTTSTATE(dhd);
 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
 	if (rtt_status->status == RTT_STOPPED) {
-		DHD_ERROR(("rtt is not started\n"));
+		DHD_RTT_ERR(("rtt is not started\n"));
 		return BCME_OK;
 	}
 	DHD_RTT(("%s enter\n", __FUNCTION__));
@@ -1203,6 +2013,7 @@
 		/* remove the rtt results in cache */
 		if (!list_empty(&rtt_status->rtt_results_cache)) {
 			/* Iterate rtt_results_header list */
+			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 			list_for_each_entry_safe(entry, next,
 				&rtt_status->rtt_results_cache, list) {
 				list_del(&entry->list);
@@ -1214,12 +2025,14 @@
 				}
 				kfree(entry);
 			}
+			GCC_DIAGNOSTIC_POP();
 		}
 		/* send the rtt complete event to wake up the user process */
+		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 		list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
+			GCC_DIAGNOSTIC_POP();
 			iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache);
 		}
-
 		/* reinitialize the HEAD */
 		INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
 		/* clear information for rtt_config */
@@ -1227,20 +2040,128 @@
 		memset(rtt_status->rtt_config.target_info, 0,
 			TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
 		rtt_status->cur_idx = 0;
+		/* Cancel pending proxd timeout work if any */
+		if (delayed_work_pending(&rtt_status->proxd_timeout)) {
+			cancel_delayed_work(&rtt_status->proxd_timeout);
+		}
 		dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION);
+#ifdef WL_NAN
+		dhd_rtt_delete_nan_session(dhd);
+#endif /* WL_NAN */
 		dhd_rtt_ftm_enable(dhd, FALSE);
 	}
 	mutex_unlock(&rtt_status->rtt_mutex);
+#endif /* WL_CFG80211 */
 	return err;
+}
+
+#ifdef WL_CFG80211
+static void
+dhd_rtt_timeout(dhd_pub_t *dhd)
+{
+	rtt_status_info_t *rtt_status;
+#ifndef DHD_DUMP_ON_RTT_TIMEOUT
+	rtt_target_info_t *rtt_target = NULL;
+	rtt_target_info_t *rtt_target_info = NULL;
+#ifdef WL_NAN
+	nan_ranging_inst_t *ranging_inst = NULL;
+	int ret = BCME_OK;
+	uint32 status;
+	struct net_device *ndev = dhd_linux_get_primary_netdev(dhd);
+	struct bcm_cfg80211 *cfg =  wiphy_priv(ndev->ieee80211_ptr->wiphy);
+#endif /* WL_NAN */
+#endif /* !DHD_DUMP_ON_RTT_TIMEOUT */
+
+	rtt_status = GET_RTTSTATE(dhd);
+	if (!rtt_status) {
+		DHD_RTT_ERR(("Proxd timer expired but no RTT status\n"));
+		goto exit;
+	}
+
+	if (RTT_IS_STOPPED(rtt_status)) {
+		DHD_RTT_ERR(("Proxd timer expired but no RTT Request\n"));
+		goto exit;
+	}
+
+#ifdef DHD_DUMP_ON_RTT_TIMEOUT
+	/* Dump, and Panic depending on memdump.info */
+	if (dhd_query_bus_erros(dhd)) {
+		goto exit;
+	}
+#ifdef DHD_FW_COREDUMP
+	if (dhd->memdump_enabled) {
+		/* Behave based on user memdump info */
+		dhd->memdump_type = DUMP_TYPE_PROXD_TIMEOUT;
+		dhd_bus_mem_dump(dhd);
+	}
+#endif /* DHD_FW_COREDUMP */
+#else /* DHD_DUMP_ON_RTT_TIMEOUT */
+	/* Cancel RTT for target and proceed to next target */
+	rtt_target_info = rtt_status->rtt_config.target_info;
+	if ((!rtt_target_info) ||
+		(rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt)) {
+		goto exit;
+	}
+	rtt_target = &rtt_target_info[rtt_status->cur_idx];
+	WL_ERR(("Proxd timer expired for Target: "MACDBG" \n", MAC2STRDBG(&rtt_target->addr)));
+#ifdef WL_NAN
+	if (rtt_target->peer == RTT_PEER_NAN) {
+		ranging_inst = wl_cfgnan_check_for_ranging(cfg, &rtt_target->addr);
+		if (!ranging_inst) {
+			goto exit;
+		}
+		ret =  wl_cfgnan_cancel_ranging(ndev, cfg, ranging_inst->range_id,
+				NAN_RNG_TERM_FLAG_IMMEDIATE, &status);
+		if (unlikely(ret) || unlikely(status)) {
+			WL_ERR(("%s:nan range cancel failed ret = %d status = %d\n",
+				__FUNCTION__, ret, status));
+		}
+	} else
+#endif /* WL_NAN */
+	{
+		/* For Legacy RTT */
+		dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION);
+	}
+	dhd_rtt_create_failure_result(rtt_status, &rtt_target->addr);
+	dhd_rtt_handle_rtt_session_end(dhd);
+#endif /* DHD_DUMP_ON_RTT_TIMEOUT */
+exit:
+	return;
+}
+
+static void
+dhd_rtt_timeout_work(struct work_struct *work)
+{
+	rtt_status_info_t *rtt_status = NULL;
+	dhd_pub_t *dhd = NULL;
+
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif // endif
+	rtt_status = container_of(work, rtt_status_info_t, proxd_timeout.work);
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif // endif
+
+	dhd = rtt_status->dhd;
+	if (dhd == NULL) {
+		DHD_RTT_ERR(("%s : dhd is NULL\n", __FUNCTION__));
+		return;
+	}
+	mutex_lock(&rtt_status->rtt_mutex);
+	(void) dhd_rtt_timeout(dhd);
+	mutex_unlock(&rtt_status->rtt_mutex);
 }
 
 static int
 dhd_rtt_start(dhd_pub_t *dhd)
 {
 	int err = BCME_OK;
+	int err_at = 0;
 	char eabuf[ETHER_ADDR_STR_LEN];
 	char chanbuf[CHANSPEC_STR_LEN];
-	int mpc = 0;
+	int pm = PM_OFF;
 	int ftm_cfg_cnt = 0;
 	int ftm_param_cnt = 0;
 	uint32 rspec = 0;
@@ -1248,39 +2169,86 @@
 	ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS];
 	rtt_target_info_t *rtt_target;
 	rtt_status_info_t *rtt_status;
+	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
+	u8 ioctl_buf[WLC_IOCTL_SMLEN];
+	u8 rtt_invalid_reason = RTT_STATE_VALID;
+	int rtt_sched_type = RTT_TYPE_INVALID;
+
 	NULL_CHECK(dhd, "dhd is NULL", err);
 
 	rtt_status = GET_RTTSTATE(dhd);
 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
+
+	DHD_RTT(("Enter %s\n", __FUNCTION__));
+
+	if (RTT_IS_STOPPED(rtt_status)) {
+		DHD_RTT(("No Directed RTT target to process, check for geofence\n"));
+		goto geofence;
+	}
+
 	if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) {
 		err = BCME_RANGE;
-		DHD_ERROR(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx));
-		goto exit;
-	}
-	if (RTT_IS_STOPPED(rtt_status)) {
-		DHD_ERROR(("RTT is stopped\n"));
-		goto exit;
-	}
-	/* turn off mpc in case of non-associted */
-	if (!dhd_is_associated(dhd, NULL, NULL)) {
-		err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), NULL, 0, TRUE);
-		if (err) {
-			DHD_ERROR(("%s : failed to set mpc\n", __FUNCTION__));
-			goto exit;
+		err_at = 1;
+		DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx));
+		if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) {
+			DHD_RTT_ERR(("STA is set as Target/Responder \n"));
+			err = BCME_ERROR;
+			err_at = 1;
 		}
-		rtt_status->mpc = 1; /* Either failure or complete, we need to enable mpc */
+		goto exit;
+	}
+
+	rtt_status->pm = PM_OFF;
+	err = wldev_ioctl_get(dev, WLC_GET_PM, &rtt_status->pm, sizeof(rtt_status->pm));
+	if (err) {
+		DHD_RTT_ERR(("Failed to get the PM value\n"));
+	} else {
+		err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
+		if (err) {
+			DHD_RTT_ERR(("Failed to set the PM\n"));
+			rtt_status->pm_restore = FALSE;
+		} else {
+			rtt_status->pm_restore = TRUE;
+		}
 	}
 
 	mutex_lock(&rtt_status->rtt_mutex);
 	/* Get a target information */
 	rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
 	mutex_unlock(&rtt_status->rtt_mutex);
-	DHD_ERROR(("%s enter\n", __FUNCTION__));
+	DHD_RTT(("%s enter\n", __FUNCTION__));
+
+	if (ETHER_ISNULLADDR(rtt_target->addr.octet)) {
+		err = BCME_BADADDR;
+		err_at = 2;
+		DHD_RTT(("RTT Target addr is NULL\n"));
+		goto exit;
+	}
+
+	/* check for dp/others concurrency */
+	rtt_invalid_reason = dhd_rtt_invalid_states(dev, &rtt_target->addr);
+	if (rtt_invalid_reason != RTT_STATE_VALID) {
+		err = BCME_BUSY;
+		err_at = 3;
+		DHD_RTT(("DRV State is not valid for RTT\n"));
+		goto exit;
+	}
+
+#ifdef WL_NAN
+	if (rtt_target->peer == RTT_PEER_NAN) {
+		rtt_sched_type = RTT_TYPE_NAN_DIRECTED;
+		rtt_status->status = RTT_ENABLED;
+		/* Ignore return value..failure taken care inside the API */
+		dhd_rtt_nan_start_session(dhd, rtt_target);
+		goto exit;
+	}
+#endif /* WL_NAN */
 	if (!RTT_IS_ENABLED(rtt_status)) {
 		/* enable ftm */
 		err = dhd_rtt_ftm_enable(dhd, TRUE);
 		if (err) {
-			DHD_ERROR(("failed to enable FTM (%d)\n", err));
+			DHD_RTT_ERR(("failed to enable FTM (%d)\n", err));
+			err_at = 5;
 			goto exit;
 		}
 	}
@@ -1288,7 +2256,8 @@
 	/* delete session of index default sesession  */
 	err = dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION);
 	if (err < 0 && err != BCME_NOTFOUND) {
-		DHD_ERROR(("failed to delete session of FTM (%d)\n", err));
+		DHD_RTT_ERR(("failed to delete session of FTM (%d)\n", err));
+		err_at = 6;
 		goto exit;
 	}
 	rtt_status->status = RTT_ENABLED;
@@ -1300,45 +2269,72 @@
 	ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_INITIATOR;
 	dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS,
 		ftm_configs, ftm_cfg_cnt);
+
+	memset(ioctl_buf, 0, WLC_IOCTL_SMLEN);
+
+	/* Rand Mac for newer version in place of cur_eth */
+	if (dhd->wlc_ver_major < RTT_IOV_CUR_ETH_OBSOLETE) {
+		err = wldev_iovar_getbuf(dev, "cur_etheraddr", NULL, 0,
+				ioctl_buf, WLC_IOCTL_SMLEN, NULL);
+		if (err) {
+			DHD_RTT_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
+			err_at = 7;
+			goto exit;
+		}
+		memcpy(rtt_target->local_addr.octet, ioctl_buf, ETHER_ADDR_LEN);
+
+		/* local mac address */
+		if (!ETHER_ISNULLADDR(rtt_target->local_addr.octet)) {
+			ftm_params[ftm_param_cnt].mac_addr = rtt_target->local_addr;
+			ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_CUR_ETHER_ADDR;
+			bcm_ether_ntoa(&rtt_target->local_addr, eabuf);
+			DHD_RTT((">\t local %s\n", eabuf));
+		}
+	}
 	/* target's mac address */
 	if (!ETHER_ISNULLADDR(rtt_target->addr.octet)) {
 		ftm_params[ftm_param_cnt].mac_addr = rtt_target->addr;
 		ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_PEER_MAC;
-		DHD_ERROR((">\t target %s\n", bcm_ether_ntoa(&rtt_target->addr, eabuf)));
+		bcm_ether_ntoa(&rtt_target->addr, eabuf);
+		DHD_RTT((">\t target %s\n", eabuf));
 	}
 	/* target's chanspec */
 	if (rtt_target->chanspec) {
 		ftm_params[ftm_param_cnt].chanspec = htol32((uint32)rtt_target->chanspec);
 		ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_CHANSPEC;
-		DHD_ERROR((">\t chanspec : %s\n", wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
+		wf_chspec_ntoa(rtt_target->chanspec, chanbuf);
+		DHD_RTT((">\t chanspec : %s\n", chanbuf));
 	}
 	/* num-burst */
 	if (rtt_target->num_burst) {
 		ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_burst);
 		ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_NUM_BURST;
-		DHD_ERROR((">\t num of burst : %d\n", rtt_target->num_burst));
+		DHD_RTT((">\t num of burst : %d\n", rtt_target->num_burst));
 	}
 	/* number of frame per burst */
-	if (rtt_target->num_frames_per_burst == 0) {
-		rtt_target->num_frames_per_burst =
-			CHSPEC_IS20(rtt_target->chanspec) ? FTM_DEFAULT_CNT_20M :
-			CHSPEC_IS40(rtt_target->chanspec) ? FTM_DEFAULT_CNT_40M :
-			FTM_DEFAULT_CNT_80M;
+	rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_80M;
+	if (CHSPEC_IS80(rtt_target->chanspec)) {
+		rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_80M;
+	} else if (CHSPEC_IS40(rtt_target->chanspec)) {
+		rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_40M;
+	} else if (CHSPEC_IS20(rtt_target->chanspec)) {
+		rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_20M;
 	}
 	ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_frames_per_burst);
 	ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_NUM_FTM;
-	DHD_ERROR((">\t number of frame per burst : %d\n", rtt_target->num_frames_per_burst));
+	DHD_RTT((">\t number of frame per burst : %d\n", rtt_target->num_frames_per_burst));
+
 	/* FTM retry count */
 	if (rtt_target->num_retries_per_ftm) {
 		ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftm;
 		ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_RETRIES;
-		DHD_ERROR((">\t retry count of FTM  : %d\n", rtt_target->num_retries_per_ftm));
+		DHD_RTT((">\t retry count of FTM  : %d\n", rtt_target->num_retries_per_ftm));
 	}
 	/* FTM Request retry count */
 	if (rtt_target->num_retries_per_ftmr) {
 		ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftmr;
 		ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_REQ_RETRIES;
-		DHD_ERROR((">\t retry count of FTM Req : %d\n", rtt_target->num_retries_per_ftm));
+		DHD_RTT((">\t retry count of FTM Req : %d\n", rtt_target->num_retries_per_ftmr));
 	}
 	/* burst-period */
 	if (rtt_target->burst_period) {
@@ -1346,86 +2342,140 @@
 			htol32(rtt_target->burst_period); /* ms */
 		ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC;
 		ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_PERIOD;
-		DHD_ERROR((">\t burst period : %d ms\n", rtt_target->burst_period));
+		DHD_RTT((">\t burst period : %d ms\n", rtt_target->burst_period));
 	}
+	/* Setting both duration and timeout to MAX duration
+	 * to handle the congestion environments.
+	 * Hence ignoring the user config.
+	 */
 	/* burst-duration */
+	rtt_target->burst_duration = FTM_MAX_BURST_DUR_TMO_MS;
 	if (rtt_target->burst_duration) {
 		ftm_params[ftm_param_cnt].data_intvl.intvl =
-			htol32(rtt_target->burst_period); /* ms */
+			htol32(rtt_target->burst_duration); /* ms */
 		ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC;
 		ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_DURATION;
-		DHD_ERROR((">\t burst duration : %d ms\n",
+		DHD_RTT((">\t burst duration : %d ms\n",
 			rtt_target->burst_duration));
 	}
+	/* burst-timeout */
+	rtt_target->burst_timeout = FTM_MAX_BURST_DUR_TMO_MS;
+	if (rtt_target->burst_timeout) {
+		ftm_params[ftm_param_cnt].data_intvl.intvl =
+			htol32(rtt_target->burst_timeout); /* ms */
+		ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC;
+		ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_TIMEOUT;
+		DHD_RTT((">\t burst timeout : %d ms\n",
+			rtt_target->burst_timeout));
+	}
+	/* event_mask..applicable for only Legacy RTT.
+	* For nan-rtt config happens from firmware
+	*/
+	ftm_params[ftm_param_cnt].event_mask = ((1 << WL_PROXD_EVENT_BURST_END) |
+		(1 << WL_PROXD_EVENT_SESSION_END));
+	ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_EVENT_MASK;
+
 	if (rtt_target->bw && rtt_target->preamble) {
 		bool use_default = FALSE;
 		int nss;
 		int mcs;
 		switch (rtt_target->preamble) {
-		case RTT_PREAMBLE_LEGACY:
-			rspec |= WL_RSPEC_ENCODE_RATE; /* 11abg */
-			rspec |= WL_RATE_6M;
-			break;
-		case RTT_PREAMBLE_HT:
-			rspec |= WL_RSPEC_ENCODE_HT; /* 11n HT */
-			mcs = 0; /* default MCS 0 */
-			rspec |= mcs;
-			break;
-		case RTT_PREAMBLE_VHT:
-			rspec |= WL_RSPEC_ENCODE_VHT; /* 11ac VHT */
-			mcs = 0; /* default MCS 0 */
-			nss = 1; /* default Nss = 1  */
-			rspec |= (nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs;
-			break;
-		default:
-			DHD_ERROR(("doesn't support this preamble : %d\n", rtt_target->preamble));
-			use_default = TRUE;
-			break;
+			case RTT_PREAMBLE_LEGACY:
+				rspec |= WL_RSPEC_ENCODE_RATE; /* 11abg */
+				rspec |= WL_RATE_6M;
+				break;
+			case RTT_PREAMBLE_HT:
+				rspec |= WL_RSPEC_ENCODE_HT; /* 11n HT */
+				mcs = 0; /* default MCS 0 */
+				rspec |= mcs;
+				break;
+			case RTT_PREAMBLE_VHT:
+				rspec |= WL_RSPEC_ENCODE_VHT; /* 11ac VHT */
+				mcs = 0; /* default MCS 0 */
+				nss = 1; /* default Nss = 1  */
+				rspec |= (nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs;
+				break;
+			default:
+				DHD_RTT(("doesn't support this preamble : %d\n",
+					rtt_target->preamble));
+				use_default = TRUE;
+				break;
 		}
 		switch (rtt_target->bw) {
-		case RTT_BW_20:
-			rspec |= WL_RSPEC_BW_20MHZ;
-			break;
-		case RTT_BW_40:
-			rspec |= WL_RSPEC_BW_40MHZ;
-			break;
-		case RTT_BW_80:
-			rspec |= WL_RSPEC_BW_80MHZ;
-			break;
-		default:
-			DHD_ERROR(("doesn't support this BW : %d\n", rtt_target->bw));
-			use_default = TRUE;
-			break;
+			case RTT_BW_20:
+				rspec |= WL_RSPEC_BW_20MHZ;
+				break;
+			case RTT_BW_40:
+				rspec |= WL_RSPEC_BW_40MHZ;
+				break;
+			case RTT_BW_80:
+				rspec |= WL_RSPEC_BW_80MHZ;
+				break;
+			default:
+				DHD_RTT(("doesn't support this BW : %d\n", rtt_target->bw));
+				use_default = TRUE;
+				break;
 		}
 		if (!use_default) {
 			ftm_params[ftm_param_cnt].data32 = htol32(rspec);
 			ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_RATESPEC;
-			DHD_ERROR((">\t ratespec : %d\n", rspec));
+			DHD_RTT((">\t ratespec : %d\n", rspec));
 		}
 
 	}
+	dhd_set_rand_mac_oui(dhd);
 	dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_GENERAL,
-		ftm_params, ftm_param_cnt);
+			ftm_params, ftm_param_cnt);
 
+	rtt_sched_type = RTT_TYPE_LEGACY;
 	err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE);
 	if (err) {
-		DHD_ERROR(("failed to start session of FTM : error %d\n", err));
+		DHD_RTT_ERR(("failed to start session of FTM : error %d\n", err));
+		err_at = 8;
+	} else {
+		/* schedule proxd timeout */
+		schedule_delayed_work(&rtt_status->proxd_timeout,
+			msecs_to_jiffies(DHD_NAN_RTT_TIMER_INTERVAL_MS));
+
 	}
+
+	goto exit;
+geofence:
+#ifdef WL_NAN
+	/* sched geofencing rtt */
+	rtt_sched_type = RTT_TYPE_NAN_GEOFENCE;
+	if ((err = dhd_rtt_sched_geofencing_target(dhd)) != BCME_OK) {
+		DHD_RTT_ERR(("geofencing sched failed, err = %d\n", err));
+		err_at = 9;
+	}
+#endif /* WL_NAN */
+
 exit:
 	if (err) {
+		/* RTT Failed */
+		DHD_RTT_ERR(("dhd_rtt_start: Failed & RTT_STOPPED, err = %d,"
+			" err_at = %d, rtt_sched_type = %d, rtt_invalid_reason = %d\n"
+			" sched_reason = %d",
+			err, err_at, rtt_sched_type, rtt_invalid_reason,
+			rtt_status->rtt_sched_reason));
 		rtt_status->status = RTT_STOPPED;
 		/* disable FTM */
 		dhd_rtt_ftm_enable(dhd, FALSE);
-		if (rtt_status->mpc) {
-			/* enable mpc again in case of error */
-			mpc = 1;
-			rtt_status->mpc = 0;
-			err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc),
-				NULL, 0, TRUE);
+		if (rtt_status->pm_restore) {
+			pm = PM_FAST;
+			DHD_RTT_ERR(("pm_restore =%d func =%s \n",
+				rtt_status->pm_restore, __FUNCTION__));
+			err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
+			if (err) {
+				DHD_RTT_ERR(("Failed to set PM \n"));
+			} else {
+				rtt_status->pm_restore = FALSE;
+			}
 		}
 	}
 	return err;
 }
+#endif /* WL_CFG80211 */
 
 int
 dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn)
@@ -1439,7 +2489,9 @@
 	rtt_status = GET_RTTSTATE(dhd);
 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
 	spin_lock_bh(&noti_list_lock);
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 	list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
+		GCC_DIAGNOSTIC_POP();
 		if (iter->noti_fn == noti_fn) {
 			goto exit;
 		}
@@ -1468,13 +2520,16 @@
 	rtt_status = GET_RTTSTATE(dhd);
 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
 	spin_lock_bh(&noti_list_lock);
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 	list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
+		GCC_DIAGNOSTIC_POP();
 		if (iter->noti_fn == noti_fn) {
 			cb = iter;
 			list_del(&cb->list);
 			break;
 		}
 	}
+
 	spin_unlock_bh(&noti_list_lock);
 	if (cb) {
 		kfree(cb);
@@ -1486,56 +2541,103 @@
 dhd_rtt_convert_rate_to_host(uint32 rspec)
 {
 	wifi_rate_t host_rate;
+	uint32 bandwidth;
 	memset(&host_rate, 0, sizeof(wifi_rate_t));
-	if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) {
+	if (RSPEC_ISLEGACY(rspec)) {
 		host_rate.preamble = 0;
-	} else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) {
+	} else if (RSPEC_ISHT(rspec)) {
 		host_rate.preamble = 2;
 		host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK;
-	} else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) {
+	} else if (RSPEC_ISVHT(rspec)) {
 		host_rate.preamble = 3;
 		host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK;
 		host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
 	}
-	host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1;
+
+	bandwidth = RSPEC_BW(rspec);
+	switch (bandwidth) {
+	case WL_RSPEC_BW_20MHZ:
+		host_rate.bw = RTT_RATE_20M;
+		break;
+	case WL_RSPEC_BW_40MHZ:
+		host_rate.bw = RTT_RATE_40M;
+		break;
+	case WL_RSPEC_BW_80MHZ:
+		host_rate.bw = RTT_RATE_80M;
+		break;
+	case WL_RSPEC_BW_160MHZ:
+		host_rate.bw = RTT_RATE_160M;
+		break;
+	default:
+		host_rate.bw = RTT_RATE_20M;
+		break;
+	}
+
 	host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */
 	DHD_RTT(("bit rate : %d\n", host_rate.bitrate));
 	return host_rate;
 }
 
-
+#define FTM_FRAME_TYPES	{"SETUP", "TRIGGER", "TIMESTAMP"}
 static int
-dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len)
+dhd_rtt_convert_results_to_host_v1(rtt_result_t *rtt_result, const uint8 *p_data,
+	uint16 tlvid, uint16 len)
 {
+	int i;
 	int err = BCME_OK;
 	char eabuf[ETHER_ADDR_STR_LEN];
-	wl_proxd_rtt_result_t *p_data_info;
 	wl_proxd_result_flags_t flags;
 	wl_proxd_session_state_t session_state;
 	wl_proxd_status_t proxd_status;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
 	struct timespec64 ts;
-#else
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
 	struct timespec ts;
-#endif
+#endif /* LINUX_VER >= 2.6.39 */
 	uint32 ratespec;
 	uint32 avg_dist;
-	wl_proxd_rtt_sample_t *p_sample;
+	const wl_proxd_rtt_result_v1_t *p_data_info = NULL;
+	const wl_proxd_rtt_sample_v1_t *p_sample_avg = NULL;
+	const wl_proxd_rtt_sample_v1_t *p_sample = NULL;
 	wl_proxd_intvl_t rtt;
 	wl_proxd_intvl_t p_time;
+	uint16 num_rtt = 0, snr = 0, bitflips = 0;
+	wl_proxd_phy_error_t tof_phy_error = 0;
+	wl_proxd_phy_error_t tof_phy_tgt_error = 0;
+	wl_proxd_snr_t tof_target_snr = 0;
+	wl_proxd_bitflips_t tof_target_bitflips = 0;
+	int16 rssi = 0;
+	int32 dist = 0;
+	uint8 num_ftm = 0;
+	char *ftm_frame_types[] = FTM_FRAME_TYPES;
+	rtt_report_t *rtt_report = &(rtt_result->report);
+
+	BCM_REFERENCE(ftm_frame_types);
+	BCM_REFERENCE(dist);
+	BCM_REFERENCE(rssi);
+	BCM_REFERENCE(tof_target_bitflips);
+	BCM_REFERENCE(tof_target_snr);
+	BCM_REFERENCE(tof_phy_tgt_error);
+	BCM_REFERENCE(tof_phy_error);
+	BCM_REFERENCE(bitflips);
+	BCM_REFERENCE(snr);
+	BCM_REFERENCE(session_state);
+	BCM_REFERENCE(ftm_session_state_value_to_logstr);
 
 	NULL_CHECK(rtt_report, "rtt_report is NULL", err);
 	NULL_CHECK(p_data, "p_data is NULL", err);
 	DHD_RTT(("%s enter\n", __FUNCTION__));
-	p_data_info = (wl_proxd_rtt_result_t *) p_data;
+	p_data_info = (const wl_proxd_rtt_result_v1_t *) p_data;
 	/* unpack and format 'flags' for display */
 	flags = ltoh16_ua(&p_data_info->flags);
 
 	/* session state and status */
 	session_state = ltoh16_ua(&p_data_info->state);
 	proxd_status = ltoh32_ua(&p_data_info->status);
+	bcm_ether_ntoa((&(p_data_info->peer)), eabuf);
+	ftm_status_value_to_logstr(proxd_status);
 	DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n",
-		bcm_ether_ntoa((&(p_data_info->peer)), eabuf),
+		eabuf,
 		session_state,
 		ftm_session_state_value_to_logstr(session_state),
 		proxd_status,
@@ -1558,13 +2660,14 @@
 			p_data_info->num_ftm)); /* in a session */
 	}
 	/* show 'avg_rtt' sample */
-	p_sample = &p_data_info->avg_rtt;
+	p_sample_avg = &p_data_info->avg_rtt;
+	ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu));
 	DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d ratespec=0x%08x\n",
-		(int16) ltoh16_ua(&p_sample->rssi),
-		ltoh32_ua(&p_sample->rtt.intvl),
-		ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)),
+		(int16) ltoh16_ua(&p_sample_avg->rssi),
+		ltoh32_ua(&p_sample_avg->rtt.intvl),
+		ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu)),
 		ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10,
-		ltoh32_ua(&p_sample->ratespec)));
+		ltoh32_ua(&p_sample_avg->ratespec)));
 
 	/* set peer address */
 	rtt_report->addr = p_data_info->peer;
@@ -1578,8 +2681,10 @@
 	/* status */
 	rtt_report->status = ftm_get_statusmap_info(proxd_status,
 			&ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info));
+
 	/* rssi (0.5db) */
-	rtt_report->rssi = (int16)ltoh16_ua(&p_data_info->avg_rtt.rssi) * 2;
+	rtt_report->rssi = ABS((wl_proxd_rssi_t)ltoh16_ua(&p_data_info->avg_rtt.rssi)) * 2;
+
 	/* rx rate */
 	ratespec = ltoh32_ua(&p_data_info->avg_rtt.ratespec);
 	rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec);
@@ -1592,26 +2697,24 @@
 	/* rtt_sd */
 	rtt.tmu = ltoh16_ua(&p_data_info->avg_rtt.rtt.tmu);
 	rtt.intvl = ltoh32_ua(&p_data_info->avg_rtt.rtt.intvl);
-	rtt_report->rtt = FTM_INTVL2NSEC(&rtt) * 10; /* nano -> 0.1 nano */
+	rtt_report->rtt = (wifi_timespan)FTM_INTVL2NSEC(&rtt) * 1000; /* nano -> pico seconds */
 	rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */
 	DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt));
 	DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi));
 
 	/* average distance */
 	if (avg_dist != FTM_INVALID) {
-		rtt_report->distance = (avg_dist >> 8) * 100; /* meter -> cm */
-		rtt_report->distance += (avg_dist & 0xff) * 100 / 256;
+		rtt_report->distance = (avg_dist >> 8) * 1000; /* meter -> mm */
+		rtt_report->distance += (avg_dist & 0xff) * 1000 / 256;
 	} else {
 		rtt_report->distance = FTM_INVALID;
 	}
 	/* time stamp */
 	/* get the time elapsed from boot time */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
-	ktime_get_boottime_ts64(&ts);
-#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
 	get_monotonic_boottime(&ts);
-#endif
 	rtt_report->ts = (uint64)TIMESPEC_TO_US(ts);
+#endif /* LINUX_VER >= 2.6.39 */
 
 	if (proxd_status == WL_PROXD_E_REMOTE_FAIL) {
 		/* retry time  after failure */
@@ -1631,31 +2734,741 @@
 			ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu))));
 		DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report->burst_duration));
 	}
+
+	/* display detail if available */
+	num_rtt = ltoh16_ua(&p_data_info->num_rtt);
+	if (num_rtt > 0) {
+		DHD_RTT((">\tnum rtt: %d samples\n", num_rtt));
+		p_sample = &p_data_info->rtt[0];
+		for (i = 0; i < num_rtt; i++) {
+			snr = 0;
+			bitflips = 0;
+			tof_phy_error = 0;
+			tof_phy_tgt_error = 0;
+			tof_target_snr = 0;
+			tof_target_bitflips = 0;
+			rssi = 0;
+			dist = 0;
+			num_ftm = p_data_info->num_ftm;
+			/* FTM frames 1,4,7,11 have valid snr, rssi and bitflips */
+			if ((i % num_ftm) == 1) {
+				rssi = (wl_proxd_rssi_t) ltoh16_ua(&p_sample->rssi);
+				snr = (wl_proxd_snr_t) ltoh16_ua(&p_sample->snr);
+				bitflips = (wl_proxd_bitflips_t) ltoh16_ua(&p_sample->bitflips);
+				tof_phy_error =
+					(wl_proxd_phy_error_t)
+					ltoh32_ua(&p_sample->tof_phy_error);
+				tof_phy_tgt_error =
+					(wl_proxd_phy_error_t)
+					ltoh32_ua(&p_sample->tof_tgt_phy_error);
+				tof_target_snr =
+					(wl_proxd_snr_t)
+					ltoh16_ua(&p_sample->tof_tgt_snr);
+				tof_target_bitflips =
+					(wl_proxd_bitflips_t)
+					ltoh16_ua(&p_sample->tof_tgt_bitflips);
+				dist = ltoh32_ua(&p_sample->distance);
+			} else {
+				rssi = -1;
+				snr = 0;
+				bitflips = 0;
+				dist = 0;
+				tof_target_bitflips = 0;
+				tof_target_snr = 0;
+				tof_phy_tgt_error = 0;
+			}
+			DHD_RTT((">\t sample[%d]: id=%d rssi=%d snr=0x%x bitflips=%d"
+				" tof_phy_error %x tof_phy_tgt_error %x target_snr=0x%x"
+				" target_bitflips=%d dist=%d rtt=%d%s status %s"
+				" Type %s coreid=%d\n",
+				i, p_sample->id, rssi, snr,
+				bitflips, tof_phy_error, tof_phy_tgt_error,
+				tof_target_snr,
+				tof_target_bitflips, dist,
+				ltoh32_ua(&p_sample->rtt.intvl),
+				ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)),
+				ftm_status_value_to_logstr(ltoh32_ua(&p_sample->status)),
+				ftm_frame_types[i % num_ftm], p_sample->coreid));
+			p_sample++;
+		}
+	}
 	return err;
 }
+
+static int
+dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data,
+	uint16 tlvid, uint16 len)
+{
+	int i;
+	int err = BCME_OK;
+	char eabuf[ETHER_ADDR_STR_LEN];
+	wl_proxd_result_flags_t flags;
+	wl_proxd_session_state_t session_state;
+	wl_proxd_status_t proxd_status;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
+	struct timespec64 ts;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+	struct timespec ts;
+#endif /* LINUX_VER >= 2.6.39 */
+	uint32 ratespec;
+	uint32 avg_dist;
+	const wl_proxd_rtt_result_v2_t *p_data_info = NULL;
+	const wl_proxd_rtt_sample_v2_t *p_sample_avg = NULL;
+	const wl_proxd_rtt_sample_v2_t *p_sample = NULL;
+	uint16 num_rtt = 0;
+	wl_proxd_intvl_t rtt;
+	wl_proxd_intvl_t p_time;
+	uint16 snr = 0, bitflips = 0;
+	wl_proxd_phy_error_t tof_phy_error = 0;
+	wl_proxd_phy_error_t tof_phy_tgt_error = 0;
+	wl_proxd_snr_t tof_target_snr = 0;
+	wl_proxd_bitflips_t tof_target_bitflips = 0;
+	int16 rssi = 0;
+	int32 dist = 0;
+	uint32 chanspec = 0;
+	uint8 num_ftm = 0;
+	char *ftm_frame_types[] =  FTM_FRAME_TYPES;
+	rtt_report_t *rtt_report = &(rtt_result->report);
+
+	BCM_REFERENCE(ftm_frame_types);
+	BCM_REFERENCE(dist);
+	BCM_REFERENCE(rssi);
+	BCM_REFERENCE(tof_target_bitflips);
+	BCM_REFERENCE(tof_target_snr);
+	BCM_REFERENCE(tof_phy_tgt_error);
+	BCM_REFERENCE(tof_phy_error);
+	BCM_REFERENCE(bitflips);
+	BCM_REFERENCE(snr);
+	BCM_REFERENCE(chanspec);
+	BCM_REFERENCE(session_state);
+	BCM_REFERENCE(ftm_session_state_value_to_logstr);
+
+	NULL_CHECK(rtt_report, "rtt_report is NULL", err);
+	NULL_CHECK(p_data, "p_data is NULL", err);
+	DHD_RTT(("%s enter\n", __FUNCTION__));
+	p_data_info = (const wl_proxd_rtt_result_v2_t *) p_data;
+	/* unpack and format 'flags' for display */
+	flags = ltoh16_ua(&p_data_info->flags);
+	/* session state and status */
+	session_state = ltoh16_ua(&p_data_info->state);
+	proxd_status = ltoh32_ua(&p_data_info->status);
+	bcm_ether_ntoa((&(p_data_info->peer)), eabuf);
+
+	if (proxd_status != BCME_OK) {
+		DHD_RTT_ERR((">\tTarget(%s) session state=%d(%s), status=%d(%s) "
+			"num_meas_ota %d num_valid_rtt %d result_flags %x\n",
+			eabuf, session_state,
+			ftm_session_state_value_to_logstr(session_state),
+			proxd_status, ftm_status_value_to_logstr(proxd_status),
+			p_data_info->num_meas, p_data_info->num_valid_rtt,
+			p_data_info->flags));
+	} else {
+		DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n",
+		eabuf, session_state,
+		ftm_session_state_value_to_logstr(session_state),
+		proxd_status, ftm_status_value_to_logstr(proxd_status)));
+	}
+	/* show avg_dist (1/256m units), burst_num */
+	avg_dist = ltoh32_ua(&p_data_info->avg_dist);
+	if (avg_dist == 0xffffffff) {	/* report 'failure' case */
+		DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n",
+		ltoh16_ua(&p_data_info->burst_num),
+		p_data_info->num_valid_rtt)); /* in a session */
+		avg_dist = FTM_INVALID;
+	} else {
+		DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d "
+			"num_meas_ota=%d, result_flags=%x\n", avg_dist >> 8, /* 1/256m units */
+			((avg_dist & 0xff) * 625) >> 4,
+			ltoh16_ua(&p_data_info->burst_num),
+			p_data_info->num_valid_rtt,
+			p_data_info->num_ftm, p_data_info->num_meas,
+			p_data_info->flags)); /* in a session */
+	}
+	rtt_result->rtt_detail.num_ota_meas = p_data_info->num_meas;
+	rtt_result->rtt_detail.result_flags = p_data_info->flags;
+	/* show 'avg_rtt' sample */
+	/* in v2, avg_rtt is the first element of the variable rtt[] */
+	p_sample_avg = &p_data_info->rtt[0];
+	ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu));
+	DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d"
+		"ratespec=0x%08x chanspec=0x%08x\n",
+		(int16) ltoh16_ua(&p_sample_avg->rssi),
+		ltoh32_ua(&p_sample_avg->rtt.intvl),
+		ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu)),
+		ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10,
+		ltoh32_ua(&p_sample_avg->ratespec),
+		ltoh32_ua(&p_sample_avg->chanspec)));
+
+	/* set peer address */
+	rtt_report->addr = p_data_info->peer;
+
+	/* burst num */
+	rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num);
+
+	/* success num */
+	rtt_report->success_num = p_data_info->num_valid_rtt;
+
+	/* num-ftm configured */
+	rtt_report->ftm_num = p_data_info->num_ftm;
+
+	/* actual number of FTM supported by peer */
+	rtt_report->num_per_burst_peer = p_data_info->num_ftm;
+	rtt_report->negotiated_burst_num = p_data_info->num_ftm;
+
+	/* status */
+	rtt_report->status = ftm_get_statusmap_info(proxd_status,
+			&ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info));
+
+	/* Framework expects status as SUCCESS else all results will be
+	* set to zero even if we have partial valid result.
+	* So setting status as SUCCESS if we have a valid_rtt
+	* On burst timeout we stop burst with "timeout" reason and
+	* on msch end we set status as "cancel"
+	*/
+	if ((proxd_status == WL_PROXD_E_TIMEOUT ||
+		proxd_status == WL_PROXD_E_CANCELED) &&
+		rtt_report->success_num) {
+		rtt_report->status = RTT_STATUS_SUCCESS;
+	}
+
+	/* rssi (0.5db) */
+	rtt_report->rssi = ABS((wl_proxd_rssi_t)ltoh16_ua(&p_sample_avg->rssi)) * 2;
+
+	/* rx rate */
+	ratespec = ltoh32_ua(&p_sample_avg->ratespec);
+	rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec);
+
+	/* tx rate */
+	if (flags & WL_PROXD_RESULT_FLAG_VHTACK) {
+		rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0x2010010);
+	} else {
+		rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0xc);
+	}
+
+	/* rtt_sd */
+	rtt.tmu = ltoh16_ua(&p_sample_avg->rtt.tmu);
+	rtt.intvl = ltoh32_ua(&p_sample_avg->rtt.intvl);
+	rtt_report->rtt = (wifi_timespan)FTM_INTVL2NSEC(&rtt) * 1000; /* nano -> pico seconds */
+	rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */
+	DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt));
+	DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi));
+
+	/* average distance */
+	if (avg_dist != FTM_INVALID) {
+		rtt_report->distance = (avg_dist >> 8) * 1000; /* meter -> mm */
+		rtt_report->distance += (avg_dist & 0xff) * 1000 / 256;
+		/* rtt_sd is in 0.1 ns.
+		* host needs distance_sd in milli mtrs
+		* (0.1 * rtt_sd/2 * 10^-9) * C * 1000
+		*/
+		rtt_report->distance_sd = rtt_report->rtt_sd * 15; /* mm */
+	} else {
+		rtt_report->distance = FTM_INVALID;
+	}
+	/* time stamp */
+	/* get the time elapsed from boot time */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+	get_monotonic_boottime(&ts);
+	rtt_report->ts = (uint64)TIMESPEC_TO_US(ts);
+#endif /* LINUX_VER >= 2.6.39 */
+
+	if (proxd_status == WL_PROXD_E_REMOTE_FAIL) {
+		/* retry time  after failure */
+		p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl);
+		p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu);
+		rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */
+		DHD_RTT((">\tretry_after: %d%s\n",
+			ltoh32_ua(&p_data_info->u.retry_after.intvl),
+			ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu))));
+	} else {
+		/* burst duration */
+		p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl);
+		p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu);
+		rtt_report->burst_duration =  FTM_INTVL2MSEC(&p_time); /* s -> ms */
+		DHD_RTT((">\tburst_duration: %d%s\n",
+			ltoh32_ua(&p_data_info->u.burst_duration.intvl),
+			ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu))));
+		DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report->burst_duration));
+	}
+	/* display detail if available */
+	num_rtt = ltoh16_ua(&p_data_info->num_rtt);
+	if (num_rtt > 0) {
+		DHD_RTT((">\tnum rtt: %d samples\n", num_rtt));
+		p_sample = &p_data_info->rtt[1];
+		for (i = 0; i < num_rtt; i++) {
+			snr = 0;
+			bitflips = 0;
+			tof_phy_error = 0;
+			tof_phy_tgt_error = 0;
+			tof_target_snr = 0;
+			tof_target_bitflips = 0;
+			rssi = 0;
+			dist = 0;
+			num_ftm = p_data_info->num_ftm;
+			/* FTM frames 1,4,7,11 have valid snr, rssi and bitflips */
+			if ((i % num_ftm) == 1) {
+				rssi = (wl_proxd_rssi_t) ltoh16_ua(&p_sample->rssi);
+				snr = (wl_proxd_snr_t) ltoh16_ua(&p_sample->snr);
+				bitflips = (wl_proxd_bitflips_t) ltoh16_ua(&p_sample->bitflips);
+				tof_phy_error =
+					(wl_proxd_phy_error_t)
+					ltoh32_ua(&p_sample->tof_phy_error);
+				tof_phy_tgt_error =
+					(wl_proxd_phy_error_t)
+					ltoh32_ua(&p_sample->tof_tgt_phy_error);
+				tof_target_snr =
+					(wl_proxd_snr_t)
+					ltoh16_ua(&p_sample->tof_tgt_snr);
+				tof_target_bitflips =
+					(wl_proxd_bitflips_t)
+					ltoh16_ua(&p_sample->tof_tgt_bitflips);
+				dist = ltoh32_ua(&p_sample->distance);
+				chanspec = ltoh32_ua(&p_sample->chanspec);
+			} else {
+				rssi = -1;
+				snr = 0;
+				bitflips = 0;
+				dist = 0;
+				tof_target_bitflips = 0;
+				tof_target_snr = 0;
+				tof_phy_tgt_error = 0;
+			}
+			DHD_RTT((">\t sample[%d]: id=%d rssi=%d snr=0x%x bitflips=%d"
+				" tof_phy_error %x tof_phy_tgt_error %x target_snr=0x%x"
+				" target_bitflips=%d dist=%d rtt=%d%s status %s Type %s"
+				" coreid=%d chanspec=0x%08x\n",
+				i, p_sample->id, rssi, snr,
+				bitflips, tof_phy_error, tof_phy_tgt_error,
+				tof_target_snr,
+				tof_target_bitflips, dist,
+				ltoh32_ua(&p_sample->rtt.intvl),
+				ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)),
+				ftm_status_value_to_logstr(ltoh32_ua(&p_sample->status)),
+				ftm_frame_types[i % num_ftm], p_sample->coreid,
+				chanspec));
+			p_sample++;
+		}
+	}
+	return err;
+}
+#ifdef WL_CFG80211
+/* Common API for handling Session End.
+* This API will flush out the results for a peer MAC.
+*
+* @For legacy FTM session, this API will be called
+* when legacy FTM_SESSION_END event is received.
+* @For legacy Nan-RTT , this API will be called when
+* we are cancelling the nan-ranging session or on
+* nan-ranging-end event.
+*/
+static void
+dhd_rtt_handle_rtt_session_end(dhd_pub_t *dhd)
+{
+
+	int idx;
+	struct rtt_noti_callback *iter;
+	rtt_results_header_t *entry, *next;
+	rtt_result_t *next2;
+	rtt_result_t *rtt_result;
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+
+	/* Cancel pending proxd timeout work if any */
+	if (delayed_work_pending(&rtt_status->proxd_timeout)) {
+		cancel_delayed_work(&rtt_status->proxd_timeout);
+	}
+
+	/* find next target to trigger RTT */
+	for (idx = (rtt_status->cur_idx + 1);
+		idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
+		/* skip the disabled device */
+		if (rtt_status->rtt_config.target_info[idx].disable) {
+			continue;
+		} else {
+			/* set the idx to cur_idx */
+			rtt_status->cur_idx = idx;
+			break;
+		}
+	}
+	if (idx < rtt_status->rtt_config.rtt_target_cnt) {
+		/* restart to measure RTT from next device */
+		DHD_INFO(("restart to measure rtt\n"));
+		schedule_work(&rtt_status->work);
+	} else {
+		DHD_RTT(("RTT_STOPPED\n"));
+		rtt_status->status = RTT_STOPPED;
+		/* notify the completed information to others */
+		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+		list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
+			iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache);
+		}
+		/* remove the rtt results in cache */
+		if (!list_empty(&rtt_status->rtt_results_cache)) {
+			/* Iterate rtt_results_header list */
+			list_for_each_entry_safe(entry, next,
+				&rtt_status->rtt_results_cache, list) {
+				list_del(&entry->list);
+				/* Iterate rtt_result list */
+				list_for_each_entry_safe(rtt_result, next2,
+					&entry->result_list, list) {
+					list_del(&rtt_result->list);
+					kfree(rtt_result);
+				}
+				kfree(entry);
+			}
+		}
+		GCC_DIAGNOSTIC_POP();
+		/* reinitialize the HEAD */
+		INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
+		/* clear information for rtt_config */
+		rtt_status->rtt_config.rtt_target_cnt = 0;
+		memset_s(rtt_status->rtt_config.target_info, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT),
+			0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
+		rtt_status->cur_idx = 0;
+	}
+}
+#endif /* WL_CFG80211 */
+
+#ifdef WL_CFG80211
+static int
+dhd_rtt_create_failure_result(rtt_status_info_t *rtt_status,
+	struct ether_addr *addr)
+{
+	rtt_results_header_t *rtt_results_header = NULL;
+	rtt_target_info_t *rtt_target_info;
+	int ret = BCME_OK;
+	rtt_result_t *rtt_result;
+
+	/* allocate new header for rtt_results */
+	rtt_results_header = (rtt_results_header_t *)MALLOCZ(rtt_status->dhd->osh,
+		sizeof(rtt_results_header_t));
+	if (!rtt_results_header) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+	rtt_target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
+	/* Initialize the head of list for rtt result */
+	INIT_LIST_HEAD(&rtt_results_header->result_list);
+	/* same src and dest len */
+	(void)memcpy_s(&rtt_results_header->peer_mac,
+		ETHER_ADDR_LEN, addr, ETHER_ADDR_LEN);
+	list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache);
+
+	/* allocate rtt_results for new results */
+	rtt_result = (rtt_result_t *)MALLOCZ(rtt_status->dhd->osh,
+		sizeof(rtt_result_t));
+	if (!rtt_result) {
+		ret = -ENOMEM;
+		kfree(rtt_results_header);
+		goto exit;
+	}
+	/* fill out the results from the configuration param */
+	rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst;
+	rtt_result->report.type = RTT_TWO_WAY;
+	DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num));
+	rtt_result->report_len = RTT_REPORT_SIZE;
+	rtt_result->report.status = RTT_STATUS_FAIL_NO_RSP;
+	/* same src and dest len */
+	(void)memcpy_s(&rtt_result->report.addr, ETHER_ADDR_LEN,
+		&rtt_target_info->addr, ETHER_ADDR_LEN);
+	rtt_result->report.distance = FTM_INVALID;
+	list_add_tail(&rtt_result->list, &rtt_results_header->result_list);
+	rtt_results_header->result_cnt++;
+	rtt_results_header->result_tot_len += rtt_result->report_len;
+exit:
+	return ret;
+}
+
+static bool
+dhd_rtt_get_report_header(rtt_status_info_t *rtt_status,
+	rtt_results_header_t **rtt_results_header, struct ether_addr *addr)
+{
+	rtt_results_header_t *entry;
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+	/* find a rtt_report_header for this mac address */
+	list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) {
+		GCC_DIAGNOSTIC_POP();
+		if (!memcmp(&entry->peer_mac, addr, ETHER_ADDR_LEN))  {
+			/* found a rtt_report_header for peer_mac in the list */
+			if (rtt_results_header) {
+				*rtt_results_header = entry;
+			}
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+int
+dhd_rtt_handle_nan_rtt_session_end(dhd_pub_t *dhd, struct ether_addr *peer)
+{
+	bool is_new = TRUE;
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+	mutex_lock(&rtt_status->rtt_mutex);
+	is_new = !dhd_rtt_get_report_header(rtt_status, NULL, peer);
+
+	if (is_new) { /* no FTM result..create failure result */
+		dhd_rtt_create_failure_result(rtt_status, peer);
+	}
+	dhd_rtt_handle_rtt_session_end(dhd);
+	mutex_unlock(&rtt_status->rtt_mutex);
+	return BCME_OK;
+}
+#endif /* WL_CFG80211 */
+
+static bool
+dhd_rtt_is_valid_measurement(rtt_result_t *rtt_result)
+{
+	bool ret = FALSE;
+
+	if (rtt_result && (rtt_result->report.success_num != 0)) {
+		ret = TRUE;
+	}
+	return ret;
+}
+
+static int
+dhd_rtt_parse_result_event(wl_proxd_event_t *proxd_ev_data,
+	int tlvs_len, rtt_result_t *rtt_result)
+{
+	int ret = BCME_OK;
+
+	/* unpack TLVs and invokes the cbfn to print the event content TLVs */
+	ret = bcm_unpack_xtlv_buf((void *) rtt_result,
+			(uint8 *)&proxd_ev_data->tlvs[0], tlvs_len,
+			BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn);
+	if (ret != BCME_OK) {
+		DHD_RTT_ERR(("%s : Failed to unpack xtlv for an event\n",
+			__FUNCTION__));
+		goto exit;
+	}
+	/* fill out the results from the configuration param */
+	rtt_result->report.type = RTT_TWO_WAY;
+	DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num));
+	rtt_result->report_len = RTT_REPORT_SIZE;
+	rtt_result->detail_len = sizeof(rtt_result->rtt_detail);
+
+exit:
+	return ret;
+
+}
+
+static int
+dhd_rtt_handle_directed_rtt_burst_end(dhd_pub_t *dhd, struct ether_addr *peer_addr,
+        wl_proxd_event_t *proxd_ev_data, int tlvs_len, rtt_result_t *rtt_result, bool is_nan)
+{
+	rtt_status_info_t *rtt_status;
+	rtt_results_header_t *rtt_results_header = NULL;
+	bool is_new = TRUE;
+	int ret = BCME_OK;
+	int err_at = 0;
+
+	rtt_status = GET_RTTSTATE(dhd);
+	is_new = !dhd_rtt_get_report_header(rtt_status,
+		&rtt_results_header, peer_addr);
+
+	if (tlvs_len > 0) {
+		if (is_new) {
+			/* allocate new header for rtt_results */
+			rtt_results_header = (rtt_results_header_t *)MALLOCZ(rtt_status->dhd->osh,
+				sizeof(rtt_results_header_t));
+			if (!rtt_results_header) {
+				ret = BCME_NORESOURCE;
+				err_at = 1;
+				goto exit;
+			}
+			/* Initialize the head of list for rtt result */
+			INIT_LIST_HEAD(&rtt_results_header->result_list);
+			/* same src and header len */
+			(void)memcpy_s(&rtt_results_header->peer_mac, ETHER_ADDR_LEN,
+				peer_addr, ETHER_ADDR_LEN);
+			list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache);
+		}
+
+		ret = dhd_rtt_parse_result_event(proxd_ev_data, tlvs_len, rtt_result);
+		if ((ret == BCME_OK) && ((!is_nan) ||
+			dhd_rtt_is_valid_measurement(rtt_result))) {
+			/*
+			 * Add to list, if non-nan RTT (legacy) or
+			 * valid measurement in nan rtt case
+			 */
+			list_add_tail(&rtt_result->list, &rtt_results_header->result_list);
+			rtt_results_header->result_cnt++;
+			rtt_results_header->result_tot_len += rtt_result->report_len +
+				rtt_result->detail_len;
+		} else {
+			err_at = 2;
+			if (ret == BCME_OK) {
+				/* Case for nan rtt invalid measurement */
+				ret = BCME_ERROR;
+				err_at = 3;
+			}
+			goto exit;
+		}
+	} else {
+		ret = BCME_ERROR;
+		err_at = 4;
+		goto exit;
+	}
+
+exit:
+	if (ret != BCME_OK) {
+		DHD_RTT_ERR(("dhd_rtt_handle_directed_rtt_burst_end: failed, "
+			" ret = %d, err_at = %d\n", ret, err_at));
+		if (rtt_results_header) {
+			list_del(&rtt_results_header->list);
+			kfree(rtt_results_header);
+			rtt_results_header = NULL;
+		}
+	}
+	return ret;
+}
+
+#ifdef WL_NAN
+static	void
+dhd_rtt_nan_range_report(struct bcm_cfg80211 *cfg,
+		rtt_result_t *rtt_result)
+{
+	wl_nan_ev_rng_rpt_ind_t range_res;
+	nan_ranging_inst_t *rng_inst = NULL;
+	dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
+	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
+
+	UNUSED_PARAMETER(range_res);
+
+	if (!dhd_rtt_is_valid_measurement(rtt_result)) {
+		/* Drop Invalid Measurements for NAN RTT report */
+		DHD_RTT(("dhd_rtt_nan_range_report: Drop Invalid Measurements\n"));
+		return;
+	}
+	bzero(&range_res, sizeof(range_res));
+	range_res.indication = 0;
+	range_res.dist_mm = rtt_result->report.distance;
+	/* same src and header len, ignoring ret val here */
+	(void)memcpy_s(&range_res.peer_m_addr, ETHER_ADDR_LEN,
+		&rtt_result->report.addr, ETHER_ADDR_LEN);
+	wl_cfgnan_process_range_report(cfg, &range_res);
+	/*
+	 * suspend geofence ranging for this target
+	 * and move to next target
+	 * after valid measurement for the target
+	 */
+	rng_inst = wl_cfgnan_check_for_ranging(cfg, &range_res.peer_m_addr);
+	if (rng_inst) {
+		wl_cfgnan_suspend_geofence_rng_session(bcmcfg_to_prmry_ndev(cfg),
+			&rng_inst->peer_addr, RTT_GEO_SUSPN_RANGE_RES_REPORTED, 0);
+		GEOFENCE_RTT_LOCK(rtt_status);
+		dhd_rtt_move_geofence_cur_target_idx_to_next(dhd);
+		GEOFENCE_RTT_UNLOCK(rtt_status);
+		wl_cfgnan_reset_geofence_ranging(cfg,
+			rng_inst, RTT_SCHED_RNG_RPT_GEOFENCE);
+	}
+}
+
+static int
+dhd_rtt_handle_nan_burst_end(dhd_pub_t *dhd, struct ether_addr *peer_addr,
+	wl_proxd_event_t *proxd_ev_data, int tlvs_len)
+{
+	struct net_device *ndev = NULL;
+	struct bcm_cfg80211 *cfg = NULL;
+	nan_ranging_inst_t *rng_inst = NULL;
+	rtt_status_info_t *rtt_status = NULL;
+	rtt_result_t *rtt_result = NULL;
+	bool is_geofence = FALSE;
+	int ret = BCME_OK;
+
+	ndev = dhd_linux_get_primary_netdev(dhd);
+	cfg =  wiphy_priv(ndev->ieee80211_ptr->wiphy);
+
+	rtt_status = GET_RTTSTATE(dhd);
+	NULL_CHECK(rtt_status, "rtt_status is NULL", ret);
+	NAN_MUTEX_LOCK();
+	mutex_lock(&rtt_status->rtt_mutex);
+
+	if ((cfg->nan_enable == FALSE) ||
+		ETHER_ISNULLADDR(peer_addr)) {
+		DHD_RTT_ERR(("Received Burst End with NULL ether addr, "
+			"or nan disable, nan_enable = %d\n", cfg->nan_enable));
+		ret = BCME_UNSUPPORTED;
+		goto exit;
+	}
+
+	rng_inst = wl_cfgnan_check_for_ranging(cfg, peer_addr);
+	if (rng_inst) {
+		is_geofence = (rng_inst->range_type
+			== RTT_TYPE_NAN_GEOFENCE);
+	} else {
+		DHD_RTT_ERR(("Received Burst End without Ranging Instance\n"));
+		ret = BCME_ERROR;
+		goto exit;
+	}
+
+	/* allocate rtt_results for new results */
+	rtt_result = (rtt_result_t *)MALLOCZ(dhd->osh, sizeof(rtt_result_t));
+	if (!rtt_result) {
+		ret = BCME_NORESOURCE;
+		goto exit;
+	}
+
+	if (is_geofence) {
+		ret = dhd_rtt_parse_result_event(proxd_ev_data, tlvs_len, rtt_result);
+		if (ret != BCME_OK) {
+			DHD_RTT_ERR(("avilog: dhd_rtt_handle_nan_burst_end: "
+				"dhd_rtt_parse_result_event failed\n"));
+			goto exit;
+		}
+	} else {
+		if (RTT_IS_STOPPED(rtt_status)) {
+			/* Ignore the Proxd event */
+			DHD_RTT((" event handler rtt is stopped \n"));
+			if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) {
+				DHD_RTT(("Device is target/Responder. Recv the event. \n"));
+			} else {
+				ret = BCME_UNSUPPORTED;
+				goto exit;
+			}
+		}
+		ret = dhd_rtt_handle_directed_rtt_burst_end(dhd, peer_addr,
+			proxd_ev_data, tlvs_len, rtt_result, TRUE);
+		if (ret != BCME_OK) {
+			goto exit;
+		}
+
+	}
+
+exit:
+	mutex_unlock(&rtt_status->rtt_mutex);
+	if (ret == BCME_OK) {
+		dhd_rtt_nan_range_report(cfg, rtt_result);
+	}
+	if (rtt_result &&
+		((ret != BCME_OK) || is_geofence)) {
+		kfree(rtt_result);
+		rtt_result = NULL;
+	}
+	NAN_MUTEX_UNLOCK();
+	return ret;
+}
+#endif /* WL_NAN */
 
 int
 dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
 {
 	int ret = BCME_OK;
 	int tlvs_len;
-	int idx;
 	uint16 version;
 	wl_proxd_event_t *p_event;
 	wl_proxd_event_type_t event_type;
 	wl_proxd_ftm_session_status_t session_status;
 	const ftm_strmap_entry_t *p_loginfo;
+	rtt_result_t *rtt_result;
+#ifdef WL_CFG80211
 	rtt_status_info_t *rtt_status;
-	rtt_target_info_t *rtt_target_info;
-	struct rtt_noti_callback *iter;
-	rtt_results_header_t *entry, *next, *rtt_results_header = NULL;
-	rtt_result_t *rtt_result, *next2;
-	gfp_t kflags;
+	rtt_results_header_t *rtt_results_header = NULL;
 	bool is_new = TRUE;
+#endif /* WL_CFG80211 */
 
+	DHD_RTT(("Enter %s \n", __FUNCTION__));
 	NULL_CHECK(dhd, "dhd is NULL", ret);
-	rtt_status = GET_RTTSTATE(dhd);
-	NULL_CHECK(rtt_status, "rtt_status is NULL", ret);
 
 	if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) {
 		DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__,
@@ -1664,46 +3477,37 @@
 	}
 	event_type = ntoh32_ua((void *)&event->event_type);
 	if (event_type != WLC_E_PROXD) {
-		DHD_ERROR((" failed event \n"));
+		DHD_RTT_ERR((" failed event \n"));
 		return -EINVAL;
 	}
 
 	if (!event_data) {
-		DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__));
+		DHD_RTT_ERR(("%s: event_data:NULL\n", __FUNCTION__));
 		return -EINVAL;
-	}
-
-	if (RTT_IS_STOPPED(rtt_status)) {
-		/* Ignore the Proxd event */
-		return ret;
 	}
 	p_event = (wl_proxd_event_t *) event_data;
 	version = ltoh16(p_event->version);
 	if (version < WL_PROXD_API_VERSION) {
-		DHD_ERROR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n",
+		DHD_RTT_ERR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n",
 			version, WL_PROXD_API_VERSION));
 		return ret;
 	}
-	if (!in_atomic()) {
-		mutex_lock(&rtt_status->rtt_mutex);
-	}
-	event_type = (wl_proxd_event_type_t) ltoh16(p_event->type);
 
-	kflags = in_softirq()? GFP_ATOMIC : GFP_KERNEL;
+	event_type = (wl_proxd_event_type_t) ltoh16(p_event->type);
 
 	DHD_RTT(("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x\n",
 		p_event->type, ntoh16(p_event->type), ltoh16(p_event->type)));
 	p_loginfo = ftm_get_event_type_loginfo(event_type);
 	if (p_loginfo == NULL) {
-		DHD_ERROR(("receive an invalid FTM event %d\n", event_type));
+		DHD_RTT_ERR(("receive an invalid FTM event %d\n", event_type));
 		ret = -EINVAL;
-		goto exit;	/* ignore this event */
+		return ret;	/* ignore this event */
 	}
 	/* get TLVs len, skip over event header */
 	if (ltoh16(p_event->len) < OFFSETOF(wl_proxd_event_t, tlvs)) {
-		DHD_ERROR(("invalid FTM event length:%d\n", ltoh16(p_event->len)));
+		DHD_RTT_ERR(("invalid FTM event length:%d\n", ltoh16(p_event->len)));
 		ret = -EINVAL;
-		goto exit;
+		return ret;
 	}
 	tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs);
 	DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n",
@@ -1713,17 +3517,38 @@
 		ltoh16(p_event->method),
 		ltoh16(p_event->sid),
 		tlvs_len));
-	rtt_target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
-	/* find a rtt_report_header for this mac address */
-	list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) {
-		 if (!memcmp(&entry->peer_mac, &event->addr, ETHER_ADDR_LEN))  {
-			/* found a rtt_report_header for peer_mac in the list */
-			is_new = FALSE;
-			rtt_results_header = entry;
-			break;
-		 }
+#ifdef WL_CFG80211
+#ifdef WL_NAN
+	if ((event_type == WL_PROXD_EVENT_BURST_END) &&
+			dhd_rtt_is_nan_peer(dhd, &event->addr)) {
+		DHD_RTT(("WL_PROXD_EVENT_BURST_END for NAN RTT\n"));
+		ret = dhd_rtt_handle_nan_burst_end(dhd, &event->addr, p_event, tlvs_len);
+		return ret;
 	}
+#endif /* WL_NAN */
 
+	rtt_status = GET_RTTSTATE(dhd);
+	NULL_CHECK(rtt_status, "rtt_status is NULL", ret);
+	mutex_lock(&rtt_status->rtt_mutex);
+
+	if (RTT_IS_STOPPED(rtt_status)) {
+		/* Ignore the Proxd event */
+		DHD_RTT((" event handler rtt is stopped \n"));
+		if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) {
+			DHD_RTT(("Device is target/Responder. Recv the event. \n"));
+		} else {
+			ret = BCME_NOTREADY;
+			goto exit;
+		}
+	}
+#endif /* WL_CFG80211 */
+
+#ifdef WL_CFG80211
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+	is_new = !dhd_rtt_get_report_header(rtt_status,
+		&rtt_results_header, &event->addr);
+	GCC_DIAGNOSTIC_POP();
+#endif /* WL_CFG80211 */
 	switch (event_type) {
 	case WL_PROXD_EVENT_SESSION_CREATE:
 		DHD_RTT(("WL_PROXD_EVENT_SESSION_CREATE\n"));
@@ -1735,143 +3560,55 @@
 		DHD_RTT(("WL_PROXD_EVENT_BURST_START\n"));
 		break;
 	case WL_PROXD_EVENT_BURST_END:
-		DHD_RTT(("WL_PROXD_EVENT_BURST_END\n"));
-		if (is_new) {
-			/* allocate new header for rtt_results */
-			rtt_results_header = kzalloc(sizeof(rtt_results_header_t), kflags);
-			if (!rtt_results_header) {
-				ret = -ENOMEM;
-				goto exit;
-			}
-			/* Initialize the head of list for rtt result */
-			INIT_LIST_HEAD(&rtt_results_header->result_list);
-			rtt_results_header->peer_mac = event->addr;
-			list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache);
+		DHD_RTT(("WL_PROXD_EVENT_BURST_END for Legacy RTT\n"));
+		/* allocate rtt_results for new legacy rtt results */
+		rtt_result = (rtt_result_t *)MALLOCZ(dhd->osh, sizeof(rtt_result_t));
+		if (!rtt_result) {
+			ret = -ENOMEM;
+			goto exit;
 		}
-		if (tlvs_len > 0) {
-			/* allocate rtt_results for new results */
-			rtt_result = kzalloc(sizeof(rtt_result_t), kflags);
-			if (!rtt_result) {
-				ret = -ENOMEM;
-				goto exit;
-			}
-			/* unpack TLVs and invokes the cbfn to print the event content TLVs */
-			ret = bcm_unpack_xtlv_buf((void *) &(rtt_result->report),
-				(uint8 *)&p_event->tlvs[0], tlvs_len,
-				BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn);
-			if (ret != BCME_OK) {
-				DHD_ERROR(("%s : Failed to unpack xtlv for an event\n",
-					__FUNCTION__));
-				goto exit;
-			}
-			/* fill out the results from the configuration param */
-			rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst;
-			rtt_result->report.type = RTT_TWO_WAY;
-			DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num));
-			rtt_result->report_len = RTT_REPORT_SIZE;
-
-			list_add_tail(&rtt_result->list, &rtt_results_header->result_list);
-			rtt_results_header->result_cnt++;
-			rtt_results_header->result_tot_len += rtt_result->report_len;
+		ret = dhd_rtt_handle_directed_rtt_burst_end(dhd, &event->addr,
+			p_event, tlvs_len, rtt_result, FALSE);
+		if (rtt_result && (ret != BCME_OK)) {
+			kfree(rtt_result);
+			rtt_result = NULL;
+			goto exit;
 		}
 		break;
 	case WL_PROXD_EVENT_SESSION_END:
-			DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n"));
+		DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n"));
+		if (dhd_rtt_is_nan_peer(dhd, &event->addr)) {
+			/*
+			 * Nothing to do for session end for nan peer
+			 * All taken care in burst end and nan rng rep
+			 */
+			break;
+		}
+#ifdef WL_CFG80211
 		if (!RTT_IS_ENABLED(rtt_status)) {
 			DHD_RTT(("Ignore the session end evt\n"));
 			goto exit;
 		}
+#endif /* WL_CFG80211 */
 		if (tlvs_len > 0) {
 			/* unpack TLVs and invokes the cbfn to print the event content TLVs */
 			ret = bcm_unpack_xtlv_buf((void *) &session_status,
 				(uint8 *)&p_event->tlvs[0], tlvs_len,
 				BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn);
 			if (ret != BCME_OK) {
-				DHD_ERROR(("%s : Failed to unpack xtlv for an event\n",
+				DHD_RTT_ERR(("%s : Failed to unpack xtlv for an event\n",
 					__FUNCTION__));
 				goto exit;
 			}
 		}
+#ifdef WL_CFG80211
 		/* In case of no result for the peer device, make fake result for error case */
 		if (is_new) {
-			/* allocate new header for rtt_results */
-			rtt_results_header = kzalloc(sizeof(rtt_results_header_t), GFP_KERNEL);
-			if (!rtt_results_header) {
-				ret = -ENOMEM;
-				goto exit;
-			}
-			/* Initialize the head of list for rtt result */
-			INIT_LIST_HEAD(&rtt_results_header->result_list);
-			rtt_results_header->peer_mac = event->addr;
-			list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache);
-
-			/* allocate rtt_results for new results */
-			rtt_result = kzalloc(sizeof(rtt_result_t), kflags);
-			if (!rtt_result) {
-				ret = -ENOMEM;
-				kfree(rtt_results_header);
-				goto exit;
-			}
-			/* fill out the results from the configuration param */
-			rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst;
-			rtt_result->report.type = RTT_TWO_WAY;
-			DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num));
-			rtt_result->report_len = RTT_REPORT_SIZE;
-			rtt_result->report.status = RTT_REASON_FAIL_NO_RSP;
-			rtt_result->report.addr = rtt_target_info->addr;
-			rtt_result->report.distance = FTM_INVALID;
-			list_add_tail(&rtt_result->list, &rtt_results_header->result_list);
-			rtt_results_header->result_cnt++;
-			rtt_results_header->result_tot_len += rtt_result->report_len;
+			dhd_rtt_create_failure_result(rtt_status, &event->addr);
 		}
-		/* find next target to trigger RTT */
-		for (idx = (rtt_status->cur_idx + 1);
-			idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
-			/* skip the disabled device */
-			if (rtt_status->rtt_config.target_info[idx].disable) {
-				continue;
-			} else {
-				/* set the idx to cur_idx */
-				rtt_status->cur_idx = idx;
-				break;
-			}
-		}
-		if (idx < rtt_status->rtt_config.rtt_target_cnt) {
-			/* restart to measure RTT from next device */
-			schedule_work(&rtt_status->work);
-		} else {
-			DHD_RTT(("RTT_STOPPED\n"));
-			rtt_status->status = RTT_STOPPED;
-			/* to turn on mpc mode */
-			schedule_work(&rtt_status->work);
-			/* notify the completed information to others */
-			list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
-				iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache);
-			}
-			/* remove the rtt results in cache */
-			if (!list_empty(&rtt_status->rtt_results_cache)) {
-				/* Iterate rtt_results_header list */
-				list_for_each_entry_safe(entry, next,
-					&rtt_status->rtt_results_cache, list) {
-					list_del(&entry->list);
-					/* Iterate rtt_result list */
-					list_for_each_entry_safe(rtt_result, next2,
-						&entry->result_list, list) {
-						list_del(&rtt_result->list);
-						kfree(rtt_result);
-					}
-					kfree(entry);
-				}
-			}
-
-			/* reinitialize the HEAD */
-			INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
-			/* clear information for rtt_config */
-			rtt_status->rtt_config.rtt_target_cnt = 0;
-			memset(rtt_status->rtt_config.target_info, 0,
-				TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
-			rtt_status->cur_idx = 0;
-		}
+		DHD_RTT(("\n Not Nan peer..proceed to notify result and restart\n"));
+		dhd_rtt_handle_rtt_session_end(dhd);
+#endif /* WL_CFG80211 */
 		break;
 	case WL_PROXD_EVENT_SESSION_RESTART:
 		DHD_RTT(("WL_PROXD_EVENT_SESSION_RESTART\n"));
@@ -1894,36 +3631,78 @@
 	case WL_PROXD_EVENT_RANGING:
 		DHD_RTT(("WL_PROXD_EVENT_RANGING\n"));
 		break;
+	case WL_PROXD_EVENT_COLLECT:
+		DHD_RTT(("WL_PROXD_EVENT_COLLECT\n"));
+		if (tlvs_len > 0) {
+			void *buffer = NULL;
+			if (!(buffer = (void *)MALLOCZ(dhd->osh, tlvs_len))) {
+				ret = -ENOMEM;
+				goto exit;
+			}
+			/* unpack TLVs and invokes the cbfn to print the event content TLVs */
+			ret = bcm_unpack_xtlv_buf(buffer,
+				(uint8 *)&p_event->tlvs[0], tlvs_len,
+				BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn);
+			kfree(buffer);
+			if (ret != BCME_OK) {
+				DHD_RTT_ERR(("%s : Failed to unpack xtlv for event %d\n",
+					__FUNCTION__, event_type));
+				goto exit;
+			}
+		}
+		break;
+	case WL_PROXD_EVENT_MF_STATS:
+		DHD_RTT(("WL_PROXD_EVENT_MF_STATS\n"));
+		if (tlvs_len > 0) {
+			void *buffer = NULL;
+			if (!(buffer = (void *)MALLOCZ(dhd->osh, tlvs_len))) {
+				ret = -ENOMEM;
+				goto exit;
+			}
+			/* unpack TLVs and invokes the cbfn to print the event content TLVs */
+			ret = bcm_unpack_xtlv_buf(buffer,
+				(uint8 *)&p_event->tlvs[0], tlvs_len,
+				BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn);
+			kfree(buffer);
+			if (ret != BCME_OK) {
+				DHD_RTT_ERR(("%s : Failed to unpack xtlv for event %d\n",
+					__FUNCTION__, event_type));
+				goto exit;
+			}
+		}
+		break;
 
 	default:
-		DHD_ERROR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type));
+		DHD_RTT_ERR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type));
 		break;
 	}
 exit:
-	if (!in_atomic()) {
-		mutex_unlock(&rtt_status->rtt_mutex);
-	}
+#ifdef WL_CFG80211
+	mutex_unlock(&rtt_status->rtt_mutex);
+#endif /* WL_CFG80211 */
 
 	return ret;
 }
 
+#ifdef WL_CFG80211
 static void
 dhd_rtt_work(struct work_struct *work)
 {
 	rtt_status_info_t *rtt_status;
 	dhd_pub_t *dhd;
+
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 	rtt_status = container_of(work, rtt_status_info_t, work);
-	if (rtt_status == NULL) {
-		DHD_ERROR(("%s : rtt_status is NULL\n", __FUNCTION__));
-		return;
-	}
+	GCC_DIAGNOSTIC_POP();
+
 	dhd = rtt_status->dhd;
 	if (dhd == NULL) {
-		DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__));
+		DHD_RTT_ERR(("%s : dhd is NULL\n", __FUNCTION__));
 		return;
 	}
 	(void) dhd_rtt_start(dhd);
 }
+#endif /* WL_CFG80211 */
 
 int
 dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa)
@@ -1935,29 +3714,22 @@
 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
 	NULL_CHECK(capa, "capa is NULL", err);
 	bzero(capa, sizeof(rtt_capabilities_t));
-	switch (rtt_status->rtt_capa.proto) {
-	case RTT_CAP_ONE_WAY:
-		capa->rtt_one_sided_supported = 1;
-		break;
-	case RTT_CAP_FTM_WAY:
-		capa->rtt_ftm_supported = 1;
-		break;
-	}
 
-	switch (rtt_status->rtt_capa.feature) {
-	case RTT_FEATURE_LCI:
+	/* set rtt capabilities */
+	if (rtt_status->rtt_capa.proto & RTT_CAP_ONE_WAY)
+		capa->rtt_one_sided_supported = 1;
+	if (rtt_status->rtt_capa.proto & RTT_CAP_FTM_WAY)
+		capa->rtt_ftm_supported = 1;
+
+	if (rtt_status->rtt_capa.feature & RTT_FEATURE_LCI)
 		capa->lci_support = 1;
-		break;
-	case RTT_FEATURE_LCR:
+	if (rtt_status->rtt_capa.feature & RTT_FEATURE_LCR)
 		capa->lcr_support = 1;
-		break;
-	case RTT_FEATURE_PREAMBLE:
+	if (rtt_status->rtt_capa.feature & RTT_FEATURE_PREAMBLE)
 		capa->preamble_support = 1;
-		break;
-	case RTT_FEATURE_BW:
+	if (rtt_status->rtt_capa.feature & RTT_FEATURE_BW)
 		capa->bw_support = 1;
-		break;
-	}
+
 	/* bit mask */
 	capa->preamble_support = rtt_status->rtt_capa.preamble;
 	capa->bw_support = rtt_status->rtt_capa.bw;
@@ -1965,44 +3737,223 @@
 	return err;
 }
 
+#ifdef WL_CFG80211
+int
+dhd_rtt_avail_channel(dhd_pub_t *dhd, wifi_channel_info *channel_info)
+{
+	u32 chanspec = 0;
+	int err = BCME_OK;
+	chanspec_t c = 0;
+	u32 channel;
+	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
+
+	if ((err = wldev_iovar_getint(dev, "chanspec",
+		(s32 *)&chanspec)) == BCME_OK) {
+		c = (chanspec_t)dtoh32(chanspec);
+		c = wl_chspec_driver_to_host(c);
+		channel  = wf_chspec_ctlchan(c);
+		DHD_RTT((" control channel is %d \n", channel));
+		if (CHSPEC_IS20(c)) {
+			channel_info->width = WIFI_CHAN_WIDTH_20;
+			DHD_RTT((" band is 20 \n"));
+		} else if (CHSPEC_IS40(c)) {
+			channel_info->width = WIFI_CHAN_WIDTH_40;
+			DHD_RTT(("band is 40 \n"));
+		} else {
+			channel_info->width = WIFI_CHAN_WIDTH_80;
+			DHD_RTT(("band is 80 \n"));
+		}
+		if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
+			(channel <= CH_MAX_2G_CHANNEL)) {
+			channel_info->center_freq =
+				ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
+		} else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
+			channel_info->center_freq =
+				ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
+		}
+		if ((channel_info->width == WIFI_CHAN_WIDTH_80) ||
+			(channel_info->width == WIFI_CHAN_WIDTH_40)) {
+			channel = CHSPEC_CHANNEL(c);
+			channel_info->center_freq0 =
+				ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
+		}
+	} else {
+		DHD_RTT_ERR(("Failed to get the chanspec \n"));
+	}
+	return err;
+}
+
+int
+dhd_rtt_enable_responder(dhd_pub_t *dhd, wifi_channel_info *channel_info)
+{
+	int err = BCME_OK;
+	char chanbuf[CHANSPEC_STR_LEN];
+	int pm = PM_OFF;
+	int ftm_cfg_cnt = 0;
+	chanspec_t chanspec;
+	wifi_channel_info_t channel;
+	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
+	ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS];
+	ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS];
+	rtt_status_info_t *rtt_status;
+
+	memset(&channel, 0, sizeof(channel));
+	BCM_REFERENCE(chanbuf);
+	NULL_CHECK(dhd, "dhd is NULL", err);
+	rtt_status = GET_RTTSTATE(dhd);
+	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
+	if (RTT_IS_STOPPED(rtt_status)) {
+		DHD_RTT(("STA responder/Target. \n"));
+	}
+	DHD_RTT(("Enter %s \n", __FUNCTION__));
+	if (!dhd_is_associated(dhd, 0, NULL)) {
+		if (channel_info) {
+			channel.width = channel_info->width;
+			channel.center_freq = channel_info->center_freq;
+			channel.center_freq0 = channel_info->center_freq;
+		}
+		else {
+			channel.width = WIFI_CHAN_WIDTH_80;
+			channel.center_freq = DEFAULT_FTM_FREQ;
+			channel.center_freq0 = DEFAULT_FTM_CNTR_FREQ0;
+		}
+		chanspec =  dhd_rtt_convert_to_chspec(channel);
+		DHD_RTT(("chanspec/channel set as %s for rtt.\n",
+			wf_chspec_ntoa(chanspec, chanbuf)));
+		err = wldev_iovar_setint(dev, "chanspec", chanspec);
+		if (err) {
+			DHD_RTT_ERR(("Failed to set the chanspec \n"));
+		}
+	}
+	rtt_status->pm = PM_OFF;
+	err = wldev_ioctl_get(dev, WLC_GET_PM, &rtt_status->pm, sizeof(rtt_status->pm));
+	DHD_RTT(("Current PM value read %d\n", rtt_status->pm));
+	if (err) {
+		DHD_RTT_ERR(("Failed to get the PM value \n"));
+	} else {
+		err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
+		if (err) {
+			DHD_RTT_ERR(("Failed to set the PM \n"));
+			rtt_status->pm_restore = FALSE;
+		} else {
+			rtt_status->pm_restore = TRUE;
+		}
+	}
+	if (!RTT_IS_ENABLED(rtt_status)) {
+		err = dhd_rtt_ftm_enable(dhd, TRUE);
+		if (err) {
+			DHD_RTT_ERR(("Failed to enable FTM (%d)\n", err));
+			goto exit;
+		}
+		DHD_RTT(("FTM enabled \n"));
+	}
+	rtt_status->status = RTT_ENABLED;
+	DHD_RTT(("Responder enabled \n"));
+	memset(ftm_configs, 0, sizeof(ftm_configs));
+	memset(ftm_params, 0, sizeof(ftm_params));
+	ftm_configs[ftm_cfg_cnt].enable = TRUE;
+	ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_TARGET;
+	rtt_status->flags = WL_PROXD_SESSION_FLAG_TARGET;
+	DHD_RTT(("Set the device as responder \n"));
+	err = dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS,
+		ftm_configs, ftm_cfg_cnt);
+exit:
+	if (err) {
+		rtt_status->status = RTT_STOPPED;
+		DHD_RTT_ERR(("rtt is stopped  %s \n", __FUNCTION__));
+		dhd_rtt_ftm_enable(dhd, FALSE);
+		DHD_RTT(("restoring the PM value \n"));
+		if (rtt_status->pm_restore) {
+			pm = PM_FAST;
+			err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
+			if (err) {
+				DHD_RTT_ERR(("Failed to restore PM \n"));
+			} else {
+				rtt_status->pm_restore = FALSE;
+			}
+		}
+	}
+	return err;
+}
+
+int
+dhd_rtt_cancel_responder(dhd_pub_t *dhd)
+{
+	int err = BCME_OK;
+	rtt_status_info_t *rtt_status;
+	int pm = 0;
+	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
+
+	NULL_CHECK(dhd, "dhd is NULL", err);
+	rtt_status = GET_RTTSTATE(dhd);
+	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
+	DHD_RTT(("Enter %s \n", __FUNCTION__));
+	err = dhd_rtt_ftm_enable(dhd, FALSE);
+	if (err) {
+		DHD_RTT_ERR(("failed to disable FTM (%d)\n", err));
+	}
+	rtt_status->status = RTT_STOPPED;
+	if (rtt_status->pm_restore) {
+		pm = PM_FAST;
+		DHD_RTT(("pm_restore =%d \n", rtt_status->pm_restore));
+		err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
+		if (err) {
+			DHD_RTT_ERR(("Failed to restore PM \n"));
+		} else {
+			rtt_status->pm_restore = FALSE;
+		}
+	}
+	return err;
+}
+#endif /* WL_CFG80211 */
+
 int
 dhd_rtt_init(dhd_pub_t *dhd)
 {
-	int err = BCME_OK, ret;
-	int32 up = 1;
+	int err = BCME_OK;
+#ifdef WL_CFG80211
+	int ret;
+	int32 drv_up = 1;
 	int32 version;
 	rtt_status_info_t *rtt_status;
+	ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS];
+	int ftm_param_cnt = 0;
+
 	NULL_CHECK(dhd, "dhd is NULL", err);
 	if (dhd->rtt_state) {
 		return err;
 	}
-	dhd->rtt_state = kzalloc(sizeof(rtt_status_info_t), GFP_KERNEL);
+	dhd->rtt_state = (rtt_status_info_t *)MALLOCZ(dhd->osh,
+		sizeof(rtt_status_info_t));
 	if (dhd->rtt_state == NULL) {
 		err = BCME_NOMEM;
-		DHD_ERROR(("%s : failed to create rtt_state\n", __FUNCTION__));
+		DHD_RTT_ERR(("%s : failed to create rtt_state\n", __FUNCTION__));
 		return err;
 	}
 	bzero(dhd->rtt_state, sizeof(rtt_status_info_t));
 	rtt_status = GET_RTTSTATE(dhd);
 	rtt_status->rtt_config.target_info =
-			kzalloc(TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT), GFP_KERNEL);
+			(rtt_target_info_t *)MALLOCZ(dhd->osh,
+			TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
 	if (rtt_status->rtt_config.target_info == NULL) {
-		DHD_ERROR(("%s failed to allocate the target info for %d\n",
+		DHD_RTT_ERR(("%s failed to allocate the target info for %d\n",
 			__FUNCTION__, RTT_MAX_TARGET_CNT));
 		err = BCME_NOMEM;
 		goto exit;
 	}
 	rtt_status->dhd = dhd;
 	/* need to do WLC_UP  */
-	dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(int32), TRUE, 0);
+	dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&drv_up, sizeof(int32), TRUE, 0);
 
 	ret = dhd_rtt_get_version(dhd, &version);
 	if (ret == BCME_OK && (version == WL_PROXD_API_VERSION)) {
-		DHD_ERROR(("%s : FTM is supported\n", __FUNCTION__));
+		DHD_RTT_ERR(("%s : FTM is supported\n", __FUNCTION__));
 		/* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */
 		rtt_status->rtt_capa.proto |= RTT_CAP_FTM_WAY;
 
 		/* indicate to set tx rate */
+		rtt_status->rtt_capa.feature |= RTT_FEATURE_LCI;
+		rtt_status->rtt_capa.feature |= RTT_FEATURE_LCR;
 		rtt_status->rtt_capa.feature |= RTT_FEATURE_PREAMBLE;
 		rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_VHT;
 		rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_HT;
@@ -2014,30 +3965,48 @@
 		rtt_status->rtt_capa.bw |= RTT_BW_80;
 	} else {
 		if ((ret != BCME_OK) || (version == 0)) {
-			DHD_ERROR(("%s : FTM is not supported\n", __FUNCTION__));
+			DHD_RTT_ERR(("%s : FTM is not supported\n", __FUNCTION__));
 		} else {
-			DHD_ERROR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n",
+			DHD_RTT_ERR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n",
 				__FUNCTION__, WL_PROXD_API_VERSION, version));
 		}
 	}
 	/* cancel all of RTT request once we got the cancel request */
 	rtt_status->all_cancel = TRUE;
 	mutex_init(&rtt_status->rtt_mutex);
+	mutex_init(&rtt_status->geofence_mutex);
 	INIT_LIST_HEAD(&rtt_status->noti_fn_list);
 	INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
 	INIT_WORK(&rtt_status->work, dhd_rtt_work);
+	/* initialize proxd timer */
+	INIT_DELAYED_WORK(&rtt_status->proxd_timeout, dhd_rtt_timeout_work);
+#ifdef WL_NAN
+	/* initialize proxd retry timer */
+	INIT_DELAYED_WORK(&rtt_status->rtt_retry_timer, dhd_rtt_retry_work);
+	/* initialize non zero params of geofenne cfg */
+	rtt_status->geofence_cfg.cur_target_idx = DHD_RTT_INVALID_TARGET_INDEX;
+#endif /* WL_NAN */
+	/* Global proxd config */
+	ftm_params[ftm_param_cnt].event_mask = ((1 << WL_PROXD_EVENT_BURST_END) |
+		(1 << WL_PROXD_EVENT_SESSION_END));
+	ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_EVENT_MASK;
+	dhd_rtt_ftm_config(dhd, 0, FTM_CONFIG_CAT_GENERAL,
+			ftm_params, ftm_param_cnt);
 exit:
 	if (err < 0) {
 		kfree(rtt_status->rtt_config.target_info);
 		kfree(dhd->rtt_state);
 	}
+#endif /* WL_CFG80211 */
 	return err;
+
 }
 
 int
 dhd_rtt_deinit(dhd_pub_t *dhd)
 {
 	int err = BCME_OK;
+#ifdef WL_CFG80211
 	rtt_status_info_t *rtt_status;
 	rtt_results_header_t *rtt_header, *next;
 	rtt_result_t *rtt_result, *next2;
@@ -2046,7 +4015,9 @@
 	rtt_status = GET_RTTSTATE(dhd);
 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
 	rtt_status->status = RTT_STOPPED;
+	DHD_RTT(("rtt is stopped %s \n", __FUNCTION__));
 	/* clear evt callback list */
+	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
 	if (!list_empty(&rtt_status->noti_fn_list)) {
 		list_for_each_entry_safe(iter, iter2, &rtt_status->noti_fn_list, list) {
 			list_del(&iter->list);
@@ -2065,8 +4036,11 @@
 			kfree(rtt_header);
 		}
 	}
+	GCC_DIAGNOSTIC_POP();
+
 	kfree(rtt_status->rtt_config.target_info);
 	kfree(dhd->rtt_state);
 	dhd->rtt_state = NULL;
+#endif /* WL_CFG80211 */
 	return err;
 }

--
Gitblit v1.6.2