xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/dhd_rtt.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Broadcom Dongle Host Driver (DHD), RTT
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2020, Broadcom.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *      Unless you and Broadcom execute a separate written software license
7*4882a593Smuzhiyun  * agreement governing use of this software, this software is licensed to you
8*4882a593Smuzhiyun  * under the terms of the GNU General Public License version 2 (the "GPL"),
9*4882a593Smuzhiyun  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10*4882a593Smuzhiyun  * following added to such license:
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  *      As a special exception, the copyright holders of this software give you
13*4882a593Smuzhiyun  * permission to link this software with independent modules, and to copy and
14*4882a593Smuzhiyun  * distribute the resulting executable under terms of your choice, provided that
15*4882a593Smuzhiyun  * you also meet, for each linked independent module, the terms and conditions of
16*4882a593Smuzhiyun  * the license of that module.  An independent module is a module which is not
17*4882a593Smuzhiyun  * derived from this software.  The special exception does not apply to any
18*4882a593Smuzhiyun  * modifications of the software.
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * <<Broadcom-WL-IPTag/Dual:>>
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun #include <typedefs.h>
24*4882a593Smuzhiyun #include <osl.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include <epivers.h>
27*4882a593Smuzhiyun #include <bcmutils.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include <bcmendian.h>
30*4882a593Smuzhiyun #include <linuxver.h>
31*4882a593Smuzhiyun #include <linux/init.h>
32*4882a593Smuzhiyun #include <linux/kernel.h>
33*4882a593Smuzhiyun #include <linux/list.h>
34*4882a593Smuzhiyun #include <linux/sort.h>
35*4882a593Smuzhiyun #include <dngl_stats.h>
36*4882a593Smuzhiyun #include <wlioctl.h>
37*4882a593Smuzhiyun #include <bcmwifi_rspec.h>
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #include <bcmevent.h>
40*4882a593Smuzhiyun #include <dhd.h>
41*4882a593Smuzhiyun #include <dhd_rtt.h>
42*4882a593Smuzhiyun #include <dhd_dbg.h>
43*4882a593Smuzhiyun #include <dhd_bus.h>
44*4882a593Smuzhiyun #include <wldev_common.h>
45*4882a593Smuzhiyun #ifdef WL_CFG80211
46*4882a593Smuzhiyun #include <wl_cfg80211.h>
47*4882a593Smuzhiyun #endif /* WL_CFG80211 */
48*4882a593Smuzhiyun #ifdef WL_NAN
49*4882a593Smuzhiyun #include <wl_cfgnan.h>
50*4882a593Smuzhiyun #endif /* WL_NAN */
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun static DEFINE_SPINLOCK(noti_list_lock);
53*4882a593Smuzhiyun #define NULL_CHECK(p, s, err)  \
54*4882a593Smuzhiyun 	do { \
55*4882a593Smuzhiyun 		if (!(p)) { \
56*4882a593Smuzhiyun 			printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \
57*4882a593Smuzhiyun 			err = BCME_ERROR; \
58*4882a593Smuzhiyun 			return err; \
59*4882a593Smuzhiyun 		} \
60*4882a593Smuzhiyun 	} while (0)
61*4882a593Smuzhiyun #define DHD_RTT_CHK_SET_PARAM(param, param_cnt, targets, tlvid)  \
62*4882a593Smuzhiyun 	do { \
63*4882a593Smuzhiyun 		if ((param_cnt) >= FTM_MAX_PARAMS) { \
64*4882a593Smuzhiyun 			DHD_RTT_ERR(("Param cnt exceeded for FTM cfg iovar\n")); \
65*4882a593Smuzhiyun 			err = BCME_ERROR; \
66*4882a593Smuzhiyun 			goto exit; \
67*4882a593Smuzhiyun 		} else { \
68*4882a593Smuzhiyun 			dhd_rtt_set_ftm_config_param((param), &(param_cnt), \
69*4882a593Smuzhiyun 				(targets), (tlvid)); \
70*4882a593Smuzhiyun 		}\
71*4882a593Smuzhiyun 	} while (0)
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define TIMESPEC_TO_US(ts)  (((uint64)(ts).tv_sec * USEC_PER_SEC) + \
74*4882a593Smuzhiyun 							(ts).tv_nsec / NSEC_PER_USEC)
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #undef DHD_RTT_MEM
77*4882a593Smuzhiyun #undef DHD_RTT_ERR
78*4882a593Smuzhiyun #define DHD_RTT_MEM DHD_LOG_MEM
79*4882a593Smuzhiyun #define DHD_RTT_ERR DHD_ERROR
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun #define FTM_IOC_BUFSZ  2048	/* ioc buffsize for our module (> BCM_XTLV_HDR_SIZE) */
82*4882a593Smuzhiyun #define FTM_AVAIL_MAX_SLOTS		32
83*4882a593Smuzhiyun #define FTM_MAX_CONFIGS 10
84*4882a593Smuzhiyun #define FTM_MAX_PARAMS 20
85*4882a593Smuzhiyun #define FTM_DEFAULT_SESSION 1
86*4882a593Smuzhiyun #define FTM_BURST_TIMEOUT_UNIT 250 /* 250 ns */
87*4882a593Smuzhiyun #define FTM_INVALID -1
88*4882a593Smuzhiyun #define	FTM_DEFAULT_CNT_20M		24u
89*4882a593Smuzhiyun #define FTM_DEFAULT_CNT_40M		16u
90*4882a593Smuzhiyun #define FTM_DEFAULT_CNT_80M		11u
91*4882a593Smuzhiyun /* To handle congestion env, set max dur/timeout */
92*4882a593Smuzhiyun #define FTM_MAX_BURST_DUR_TMO_MS	128u
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun /* convenience macros */
95*4882a593Smuzhiyun #define FTM_TU2MICRO(_tu) ((uint64)(_tu) << 10)
96*4882a593Smuzhiyun #define FTM_MICRO2TU(_tu) ((uint64)(_tu) >> 10)
97*4882a593Smuzhiyun #define FTM_TU2MILLI(_tu) ((uint32)FTM_TU2MICRO(_tu) / 1000)
98*4882a593Smuzhiyun #define FTM_MICRO2MILLI(_x) ((uint32)(_x) / 1000)
99*4882a593Smuzhiyun #define FTM_MICRO2SEC(_x) ((uint32)(_x) / 1000000)
100*4882a593Smuzhiyun #define FTM_INTVL2NSEC(_intvl) ((uint32)ftm_intvl2nsec(_intvl))
101*4882a593Smuzhiyun #define FTM_INTVL2USEC(_intvl) ((uint32)ftm_intvl2usec(_intvl))
102*4882a593Smuzhiyun #define FTM_INTVL2MSEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000)
103*4882a593Smuzhiyun #define FTM_INTVL2SEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000000)
104*4882a593Smuzhiyun #define FTM_USECIN100MILLI(_usec) ((_usec) / 100000)
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /* broadcom specific set to have more accurate data */
107*4882a593Smuzhiyun #define ENABLE_VHT_ACK
108*4882a593Smuzhiyun #define CH_MIN_5G_CHANNEL 34
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun /* CUR ETH became obsolete with this major version onwards */
111*4882a593Smuzhiyun #define RTT_IOV_CUR_ETH_OBSOLETE 12
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun /*
114*4882a593Smuzhiyun  * Parallel RTT Sessions are supported
115*4882a593Smuzhiyun  * with this major and minor verion onwards
116*4882a593Smuzhiyun  */
117*4882a593Smuzhiyun #define RTT_PARALLEL_SSNS_SUPPORTED_MAJ_VER	14
118*4882a593Smuzhiyun #define RTT_PARALLEL_SSNS_SUPPORTED_MIN_VER	2
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun /* PROXD TIMEOUT */
121*4882a593Smuzhiyun #define DHD_RTT_TIMER_INTERVAL_MS		5000u
122*4882a593Smuzhiyun #define DHD_NAN_RTT_TIMER_INTERVAL_MS		20000u
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun #define DHD_NAN_RTT_MAX_SESSIONS		4u
125*4882a593Smuzhiyun #define DHD_NAN_RTT_MAX_SESSIONS_LEGACY		1u
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun struct rtt_noti_callback {
128*4882a593Smuzhiyun 	struct list_head list;
129*4882a593Smuzhiyun 	void *ctx;
130*4882a593Smuzhiyun 	dhd_rtt_compl_noti_fn noti_fn;
131*4882a593Smuzhiyun };
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun /* bitmask indicating which command groups; */
134*4882a593Smuzhiyun typedef enum {
135*4882a593Smuzhiyun 	FTM_SUBCMD_FLAG_METHOD	= 0x01,	/* FTM method command */
136*4882a593Smuzhiyun 	FTM_SUBCMD_FLAG_SESSION = 0x02,	/* FTM session command */
137*4882a593Smuzhiyun 	FTM_SUBCMD_FLAG_ALL = FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION
138*4882a593Smuzhiyun } ftm_subcmd_flag_t;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun /* proxd ftm config-category definition */
141*4882a593Smuzhiyun typedef enum {
142*4882a593Smuzhiyun 	FTM_CONFIG_CAT_GENERAL = 1,	/* generial configuration */
143*4882a593Smuzhiyun 	FTM_CONFIG_CAT_OPTIONS = 2,	/* 'config options' */
144*4882a593Smuzhiyun 	FTM_CONFIG_CAT_AVAIL = 3,	/* 'config avail' */
145*4882a593Smuzhiyun } ftm_config_category_t;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun typedef struct ftm_subcmd_info {
148*4882a593Smuzhiyun 	int16				version;    /* FTM version (optional) */
149*4882a593Smuzhiyun 	char				*name;		/* cmd-name string as cmdline input */
150*4882a593Smuzhiyun 	wl_proxd_cmd_t		cmdid;		/* cmd-id */
151*4882a593Smuzhiyun 	bcm_xtlv_unpack_cbfn_t *handler;  /* cmd response handler (optional) */
152*4882a593Smuzhiyun 	ftm_subcmd_flag_t	cmdflag; /* CMD flag (optional)  */
153*4882a593Smuzhiyun } ftm_subcmd_info_t;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun typedef struct ftm_config_options_info {
156*4882a593Smuzhiyun 	uint32 flags;				/* wl_proxd_flags_t/wl_proxd_session_flags_t */
157*4882a593Smuzhiyun 	bool enable;
158*4882a593Smuzhiyun } ftm_config_options_info_t;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun typedef struct ftm_config_param_info {
161*4882a593Smuzhiyun 	uint16		tlvid;	/* mapping TLV id for the item */
162*4882a593Smuzhiyun 	union {
163*4882a593Smuzhiyun 		uint32  chanspec;
164*4882a593Smuzhiyun 		struct ether_addr mac_addr;
165*4882a593Smuzhiyun 		wl_proxd_intvl_t data_intvl;
166*4882a593Smuzhiyun 		uint32 data32;
167*4882a593Smuzhiyun 		uint16 data16;
168*4882a593Smuzhiyun 		uint8 data8;
169*4882a593Smuzhiyun 		uint32 event_mask;
170*4882a593Smuzhiyun 	};
171*4882a593Smuzhiyun } ftm_config_param_info_t;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun /*
174*4882a593Smuzhiyun * definition for id-string mapping.
175*4882a593Smuzhiyun *   This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string
176*4882a593Smuzhiyun *   for debug-display or cmd-log-display
177*4882a593Smuzhiyun */
178*4882a593Smuzhiyun typedef struct ftm_strmap_entry {
179*4882a593Smuzhiyun 	int32		id;
180*4882a593Smuzhiyun 	char		*text;
181*4882a593Smuzhiyun } ftm_strmap_entry_t;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun typedef struct ftm_status_map_host_entry {
184*4882a593Smuzhiyun 	wl_proxd_status_t proxd_status;
185*4882a593Smuzhiyun 	rtt_reason_t rtt_reason;
186*4882a593Smuzhiyun } ftm_status_map_host_entry_t;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun static uint16
189*4882a593Smuzhiyun rtt_result_ver(uint16 tlvid, const uint8 *p_data);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun static int
192*4882a593Smuzhiyun dhd_rtt_convert_results_to_host_v1(rtt_result_t *rtt_result, const uint8 *p_data,
193*4882a593Smuzhiyun 	uint16 tlvid, uint16 len);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun static int
196*4882a593Smuzhiyun dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data,
197*4882a593Smuzhiyun 	uint16 tlvid, uint16 len);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun static wifi_rate_v1
200*4882a593Smuzhiyun dhd_rtt_convert_rate_to_host(uint32 ratespec);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun #if defined(WL_CFG80211) && defined(RTT_DEBUG)
203*4882a593Smuzhiyun const char *
204*4882a593Smuzhiyun ftm_cmdid_to_str(uint16 cmdid);
205*4882a593Smuzhiyun #endif /* WL_CFG80211 && RTT_DEBUG */
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun #ifdef WL_CFG80211
208*4882a593Smuzhiyun static int
209*4882a593Smuzhiyun dhd_rtt_start(dhd_pub_t *dhd);
210*4882a593Smuzhiyun static int dhd_rtt_create_failure_result(rtt_status_info_t *rtt_status,
211*4882a593Smuzhiyun 	struct ether_addr *addr);
212*4882a593Smuzhiyun static void dhd_rtt_handle_rtt_session_end(dhd_pub_t *dhd);
213*4882a593Smuzhiyun static void dhd_rtt_timeout_work(struct work_struct *work);
214*4882a593Smuzhiyun static bool dhd_rtt_get_report_header(rtt_status_info_t *rtt_status,
215*4882a593Smuzhiyun 	rtt_results_header_t **rtt_results_header, struct ether_addr *addr);
216*4882a593Smuzhiyun #ifdef WL_NAN
217*4882a593Smuzhiyun static void dhd_rtt_trigger_pending_targets_on_session_end(dhd_pub_t *dhd);
218*4882a593Smuzhiyun #endif /* WL_NAN */
219*4882a593Smuzhiyun #endif /* WL_CFG80211 */
220*4882a593Smuzhiyun static const int burst_duration_idx[]  = {0, 0, 1, 2, 4, 8, 16, 32, 64, 128, 0, 0};
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun /* ftm status mapping to host status */
223*4882a593Smuzhiyun static const ftm_status_map_host_entry_t ftm_status_map_info[] = {
224*4882a593Smuzhiyun 	{WL_PROXD_E_INCOMPLETE, RTT_STATUS_FAILURE},
225*4882a593Smuzhiyun 	{WL_PROXD_E_OVERRIDDEN, RTT_STATUS_FAILURE},
226*4882a593Smuzhiyun 	{WL_PROXD_E_ASAP_FAILED, RTT_STATUS_FAILURE},
227*4882a593Smuzhiyun 	{WL_PROXD_E_NOTSTARTED, RTT_STATUS_FAIL_NOT_SCHEDULED_YET},
228*4882a593Smuzhiyun 	{WL_PROXD_E_INVALIDMEAS, RTT_STATUS_FAIL_INVALID_TS},
229*4882a593Smuzhiyun 	{WL_PROXD_E_INCAPABLE, RTT_STATUS_FAIL_NO_CAPABILITY},
230*4882a593Smuzhiyun 	{WL_PROXD_E_MISMATCH, RTT_STATUS_FAILURE},
231*4882a593Smuzhiyun 	{WL_PROXD_E_DUP_SESSION, RTT_STATUS_FAILURE},
232*4882a593Smuzhiyun 	{WL_PROXD_E_REMOTE_FAIL, RTT_STATUS_FAILURE},
233*4882a593Smuzhiyun 	{WL_PROXD_E_REMOTE_INCAPABLE, RTT_STATUS_FAILURE},
234*4882a593Smuzhiyun 	{WL_PROXD_E_SCHED_FAIL, RTT_STATUS_FAIL_SCHEDULE},
235*4882a593Smuzhiyun 	{WL_PROXD_E_PROTO, RTT_STATUS_FAIL_PROTOCOL},
236*4882a593Smuzhiyun 	{WL_PROXD_E_EXPIRED, RTT_STATUS_FAILURE},
237*4882a593Smuzhiyun 	{WL_PROXD_E_TIMEOUT, RTT_STATUS_FAIL_TM_TIMEOUT},
238*4882a593Smuzhiyun 	{WL_PROXD_E_NOACK, RTT_STATUS_FAIL_NO_RSP},
239*4882a593Smuzhiyun 	{WL_PROXD_E_DEFERRED, RTT_STATUS_FAILURE},
240*4882a593Smuzhiyun 	{WL_PROXD_E_INVALID_SID, RTT_STATUS_FAILURE},
241*4882a593Smuzhiyun 	{WL_PROXD_E_REMOTE_CANCEL, RTT_STATUS_FAILURE},
242*4882a593Smuzhiyun 	{WL_PROXD_E_CANCELED, RTT_STATUS_ABORTED},
243*4882a593Smuzhiyun 	{WL_PROXD_E_INVALID_SESSION, RTT_STATUS_FAILURE},
244*4882a593Smuzhiyun 	{WL_PROXD_E_BAD_STATE, RTT_STATUS_FAILURE},
245*4882a593Smuzhiyun 	{WL_PROXD_E_ERROR, RTT_STATUS_FAILURE},
246*4882a593Smuzhiyun 	{WL_PROXD_E_OK, RTT_STATUS_SUCCESS}
247*4882a593Smuzhiyun };
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun static const ftm_strmap_entry_t ftm_event_type_loginfo[] = {
250*4882a593Smuzhiyun 	/* wl_proxd_event_type_t,		text-string */
251*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_NONE,			"none" },
252*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_SESSION_CREATE,	"session create" },
253*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_SESSION_START,		"session start" },
254*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_FTM_REQ,		"FTM req" },
255*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_BURST_START,		"burst start" },
256*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_BURST_END,		"burst end" },
257*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_SESSION_END,		"session end" },
258*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_SESSION_RESTART,	"session restart" },
259*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_BURST_RESCHED,		"burst rescheduled" },
260*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_SESSION_DESTROY,	"session destroy" },
261*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_RANGE_REQ,		"range request" },
262*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_FTM_FRAME,		"FTM frame" },
263*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_DELAY,			"delay" },
264*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_VS_INITIATOR_RPT,	"initiator-report " }, /* rx initiator-rpt */
265*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_RANGING,		"ranging " },
266*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_COLLECT,		"collect" },
267*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_MF_STATS,		"mf_stats" },
268*4882a593Smuzhiyun 	{ WL_PROXD_EVENT_START_WAIT,		"start-wait"}
269*4882a593Smuzhiyun };
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun /*
272*4882a593Smuzhiyun * session-state --> text string mapping
273*4882a593Smuzhiyun */
274*4882a593Smuzhiyun static const ftm_strmap_entry_t ftm_session_state_value_loginfo[] = {
275*4882a593Smuzhiyun 	/* wl_proxd_session_state_t,		text string */
276*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_CREATED,	"created" },
277*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_CONFIGURED,	"configured" },
278*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_STARTED,	"started" },
279*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_DELAY,		"delay" },
280*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_USER_WAIT,	"user-wait" },
281*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_SCHED_WAIT,	"sched-wait" },
282*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_BURST,		"burst" },
283*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_STOPPING,	"stopping" },
284*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_ENDED,		"ended" },
285*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_DESTROYING,	"destroying" },
286*4882a593Smuzhiyun 	{ WL_PROXD_SESSION_STATE_NONE,		"none" }
287*4882a593Smuzhiyun };
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun /*
290*4882a593Smuzhiyun * status --> text string mapping
291*4882a593Smuzhiyun */
292*4882a593Smuzhiyun static const ftm_strmap_entry_t ftm_status_value_loginfo[] = {
293*4882a593Smuzhiyun 	/* wl_proxd_status_t,			text-string */
294*4882a593Smuzhiyun 	{ WL_PROXD_E_OVERRIDDEN,		"overridden" },
295*4882a593Smuzhiyun 	{ WL_PROXD_E_ASAP_FAILED,		"ASAP failed" },
296*4882a593Smuzhiyun 	{ WL_PROXD_E_NOTSTARTED,		"not started" },
297*4882a593Smuzhiyun 	{ WL_PROXD_E_INVALIDMEAS,		"invalid measurement" },
298*4882a593Smuzhiyun 	{ WL_PROXD_E_INCAPABLE,			"incapable" },
299*4882a593Smuzhiyun 	{ WL_PROXD_E_MISMATCH,			"mismatch"},
300*4882a593Smuzhiyun 	{ WL_PROXD_E_DUP_SESSION,		"dup session" },
301*4882a593Smuzhiyun 	{ WL_PROXD_E_REMOTE_FAIL,		"remote fail" },
302*4882a593Smuzhiyun 	{ WL_PROXD_E_REMOTE_INCAPABLE,		"remote incapable" },
303*4882a593Smuzhiyun 	{ WL_PROXD_E_SCHED_FAIL,		"sched failure" },
304*4882a593Smuzhiyun 	{ WL_PROXD_E_PROTO,			"protocol error" },
305*4882a593Smuzhiyun 	{ WL_PROXD_E_EXPIRED,			"expired" },
306*4882a593Smuzhiyun 	{ WL_PROXD_E_TIMEOUT,			"timeout" },
307*4882a593Smuzhiyun 	{ WL_PROXD_E_NOACK,			"no ack" },
308*4882a593Smuzhiyun 	{ WL_PROXD_E_DEFERRED,			"deferred" },
309*4882a593Smuzhiyun 	{ WL_PROXD_E_INVALID_SID,		"invalid session id" },
310*4882a593Smuzhiyun 	{ WL_PROXD_E_REMOTE_CANCEL,		"remote cancel" },
311*4882a593Smuzhiyun 	{ WL_PROXD_E_CANCELED,			"canceled" },
312*4882a593Smuzhiyun 	{ WL_PROXD_E_INVALID_SESSION,		"invalid session" },
313*4882a593Smuzhiyun 	{ WL_PROXD_E_BAD_STATE,			"bad state" },
314*4882a593Smuzhiyun 	{ WL_PROXD_E_ERROR,			"error" },
315*4882a593Smuzhiyun 	{ WL_PROXD_E_OK,			"OK" }
316*4882a593Smuzhiyun };
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun /*
319*4882a593Smuzhiyun * time interval unit --> text string mapping
320*4882a593Smuzhiyun */
321*4882a593Smuzhiyun static const ftm_strmap_entry_t ftm_tmu_value_loginfo[] = {
322*4882a593Smuzhiyun 	/* wl_proxd_tmu_t,		text-string */
323*4882a593Smuzhiyun 	{ WL_PROXD_TMU_TU,		"TU" },
324*4882a593Smuzhiyun 	{ WL_PROXD_TMU_SEC,		"sec" },
325*4882a593Smuzhiyun 	{ WL_PROXD_TMU_MILLI_SEC,	"ms" },
326*4882a593Smuzhiyun 	{ WL_PROXD_TMU_MICRO_SEC,	"us" },
327*4882a593Smuzhiyun 	{ WL_PROXD_TMU_NANO_SEC,	"ns" },
328*4882a593Smuzhiyun 	{ WL_PROXD_TMU_PICO_SEC,	"ps" }
329*4882a593Smuzhiyun };
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun struct ieee_80211_mcs_rate_info {
332*4882a593Smuzhiyun 	uint8 constellation_bits;
333*4882a593Smuzhiyun 	uint8 coding_q;
334*4882a593Smuzhiyun 	uint8 coding_d;
335*4882a593Smuzhiyun };
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun static const struct ieee_80211_mcs_rate_info wl_mcs_info[] = {
338*4882a593Smuzhiyun 	{ 1, 1, 2 }, /* MCS  0: MOD: BPSK,   CR 1/2 */
339*4882a593Smuzhiyun 	{ 2, 1, 2 }, /* MCS  1: MOD: QPSK,   CR 1/2 */
340*4882a593Smuzhiyun 	{ 2, 3, 4 }, /* MCS  2: MOD: QPSK,   CR 3/4 */
341*4882a593Smuzhiyun 	{ 4, 1, 2 }, /* MCS  3: MOD: 16QAM,  CR 1/2 */
342*4882a593Smuzhiyun 	{ 4, 3, 4 }, /* MCS  4: MOD: 16QAM,  CR 3/4 */
343*4882a593Smuzhiyun 	{ 6, 2, 3 }, /* MCS  5: MOD: 64QAM,  CR 2/3 */
344*4882a593Smuzhiyun 	{ 6, 3, 4 }, /* MCS  6: MOD: 64QAM,  CR 3/4 */
345*4882a593Smuzhiyun 	{ 6, 5, 6 }, /* MCS  7: MOD: 64QAM,  CR 5/6 */
346*4882a593Smuzhiyun 	{ 8, 3, 4 }, /* MCS  8: MOD: 256QAM, CR 3/4 */
347*4882a593Smuzhiyun 	{ 8, 5, 6 }  /* MCS  9: MOD: 256QAM, CR 5/6 */
348*4882a593Smuzhiyun };
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun /**
351*4882a593Smuzhiyun  * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination.
352*4882a593Smuzhiyun  *     'mcs' : a *single* spatial stream MCS (11n or 11ac)
353*4882a593Smuzhiyun  */
354*4882a593Smuzhiyun uint
rate_mcs2rate(uint mcs,uint nss,uint bw,int sgi)355*4882a593Smuzhiyun rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	const int ksps = 250; /* kilo symbols per sec, 4 us sym */
358*4882a593Smuzhiyun 	const int Nsd_20MHz = 52;
359*4882a593Smuzhiyun 	const int Nsd_40MHz = 108;
360*4882a593Smuzhiyun 	const int Nsd_80MHz = 234;
361*4882a593Smuzhiyun 	const int Nsd_160MHz = 468;
362*4882a593Smuzhiyun 	uint rate;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	if (mcs == 32) {
365*4882a593Smuzhiyun 		/* just return fixed values for mcs32 instead of trying to parametrize */
366*4882a593Smuzhiyun 		rate = (sgi == 0) ? 6000 : 6778;
367*4882a593Smuzhiyun 	} else if (mcs <= 9) {
368*4882a593Smuzhiyun 		/* This calculation works for 11n HT and 11ac VHT if the HT mcs values
369*4882a593Smuzhiyun 		 * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8.
370*4882a593Smuzhiyun 		 * That is, HT MCS 23 is a base MCS = 7, Nss = 3
371*4882a593Smuzhiyun 		 */
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 		/* find the number of complex numbers per symbol */
374*4882a593Smuzhiyun 		if (RSPEC_IS20MHZ(bw)) {
375*4882a593Smuzhiyun 			/* 4360 TODO: eliminate Phy const in rspec bw, then just compare
376*4882a593Smuzhiyun 			 * as in 80 and 160 case below instead of RSPEC_IS20MHZ(bw)
377*4882a593Smuzhiyun 			 */
378*4882a593Smuzhiyun 			rate = Nsd_20MHz;
379*4882a593Smuzhiyun 		} else if (RSPEC_IS40MHZ(bw)) {
380*4882a593Smuzhiyun 			/* 4360 TODO: eliminate Phy const in rspec bw, then just compare
381*4882a593Smuzhiyun 			 * as in 80 and 160 case below instead of RSPEC_IS40MHZ(bw)
382*4882a593Smuzhiyun 			 */
383*4882a593Smuzhiyun 			rate = Nsd_40MHz;
384*4882a593Smuzhiyun 		} else if (bw == WL_RSPEC_BW_80MHZ) {
385*4882a593Smuzhiyun 			rate = Nsd_80MHz;
386*4882a593Smuzhiyun 		} else if (bw == WL_RSPEC_BW_160MHZ) {
387*4882a593Smuzhiyun 			rate = Nsd_160MHz;
388*4882a593Smuzhiyun 		} else {
389*4882a593Smuzhiyun 			rate = 0;
390*4882a593Smuzhiyun 		}
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 		/* multiply by bits per number from the constellation in use */
393*4882a593Smuzhiyun 		rate = rate * wl_mcs_info[mcs].constellation_bits;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 		/* adjust for the number of spatial streams */
396*4882a593Smuzhiyun 		rate = rate * nss;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 		/* adjust for the coding rate given as a quotient and divisor */
399*4882a593Smuzhiyun 		rate = (rate * wl_mcs_info[mcs].coding_q) / wl_mcs_info[mcs].coding_d;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 		/* multiply by Kilo symbols per sec to get Kbps */
402*4882a593Smuzhiyun 		rate = rate * ksps;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 		/* adjust the symbols per sec for SGI
405*4882a593Smuzhiyun 		 * symbol duration is 4 us without SGI, and 3.6 us with SGI,
406*4882a593Smuzhiyun 		 * so ratio is 10 / 9
407*4882a593Smuzhiyun 		 */
408*4882a593Smuzhiyun 		if (sgi) {
409*4882a593Smuzhiyun 			/* add 4 for rounding of division by 9 */
410*4882a593Smuzhiyun 			rate = ((rate * 10) + 4) / 9;
411*4882a593Smuzhiyun 		}
412*4882a593Smuzhiyun 	} else {
413*4882a593Smuzhiyun 		rate = 0;
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	return rate;
417*4882a593Smuzhiyun } /* wlc_rate_mcs2rate */
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun /** take a well formed ratespec_t arg and return phy rate in [Kbps] units */
420*4882a593Smuzhiyun static uint32
rate_rspec2rate(uint32 rspec)421*4882a593Smuzhiyun rate_rspec2rate(uint32 rspec)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun 	int rate = 0;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	if (RSPEC_ISLEGACY(rspec)) {
426*4882a593Smuzhiyun 		rate = 500 * (rspec & WL_RSPEC_RATE_MASK);
427*4882a593Smuzhiyun 	} else if (RSPEC_ISHT(rspec)) {
428*4882a593Smuzhiyun 		uint mcs = (rspec & WL_RSPEC_RATE_MASK);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 		if (mcs == 32) {
431*4882a593Smuzhiyun 			rate = rate_mcs2rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec));
432*4882a593Smuzhiyun 		} else {
433*4882a593Smuzhiyun 			uint nss = 1 + (mcs / 8);
434*4882a593Smuzhiyun 			mcs = mcs % 8;
435*4882a593Smuzhiyun 			rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec));
436*4882a593Smuzhiyun 		}
437*4882a593Smuzhiyun 	} else if (RSPEC_ISVHT(rspec)) {
438*4882a593Smuzhiyun 		uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK);
439*4882a593Smuzhiyun 		uint nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
440*4882a593Smuzhiyun 		if (mcs > 9 || nss > 8) {
441*4882a593Smuzhiyun 			DHD_RTT(("%s: Invalid mcs %d or nss %d\n", __FUNCTION__, mcs, nss));
442*4882a593Smuzhiyun 			goto exit;
443*4882a593Smuzhiyun 		}
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 		rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec));
446*4882a593Smuzhiyun 	} else {
447*4882a593Smuzhiyun 		DHD_RTT(("%s: wrong rspec:%d\n", __FUNCTION__, rspec));
448*4882a593Smuzhiyun 	}
449*4882a593Smuzhiyun exit:
450*4882a593Smuzhiyun 	return rate;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun char resp_buf[WLC_IOCTL_SMLEN];
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun static uint64
ftm_intvl2nsec(const wl_proxd_intvl_t * intvl)456*4882a593Smuzhiyun ftm_intvl2nsec(const wl_proxd_intvl_t *intvl)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun 	uint64 ret;
459*4882a593Smuzhiyun 	ret = intvl->intvl;
460*4882a593Smuzhiyun 	switch (intvl->tmu) {
461*4882a593Smuzhiyun 	case WL_PROXD_TMU_TU:			ret = FTM_TU2MICRO(ret) * 1000; break;
462*4882a593Smuzhiyun 	case WL_PROXD_TMU_SEC:			ret *= 1000000000; break;
463*4882a593Smuzhiyun 	case WL_PROXD_TMU_MILLI_SEC:	ret *= 1000000; break;
464*4882a593Smuzhiyun 	case WL_PROXD_TMU_MICRO_SEC:	ret *= 1000; break;
465*4882a593Smuzhiyun 	case WL_PROXD_TMU_PICO_SEC:		ret = intvl->intvl / 1000; break;
466*4882a593Smuzhiyun 	case WL_PROXD_TMU_NANO_SEC:		/* fall through */
467*4882a593Smuzhiyun 	default:						break;
468*4882a593Smuzhiyun 	}
469*4882a593Smuzhiyun 	return ret;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun uint64
ftm_intvl2usec(const wl_proxd_intvl_t * intvl)472*4882a593Smuzhiyun ftm_intvl2usec(const wl_proxd_intvl_t *intvl)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun 	uint64 ret;
475*4882a593Smuzhiyun 	ret = intvl->intvl;
476*4882a593Smuzhiyun 	switch (intvl->tmu) {
477*4882a593Smuzhiyun 	case WL_PROXD_TMU_TU:			ret = FTM_TU2MICRO(ret); break;
478*4882a593Smuzhiyun 	case WL_PROXD_TMU_SEC:			ret *= 1000000; break;
479*4882a593Smuzhiyun 	case WL_PROXD_TMU_NANO_SEC:		ret = intvl->intvl / 1000; break;
480*4882a593Smuzhiyun 	case WL_PROXD_TMU_PICO_SEC:		ret = intvl->intvl / 1000000; break;
481*4882a593Smuzhiyun 	case WL_PROXD_TMU_MILLI_SEC:	ret *= 1000; break;
482*4882a593Smuzhiyun 	case WL_PROXD_TMU_MICRO_SEC:	/* fall through */
483*4882a593Smuzhiyun 	default:						break;
484*4882a593Smuzhiyun 	}
485*4882a593Smuzhiyun 	return ret;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun /*
489*4882a593Smuzhiyun * lookup 'id' (as a key) from a fw status to host map table
490*4882a593Smuzhiyun * if found, return the corresponding reason code
491*4882a593Smuzhiyun */
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun static rtt_reason_t
ftm_get_statusmap_info(wl_proxd_status_t id,const ftm_status_map_host_entry_t * p_table,uint32 num_entries)494*4882a593Smuzhiyun ftm_get_statusmap_info(wl_proxd_status_t id, const ftm_status_map_host_entry_t *p_table,
495*4882a593Smuzhiyun 	uint32 num_entries)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun 	int i;
498*4882a593Smuzhiyun 	const ftm_status_map_host_entry_t *p_entry;
499*4882a593Smuzhiyun 	/* scan thru the table till end */
500*4882a593Smuzhiyun 	p_entry = p_table;
501*4882a593Smuzhiyun 	for (i = 0; i < (int) num_entries; i++)
502*4882a593Smuzhiyun 	{
503*4882a593Smuzhiyun 		if (p_entry->proxd_status == id) {
504*4882a593Smuzhiyun 			return p_entry->rtt_reason;
505*4882a593Smuzhiyun 		}
506*4882a593Smuzhiyun 		p_entry++;		/* next entry */
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun 	return RTT_STATUS_FAILURE; /* not found */
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun /*
511*4882a593Smuzhiyun * lookup 'id' (as a key) from a table
512*4882a593Smuzhiyun * if found, return the entry pointer, otherwise return NULL
513*4882a593Smuzhiyun */
514*4882a593Smuzhiyun static const ftm_strmap_entry_t*
ftm_get_strmap_info(int32 id,const ftm_strmap_entry_t * p_table,uint32 num_entries)515*4882a593Smuzhiyun ftm_get_strmap_info(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun 	int i;
518*4882a593Smuzhiyun 	const ftm_strmap_entry_t *p_entry;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	/* scan thru the table till end */
521*4882a593Smuzhiyun 	p_entry = p_table;
522*4882a593Smuzhiyun 	for (i = 0; i < (int) num_entries; i++)
523*4882a593Smuzhiyun 	{
524*4882a593Smuzhiyun 		if (p_entry->id == id)
525*4882a593Smuzhiyun 			return p_entry;
526*4882a593Smuzhiyun 		p_entry++;		/* next entry */
527*4882a593Smuzhiyun 	}
528*4882a593Smuzhiyun 	return NULL;			/* not found */
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun /*
532*4882a593Smuzhiyun * map enum to a text-string for display, this function is called by the following:
533*4882a593Smuzhiyun * For debug/trace:
534*4882a593Smuzhiyun *     ftm_[cmdid|tlvid]_to_str()
535*4882a593Smuzhiyun * For TLV-output log for 'get' commands
536*4882a593Smuzhiyun *     ftm_[method|tmu|caps|status|state]_value_to_logstr()
537*4882a593Smuzhiyun * Input:
538*4882a593Smuzhiyun *     pTable -- point to a 'enum to string' table.
539*4882a593Smuzhiyun */
540*4882a593Smuzhiyun static const char *
ftm_map_id_to_str(int32 id,const ftm_strmap_entry_t * p_table,uint32 num_entries)541*4882a593Smuzhiyun ftm_map_id_to_str(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun 	const ftm_strmap_entry_t*p_entry = ftm_get_strmap_info(id, p_table, num_entries);
544*4882a593Smuzhiyun 	if (p_entry)
545*4882a593Smuzhiyun 		return (p_entry->text);
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	return "invalid";
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun #if defined(WL_CFG80211) && defined(RTT_DEBUG)
551*4882a593Smuzhiyun /* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */
552*4882a593Smuzhiyun #define DEF_STRMAP_ENTRY(id) { (id), #id }
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun /* ftm cmd-id mapping */
555*4882a593Smuzhiyun static const ftm_strmap_entry_t ftm_cmdid_map[] = {
556*4882a593Smuzhiyun 	/* {wl_proxd_cmd_t(WL_PROXD_CMD_xxx), "WL_PROXD_CMD_xxx" }, */
557*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_NONE),
558*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_VERSION),
559*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_ENABLE),
560*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_DISABLE),
561*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_CONFIG),
562*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_SESSION),
563*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_BURST_REQUEST),
564*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_SESSION),
565*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_DELETE_SESSION),
566*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RESULT),
567*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_INFO),
568*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_STATUS),
569*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_SESSIONS),
570*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_COUNTERS),
571*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_CLEAR_COUNTERS),
572*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_COLLECT),
573*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_TUNE),
574*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_DUMP),
575*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_RANGING),
576*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_RANGING),
577*4882a593Smuzhiyun 	DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RANGING_INFO),
578*4882a593Smuzhiyun };
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun /*
581*4882a593Smuzhiyun * map a ftm cmd-id to a text-string for display
582*4882a593Smuzhiyun */
583*4882a593Smuzhiyun const char *
ftm_cmdid_to_str(uint16 cmdid)584*4882a593Smuzhiyun ftm_cmdid_to_str(uint16 cmdid)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	return ftm_map_id_to_str((int32) cmdid, &ftm_cmdid_map[0], ARRAYSIZE(ftm_cmdid_map));
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun #endif /* WL_CFG80211 && RTT_DEBUG */
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun /*
591*4882a593Smuzhiyun * convert BCME_xxx error codes into related error strings
592*4882a593Smuzhiyun * note, bcmerrorstr() defined in bcmutils is for BCMDRIVER only,
593*4882a593Smuzhiyun *       this duplicate copy is for WL access and may need to clean up later
594*4882a593Smuzhiyun */
595*4882a593Smuzhiyun static const char *ftm_bcmerrorstrtable[] = BCMERRSTRINGTABLE;
596*4882a593Smuzhiyun static const char *
ftm_status_value_to_logstr(wl_proxd_status_t status)597*4882a593Smuzhiyun ftm_status_value_to_logstr(wl_proxd_status_t status)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun 	static char ftm_msgbuf_status_undef[32];
600*4882a593Smuzhiyun 	const ftm_strmap_entry_t *p_loginfo;
601*4882a593Smuzhiyun 	int bcmerror;
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	/* check if within BCME_xxx error range */
604*4882a593Smuzhiyun 	bcmerror = (int) status;
605*4882a593Smuzhiyun 	if (VALID_BCMERROR(bcmerror))
606*4882a593Smuzhiyun 		return ftm_bcmerrorstrtable[-bcmerror];
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	/* otherwise, look for 'proxd ftm status' range */
609*4882a593Smuzhiyun 	p_loginfo = ftm_get_strmap_info((int32) status,
610*4882a593Smuzhiyun 		&ftm_status_value_loginfo[0], ARRAYSIZE(ftm_status_value_loginfo));
611*4882a593Smuzhiyun 	if (p_loginfo)
612*4882a593Smuzhiyun 		return p_loginfo->text;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	/* report for 'out of range' FTM-status error code */
615*4882a593Smuzhiyun 	memset(ftm_msgbuf_status_undef, 0, sizeof(ftm_msgbuf_status_undef));
616*4882a593Smuzhiyun 	snprintf(ftm_msgbuf_status_undef, sizeof(ftm_msgbuf_status_undef),
617*4882a593Smuzhiyun 		"Undefined status %d", status);
618*4882a593Smuzhiyun 	return &ftm_msgbuf_status_undef[0];
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun static const char *
ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu)622*4882a593Smuzhiyun ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun 	return ftm_map_id_to_str((int32)tmu,
625*4882a593Smuzhiyun 		&ftm_tmu_value_loginfo[0], ARRAYSIZE(ftm_tmu_value_loginfo));
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun static const ftm_strmap_entry_t*
ftm_get_event_type_loginfo(wl_proxd_event_type_t event_type)629*4882a593Smuzhiyun ftm_get_event_type_loginfo(wl_proxd_event_type_t	event_type)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun 	/* look up 'event-type' from a predefined table  */
632*4882a593Smuzhiyun 	return ftm_get_strmap_info((int32) event_type,
633*4882a593Smuzhiyun 		ftm_event_type_loginfo, ARRAYSIZE(ftm_event_type_loginfo));
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun static const char *
ftm_session_state_value_to_logstr(wl_proxd_session_state_t state)637*4882a593Smuzhiyun ftm_session_state_value_to_logstr(wl_proxd_session_state_t state)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun 	return ftm_map_id_to_str((int32)state, &ftm_session_state_value_loginfo[0],
640*4882a593Smuzhiyun 		ARRAYSIZE(ftm_session_state_value_loginfo));
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun #ifdef WL_CFG80211
644*4882a593Smuzhiyun /*
645*4882a593Smuzhiyun * send 'proxd' iovar for all ftm get-related commands
646*4882a593Smuzhiyun */
647*4882a593Smuzhiyun static int
rtt_do_get_ioctl(dhd_pub_t * dhd,wl_proxd_iov_t * p_proxd_iov,uint16 proxd_iovsize,ftm_subcmd_info_t * p_subcmd_info)648*4882a593Smuzhiyun rtt_do_get_ioctl(dhd_pub_t *dhd, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize,
649*4882a593Smuzhiyun 		ftm_subcmd_info_t *p_subcmd_info)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	wl_proxd_iov_t *p_iovresp = (wl_proxd_iov_t *)resp_buf;
653*4882a593Smuzhiyun 	int status;
654*4882a593Smuzhiyun 	int tlvs_len;
655*4882a593Smuzhiyun 	/*  send getbuf proxd iovar */
656*4882a593Smuzhiyun 	status = dhd_getiovar(dhd, 0, "proxd", (char *)p_proxd_iov,
657*4882a593Smuzhiyun 			proxd_iovsize, (char **)&p_iovresp, WLC_IOCTL_SMLEN);
658*4882a593Smuzhiyun 	if (status != BCME_OK) {
659*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n",
660*4882a593Smuzhiyun 			__FUNCTION__, p_subcmd_info->cmdid, status));
661*4882a593Smuzhiyun 		return status;
662*4882a593Smuzhiyun 	}
663*4882a593Smuzhiyun 	if (p_subcmd_info->cmdid == WL_PROXD_CMD_GET_VERSION) {
664*4882a593Smuzhiyun 		p_subcmd_info->version = ltoh16(p_iovresp->version);
665*4882a593Smuzhiyun 		DHD_RTT(("ftm version: 0x%x\n", ltoh16(p_iovresp->version)));
666*4882a593Smuzhiyun 		goto exit;
667*4882a593Smuzhiyun 	}
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE;
670*4882a593Smuzhiyun 	if (tlvs_len < 0) {
671*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n",
672*4882a593Smuzhiyun 			__FUNCTION__, ltoh16(p_iovresp->len), (int) WL_PROXD_IOV_HDR_SIZE));
673*4882a593Smuzhiyun 		tlvs_len = 0;
674*4882a593Smuzhiyun 	}
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	if (tlvs_len > 0 && p_subcmd_info->handler) {
677*4882a593Smuzhiyun 		/* unpack TLVs and invokes the cbfn for processing */
678*4882a593Smuzhiyun 		status = bcm_unpack_xtlv_buf(p_proxd_iov, (uint8 *)p_iovresp->tlvs,
679*4882a593Smuzhiyun 				tlvs_len, BCM_XTLV_OPTION_ALIGN32, p_subcmd_info->handler);
680*4882a593Smuzhiyun 	}
681*4882a593Smuzhiyun exit:
682*4882a593Smuzhiyun 	return status;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun static wl_proxd_iov_t *
rtt_alloc_getset_buf(dhd_pub_t * dhd,wl_proxd_method_t method,wl_proxd_session_id_t session_id,wl_proxd_cmd_t cmdid,uint16 tlvs_bufsize,uint16 * p_out_bufsize)686*4882a593Smuzhiyun rtt_alloc_getset_buf(dhd_pub_t *dhd, wl_proxd_method_t method, wl_proxd_session_id_t session_id,
687*4882a593Smuzhiyun 	wl_proxd_cmd_t cmdid, uint16 tlvs_bufsize, uint16 *p_out_bufsize)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun 	uint16 proxd_iovsize;
690*4882a593Smuzhiyun 	wl_proxd_tlv_t *p_tlv;
691*4882a593Smuzhiyun 	wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) NULL;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	*p_out_bufsize = 0;	/* init */
694*4882a593Smuzhiyun 	/* calculate the whole buffer size, including one reserve-tlv entry in the header */
695*4882a593Smuzhiyun 	proxd_iovsize = sizeof(wl_proxd_iov_t) + tlvs_bufsize;
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	p_proxd_iov = (wl_proxd_iov_t *)MALLOCZ(dhd->osh, proxd_iovsize);
698*4882a593Smuzhiyun 	if (p_proxd_iov == NULL) {
699*4882a593Smuzhiyun 		DHD_RTT_ERR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize));
700*4882a593Smuzhiyun 		return NULL;
701*4882a593Smuzhiyun 	}
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	/* setup proxd-FTM-method iovar header */
704*4882a593Smuzhiyun 	p_proxd_iov->version = htol16(WL_PROXD_API_VERSION);
705*4882a593Smuzhiyun 	p_proxd_iov->len = htol16(proxd_iovsize); /* caller may adjust it based on #of TLVs */
706*4882a593Smuzhiyun 	p_proxd_iov->cmd = htol16(cmdid);
707*4882a593Smuzhiyun 	p_proxd_iov->method = htol16(method);
708*4882a593Smuzhiyun 	p_proxd_iov->sid = htol16(session_id);
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	/* initialize the reserved/dummy-TLV in iovar header */
711*4882a593Smuzhiyun 	p_tlv = p_proxd_iov->tlvs;
712*4882a593Smuzhiyun 	p_tlv->id = htol16(WL_PROXD_TLV_ID_NONE);
713*4882a593Smuzhiyun 	p_tlv->len = htol16(0);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	*p_out_bufsize = proxd_iovsize;	/* for caller's reference */
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	return p_proxd_iov;
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun static int
dhd_rtt_common_get_handler(dhd_pub_t * dhd,ftm_subcmd_info_t * p_subcmd_info,wl_proxd_method_t method,wl_proxd_session_id_t session_id)721*4882a593Smuzhiyun dhd_rtt_common_get_handler(dhd_pub_t *dhd, ftm_subcmd_info_t *p_subcmd_info,
722*4882a593Smuzhiyun 		wl_proxd_method_t method,
723*4882a593Smuzhiyun 		wl_proxd_session_id_t session_id)
724*4882a593Smuzhiyun {
725*4882a593Smuzhiyun 	int status = BCME_OK;
726*4882a593Smuzhiyun 	uint16 proxd_iovsize = 0;
727*4882a593Smuzhiyun 	wl_proxd_iov_t *p_proxd_iov;
728*4882a593Smuzhiyun #ifdef RTT_DEBUG
729*4882a593Smuzhiyun 	DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
730*4882a593Smuzhiyun 		__FUNCTION__, method, session_id, p_subcmd_info->cmdid,
731*4882a593Smuzhiyun 		ftm_cmdid_to_str(p_subcmd_info->cmdid)));
732*4882a593Smuzhiyun #endif
733*4882a593Smuzhiyun 	/* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */
734*4882a593Smuzhiyun 	p_proxd_iov = rtt_alloc_getset_buf(dhd, method, session_id, p_subcmd_info->cmdid,
735*4882a593Smuzhiyun 		0, &proxd_iovsize);
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	if (p_proxd_iov == NULL)
738*4882a593Smuzhiyun 		return BCME_NOMEM;
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	status = rtt_do_get_ioctl(dhd, p_proxd_iov, proxd_iovsize, p_subcmd_info);
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	if (status != BCME_OK) {
743*4882a593Smuzhiyun 		DHD_RTT(("%s failed: status=%d\n", __FUNCTION__, status));
744*4882a593Smuzhiyun 	}
745*4882a593Smuzhiyun 	MFREE(dhd->osh, p_proxd_iov, proxd_iovsize);
746*4882a593Smuzhiyun 	return status;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun /*
750*4882a593Smuzhiyun * common handler for set-related proxd method commands which require no TLV as input
751*4882a593Smuzhiyun *   wl proxd ftm [session-id] <set-subcmd>
752*4882a593Smuzhiyun * e.g.
753*4882a593Smuzhiyun *   wl proxd ftm enable -- to enable ftm
754*4882a593Smuzhiyun *   wl proxd ftm disable -- to disable ftm
755*4882a593Smuzhiyun *   wl proxd ftm <session-id> start -- to start a specified session
756*4882a593Smuzhiyun *   wl proxd ftm <session-id> stop  -- to cancel a specified session;
757*4882a593Smuzhiyun *                                    state is maintained till session is delete.
758*4882a593Smuzhiyun *   wl proxd ftm <session-id> delete -- to delete a specified session
759*4882a593Smuzhiyun *   wl proxd ftm [<session-id>] clear-counters -- to clear counters
760*4882a593Smuzhiyun *   wl proxd ftm <session-id> burst-request -- on initiator: to send burst request;
761*4882a593Smuzhiyun *                                              on target: send FTM frame
762*4882a593Smuzhiyun *   wl proxd ftm <session-id> collect
763*4882a593Smuzhiyun *   wl proxd ftm tune     (TBD)
764*4882a593Smuzhiyun */
765*4882a593Smuzhiyun static int
dhd_rtt_common_set_handler(dhd_pub_t * dhd,const ftm_subcmd_info_t * p_subcmd_info,wl_proxd_method_t method,wl_proxd_session_id_t session_id)766*4882a593Smuzhiyun dhd_rtt_common_set_handler(dhd_pub_t *dhd, const ftm_subcmd_info_t *p_subcmd_info,
767*4882a593Smuzhiyun 	wl_proxd_method_t method, wl_proxd_session_id_t session_id)
768*4882a593Smuzhiyun {
769*4882a593Smuzhiyun 	uint16 proxd_iovsize;
770*4882a593Smuzhiyun 	wl_proxd_iov_t *p_proxd_iov;
771*4882a593Smuzhiyun 	int ret;
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun #ifdef RTT_DEBUG
774*4882a593Smuzhiyun 	DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
775*4882a593Smuzhiyun 		__FUNCTION__, method, session_id, p_subcmd_info->cmdid,
776*4882a593Smuzhiyun 		ftm_cmdid_to_str(p_subcmd_info->cmdid)));
777*4882a593Smuzhiyun #endif
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	/* allocate and initialize a temp buffer for 'set proxd' iovar */
780*4882a593Smuzhiyun 	proxd_iovsize = 0;
781*4882a593Smuzhiyun 	p_proxd_iov = rtt_alloc_getset_buf(dhd, method, session_id, p_subcmd_info->cmdid,
782*4882a593Smuzhiyun 			0, &proxd_iovsize);		/* no TLV */
783*4882a593Smuzhiyun 	if (p_proxd_iov == NULL)
784*4882a593Smuzhiyun 		return BCME_NOMEM;
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	/* no TLV to pack, simply issue a set-proxd iovar */
787*4882a593Smuzhiyun 	ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, proxd_iovsize, NULL, 0, TRUE);
788*4882a593Smuzhiyun #ifdef RTT_DEBUG
789*4882a593Smuzhiyun 	if (ret != BCME_OK) {
790*4882a593Smuzhiyun 		DHD_RTT(("error: IOVAR failed, status=%d\n", ret));
791*4882a593Smuzhiyun 	}
792*4882a593Smuzhiyun #endif
793*4882a593Smuzhiyun 	/* clean up */
794*4882a593Smuzhiyun 	MFREE(dhd->osh, p_proxd_iov, proxd_iovsize);
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	return ret;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun #endif /* WL_CFG80211 */
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun /* gets the length and returns the version
801*4882a593Smuzhiyun  * of the wl_proxd_collect_event_t version
802*4882a593Smuzhiyun  */
803*4882a593Smuzhiyun static uint
rtt_collect_data_event_ver(uint16 len)804*4882a593Smuzhiyun rtt_collect_data_event_ver(uint16 len)
805*4882a593Smuzhiyun {
806*4882a593Smuzhiyun 	if (len > sizeof(wl_proxd_collect_event_data_v3_t)) {
807*4882a593Smuzhiyun 		return WL_PROXD_COLLECT_EVENT_DATA_VERSION_MAX;
808*4882a593Smuzhiyun 	} else if (len == sizeof(wl_proxd_collect_event_data_v4_t)) {
809*4882a593Smuzhiyun 		return WL_PROXD_COLLECT_EVENT_DATA_VERSION_4;
810*4882a593Smuzhiyun 	} else if (len == sizeof(wl_proxd_collect_event_data_v3_t)) {
811*4882a593Smuzhiyun 		return WL_PROXD_COLLECT_EVENT_DATA_VERSION_3;
812*4882a593Smuzhiyun 	} else if (len == sizeof(wl_proxd_collect_event_data_v2_t)) {
813*4882a593Smuzhiyun 		return WL_PROXD_COLLECT_EVENT_DATA_VERSION_2;
814*4882a593Smuzhiyun 	} else {
815*4882a593Smuzhiyun 		return WL_PROXD_COLLECT_EVENT_DATA_VERSION_1;
816*4882a593Smuzhiyun 	}
817*4882a593Smuzhiyun }
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun static void
rtt_collect_event_data_display(uint8 ver,void * ctx,const uint8 * p_data,uint16 len)820*4882a593Smuzhiyun rtt_collect_event_data_display(uint8 ver, void *ctx, const uint8 *p_data, uint16 len)
821*4882a593Smuzhiyun {
822*4882a593Smuzhiyun 	int i;
823*4882a593Smuzhiyun 	wl_proxd_collect_event_data_v1_t *p_collect_data_v1 = NULL;
824*4882a593Smuzhiyun 	wl_proxd_collect_event_data_v2_t *p_collect_data_v2 = NULL;
825*4882a593Smuzhiyun 	wl_proxd_collect_event_data_v3_t *p_collect_data_v3 = NULL;
826*4882a593Smuzhiyun 	wl_proxd_collect_event_data_v4_t *p_collect_data_v4 = NULL;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	if (!ctx || !p_data) {
829*4882a593Smuzhiyun 		return;
830*4882a593Smuzhiyun 	}
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	switch (ver) {
833*4882a593Smuzhiyun 	case WL_PROXD_COLLECT_EVENT_DATA_VERSION_1:
834*4882a593Smuzhiyun 		DHD_RTT(("\tVERSION_1\n"));
835*4882a593Smuzhiyun 		memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v1_t));
836*4882a593Smuzhiyun 		p_collect_data_v1 = (wl_proxd_collect_event_data_v1_t *)ctx;
837*4882a593Smuzhiyun 		DHD_RTT(("\tH_RX\n"));
838*4882a593Smuzhiyun 		for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
839*4882a593Smuzhiyun 			p_collect_data_v1->H_RX[i] = ltoh32_ua(&p_collect_data_v1->H_RX[i]);
840*4882a593Smuzhiyun 			DHD_RTT(("\t%u\n", p_collect_data_v1->H_RX[i]));
841*4882a593Smuzhiyun 		}
842*4882a593Smuzhiyun 		DHD_RTT(("\n"));
843*4882a593Smuzhiyun 		DHD_RTT(("\tH_LB\n"));
844*4882a593Smuzhiyun 		for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
845*4882a593Smuzhiyun 			p_collect_data_v1->H_LB[i] = ltoh32_ua(&p_collect_data_v1->H_LB[i]);
846*4882a593Smuzhiyun 			DHD_RTT(("\t%u\n", p_collect_data_v1->H_LB[i]));
847*4882a593Smuzhiyun 		}
848*4882a593Smuzhiyun 		DHD_RTT(("\n"));
849*4882a593Smuzhiyun 		DHD_RTT(("\tri_rr\n"));
850*4882a593Smuzhiyun 		for (i = 0; i < FTM_TPK_RI_RR_LEN; i++) {
851*4882a593Smuzhiyun 			DHD_RTT(("\t%u\n", p_collect_data_v1->ri_rr[i]));
852*4882a593Smuzhiyun 		}
853*4882a593Smuzhiyun 		p_collect_data_v1->phy_err_mask = ltoh32_ua(&p_collect_data_v1->phy_err_mask);
854*4882a593Smuzhiyun 		DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data_v1->phy_err_mask));
855*4882a593Smuzhiyun 		break;
856*4882a593Smuzhiyun 	case WL_PROXD_COLLECT_EVENT_DATA_VERSION_2:
857*4882a593Smuzhiyun 		memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v2_t));
858*4882a593Smuzhiyun 		p_collect_data_v2 = (wl_proxd_collect_event_data_v2_t *)ctx;
859*4882a593Smuzhiyun 		DHD_RTT(("\tH_RX\n"));
860*4882a593Smuzhiyun 		for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
861*4882a593Smuzhiyun 			p_collect_data_v2->H_RX[i] = ltoh32_ua(&p_collect_data_v2->H_RX[i]);
862*4882a593Smuzhiyun 			DHD_RTT(("\t%u\n", p_collect_data_v2->H_RX[i]));
863*4882a593Smuzhiyun 		}
864*4882a593Smuzhiyun 		DHD_RTT(("\n"));
865*4882a593Smuzhiyun 		DHD_RTT(("\tH_LB\n"));
866*4882a593Smuzhiyun 		for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
867*4882a593Smuzhiyun 			p_collect_data_v2->H_LB[i] = ltoh32_ua(&p_collect_data_v2->H_LB[i]);
868*4882a593Smuzhiyun 			DHD_RTT(("\t%u\n", p_collect_data_v2->H_LB[i]));
869*4882a593Smuzhiyun 		}
870*4882a593Smuzhiyun 		DHD_RTT(("\n"));
871*4882a593Smuzhiyun 		DHD_RTT(("\tri_rr\n"));
872*4882a593Smuzhiyun 		for (i = 0; i < FTM_TPK_RI_RR_LEN_SECURE_2_0; i++) {
873*4882a593Smuzhiyun 			DHD_RTT(("\t%u\n", p_collect_data_v2->ri_rr[i]));
874*4882a593Smuzhiyun 		}
875*4882a593Smuzhiyun 		p_collect_data_v2->phy_err_mask = ltoh32_ua(&p_collect_data_v2->phy_err_mask);
876*4882a593Smuzhiyun 		DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data_v2->phy_err_mask));
877*4882a593Smuzhiyun 		break;
878*4882a593Smuzhiyun 	case WL_PROXD_COLLECT_EVENT_DATA_VERSION_3:
879*4882a593Smuzhiyun 		memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v3_t));
880*4882a593Smuzhiyun 		p_collect_data_v3 = (wl_proxd_collect_event_data_v3_t *)ctx;
881*4882a593Smuzhiyun 		switch (p_collect_data_v3->version) {
882*4882a593Smuzhiyun 		case WL_PROXD_COLLECT_EVENT_DATA_VERSION_3:
883*4882a593Smuzhiyun 			if (p_collect_data_v3->length !=
884*4882a593Smuzhiyun 				(len - OFFSETOF(wl_proxd_collect_event_data_v3_t, H_LB))) {
885*4882a593Smuzhiyun 				DHD_RTT(("\tversion/length mismatch\n"));
886*4882a593Smuzhiyun 				break;
887*4882a593Smuzhiyun 			}
888*4882a593Smuzhiyun 			DHD_RTT(("\tH_RX\n"));
889*4882a593Smuzhiyun 			for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
890*4882a593Smuzhiyun 				p_collect_data_v3->H_RX[i] =
891*4882a593Smuzhiyun 					ltoh32_ua(&p_collect_data_v3->H_RX[i]);
892*4882a593Smuzhiyun 				DHD_RTT(("\t%u\n", p_collect_data_v3->H_RX[i]));
893*4882a593Smuzhiyun 			}
894*4882a593Smuzhiyun 			DHD_RTT(("\n"));
895*4882a593Smuzhiyun 			DHD_RTT(("\tH_LB\n"));
896*4882a593Smuzhiyun 			for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
897*4882a593Smuzhiyun 				p_collect_data_v3->H_LB[i] =
898*4882a593Smuzhiyun 					ltoh32_ua(&p_collect_data_v3->H_LB[i]);
899*4882a593Smuzhiyun 				DHD_RTT(("\t%u\n", p_collect_data_v3->H_LB[i]));
900*4882a593Smuzhiyun 			}
901*4882a593Smuzhiyun 			DHD_RTT(("\n"));
902*4882a593Smuzhiyun 			DHD_RTT(("\tri_rr\n"));
903*4882a593Smuzhiyun 			for (i = 0; i < FTM_TPK_RI_RR_LEN_SECURE_2_0; i++) {
904*4882a593Smuzhiyun 				DHD_RTT(("\t%u\n", p_collect_data_v3->ri_rr[i]));
905*4882a593Smuzhiyun 			}
906*4882a593Smuzhiyun 			p_collect_data_v3->phy_err_mask =
907*4882a593Smuzhiyun 				ltoh32_ua(&p_collect_data_v3->phy_err_mask);
908*4882a593Smuzhiyun 			DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data_v3->phy_err_mask));
909*4882a593Smuzhiyun 			break;
910*4882a593Smuzhiyun 		/* future case */
911*4882a593Smuzhiyun 		}
912*4882a593Smuzhiyun 		break;
913*4882a593Smuzhiyun 	case WL_PROXD_COLLECT_EVENT_DATA_VERSION_4:
914*4882a593Smuzhiyun 		memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v4_t));
915*4882a593Smuzhiyun 		p_collect_data_v4 = (wl_proxd_collect_event_data_v4_t *)ctx;
916*4882a593Smuzhiyun 		switch (p_collect_data_v4->version) {
917*4882a593Smuzhiyun 		case WL_PROXD_COLLECT_EVENT_DATA_VERSION_4:
918*4882a593Smuzhiyun 			if (p_collect_data_v4->length !=
919*4882a593Smuzhiyun 				(len - OFFSETOF(wl_proxd_collect_event_data_v4_t, H_LB))) {
920*4882a593Smuzhiyun 				DHD_RTT(("\tversion/length mismatch\n"));
921*4882a593Smuzhiyun 				break;
922*4882a593Smuzhiyun 			}
923*4882a593Smuzhiyun 			DHD_RTT(("\tH_RX\n"));
924*4882a593Smuzhiyun 			for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
925*4882a593Smuzhiyun 				p_collect_data_v4->H_RX[i] =
926*4882a593Smuzhiyun 					ltoh32_ua(&p_collect_data_v4->H_RX[i]);
927*4882a593Smuzhiyun 				DHD_RTT(("\t%u\n", p_collect_data_v4->H_RX[i]));
928*4882a593Smuzhiyun 			}
929*4882a593Smuzhiyun 			DHD_RTT(("\n"));
930*4882a593Smuzhiyun 			DHD_RTT(("\tH_LB\n"));
931*4882a593Smuzhiyun 			for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
932*4882a593Smuzhiyun 				p_collect_data_v4->H_LB[i] =
933*4882a593Smuzhiyun 					ltoh32_ua(&p_collect_data_v4->H_LB[i]);
934*4882a593Smuzhiyun 				DHD_RTT(("\t%u\n", p_collect_data_v4->H_LB[i]));
935*4882a593Smuzhiyun 			}
936*4882a593Smuzhiyun 			DHD_RTT(("\n"));
937*4882a593Smuzhiyun 			DHD_RTT(("\tri_rr\n"));
938*4882a593Smuzhiyun 			for (i = 0; i < FTM_TPK_RI_RR_LEN_SECURE_2_0_5G; i++) {
939*4882a593Smuzhiyun 				DHD_RTT(("\t%u\n", p_collect_data_v4->ri_rr[i]));
940*4882a593Smuzhiyun 			}
941*4882a593Smuzhiyun 			p_collect_data_v4->phy_err_mask =
942*4882a593Smuzhiyun 				ltoh32_ua(&p_collect_data_v4->phy_err_mask);
943*4882a593Smuzhiyun 			DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data_v4->phy_err_mask));
944*4882a593Smuzhiyun 			break;
945*4882a593Smuzhiyun 		/* future case */
946*4882a593Smuzhiyun 		}
947*4882a593Smuzhiyun 		break;
948*4882a593Smuzhiyun 	}
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun static uint16
rtt_result_ver(uint16 tlvid,const uint8 * p_data)952*4882a593Smuzhiyun rtt_result_ver(uint16 tlvid, const uint8 *p_data)
953*4882a593Smuzhiyun {
954*4882a593Smuzhiyun 	uint16 ret = BCME_OK;
955*4882a593Smuzhiyun 	const wl_proxd_rtt_result_v2_t *r_v2 = NULL;
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	switch (tlvid) {
958*4882a593Smuzhiyun 	case WL_PROXD_TLV_ID_RTT_RESULT:
959*4882a593Smuzhiyun 		BCM_REFERENCE(p_data);
960*4882a593Smuzhiyun 		ret = WL_PROXD_RTT_RESULT_VERSION_1;
961*4882a593Smuzhiyun 		break;
962*4882a593Smuzhiyun 	case WL_PROXD_TLV_ID_RTT_RESULT_V2:
963*4882a593Smuzhiyun 		if (p_data) {
964*4882a593Smuzhiyun 			r_v2 = (const wl_proxd_rtt_result_v2_t *)p_data;
965*4882a593Smuzhiyun 			if (r_v2->version == WL_PROXD_RTT_RESULT_VERSION_2) {
966*4882a593Smuzhiyun 				ret = WL_PROXD_RTT_RESULT_VERSION_2;
967*4882a593Smuzhiyun 			}
968*4882a593Smuzhiyun 		}
969*4882a593Smuzhiyun 		break;
970*4882a593Smuzhiyun 	default:
971*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s: > Unsupported TLV ID %d\n",
972*4882a593Smuzhiyun 			__FUNCTION__, tlvid));
973*4882a593Smuzhiyun 		break;
974*4882a593Smuzhiyun 	}
975*4882a593Smuzhiyun 	return ret;
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun /* pretty hex print a contiguous buffer */
979*4882a593Smuzhiyun static void
rtt_prhex(const char * msg,const uint8 * buf,uint nbytes)980*4882a593Smuzhiyun rtt_prhex(const char *msg, const uint8 *buf, uint nbytes)
981*4882a593Smuzhiyun {
982*4882a593Smuzhiyun 	char line[128], *p;
983*4882a593Smuzhiyun 	int len = sizeof(line);
984*4882a593Smuzhiyun 	int nchar;
985*4882a593Smuzhiyun 	uint i;
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 	if (msg && (msg[0] != '\0'))
988*4882a593Smuzhiyun 		DHD_RTT(("%s:\n", msg));
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	p = line;
991*4882a593Smuzhiyun 	for (i = 0; i < nbytes; i++) {
992*4882a593Smuzhiyun 		if (i % 16 == 0) {
993*4882a593Smuzhiyun 			nchar = snprintf(p, len, "  %04d: ", i);	/* line prefix */
994*4882a593Smuzhiyun 			p += nchar;
995*4882a593Smuzhiyun 			len -= nchar;
996*4882a593Smuzhiyun 		}
997*4882a593Smuzhiyun 		if (len > 0) {
998*4882a593Smuzhiyun 			nchar = snprintf(p, len, "%02x ", buf[i]);
999*4882a593Smuzhiyun 			p += nchar;
1000*4882a593Smuzhiyun 			len -= nchar;
1001*4882a593Smuzhiyun 		}
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun 		if (i % 16 == 15) {
1004*4882a593Smuzhiyun 			DHD_RTT(("%s\n", line));	/* flush line */
1005*4882a593Smuzhiyun 			p = line;
1006*4882a593Smuzhiyun 			len = sizeof(line);
1007*4882a593Smuzhiyun 		}
1008*4882a593Smuzhiyun 	}
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	/* flush last partial line */
1011*4882a593Smuzhiyun 	if (p != line)
1012*4882a593Smuzhiyun 		DHD_RTT(("%s\n", line));
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun static int
rtt_unpack_xtlv_cbfn(void * ctx,const uint8 * p_data,uint16 tlvid,uint16 len)1016*4882a593Smuzhiyun rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len)
1017*4882a593Smuzhiyun {
1018*4882a593Smuzhiyun 	int ret = BCME_OK;
1019*4882a593Smuzhiyun 	int i;
1020*4882a593Smuzhiyun 	wl_proxd_ftm_session_status_t *p_data_info = NULL;
1021*4882a593Smuzhiyun 	uint32 chan_data_entry = 0;
1022*4882a593Smuzhiyun 	uint16 expected_rtt_result_ver = 0;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	BCM_REFERENCE(p_data_info);
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	switch (tlvid) {
1027*4882a593Smuzhiyun 	case WL_PROXD_TLV_ID_RTT_RESULT:
1028*4882a593Smuzhiyun 	case WL_PROXD_TLV_ID_RTT_RESULT_V2:
1029*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_TLV_ID_RTT_RESULT\n"));
1030*4882a593Smuzhiyun 		expected_rtt_result_ver = rtt_result_ver(tlvid, p_data);
1031*4882a593Smuzhiyun 		switch (expected_rtt_result_ver) {
1032*4882a593Smuzhiyun 		case WL_PROXD_RTT_RESULT_VERSION_1:
1033*4882a593Smuzhiyun 			ret = dhd_rtt_convert_results_to_host_v1((rtt_result_t *)ctx,
1034*4882a593Smuzhiyun 					p_data, tlvid, len);
1035*4882a593Smuzhiyun 			break;
1036*4882a593Smuzhiyun 		case WL_PROXD_RTT_RESULT_VERSION_2:
1037*4882a593Smuzhiyun 			ret = dhd_rtt_convert_results_to_host_v2((rtt_result_t *)ctx,
1038*4882a593Smuzhiyun 					p_data, tlvid, len);
1039*4882a593Smuzhiyun 			break;
1040*4882a593Smuzhiyun 		default:
1041*4882a593Smuzhiyun 			DHD_RTT_ERR((" > Unsupported RTT_RESULT version\n"));
1042*4882a593Smuzhiyun 			ret = BCME_UNSUPPORTED;
1043*4882a593Smuzhiyun 			break;
1044*4882a593Smuzhiyun 		}
1045*4882a593Smuzhiyun 		break;
1046*4882a593Smuzhiyun 	case WL_PROXD_TLV_ID_SESSION_STATUS:
1047*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_TLV_ID_SESSION_STATUS\n"));
1048*4882a593Smuzhiyun 		memcpy(ctx, p_data, sizeof(wl_proxd_ftm_session_status_t));
1049*4882a593Smuzhiyun 		p_data_info = (wl_proxd_ftm_session_status_t *)ctx;
1050*4882a593Smuzhiyun 		p_data_info->sid = ltoh16_ua(&p_data_info->sid);
1051*4882a593Smuzhiyun 		p_data_info->state = ltoh16_ua(&p_data_info->state);
1052*4882a593Smuzhiyun 		p_data_info->status = ltoh32_ua(&p_data_info->status);
1053*4882a593Smuzhiyun 		p_data_info->burst_num = ltoh16_ua(&p_data_info->burst_num);
1054*4882a593Smuzhiyun 		p_data_info->core_info = ltoh16_ua(&p_data_info->core_info);
1055*4882a593Smuzhiyun 		DHD_RTT(("\tsid=%u, state=%d, status=%d, burst_num=%u\n",
1056*4882a593Smuzhiyun 			p_data_info->sid, p_data_info->state,
1057*4882a593Smuzhiyun 			p_data_info->status, p_data_info->burst_num));
1058*4882a593Smuzhiyun 		DHD_RTT(("\tnum_cores=%u, core=%u\n", (p_data_info->core_info & 0xFF),
1059*4882a593Smuzhiyun 			(p_data_info->core_info >> 8u & 0xFF)));
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun 		break;
1062*4882a593Smuzhiyun 	case WL_PROXD_TLV_ID_COLLECT_DATA:
1063*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_DATA\n"));
1064*4882a593Smuzhiyun 		/* we do not have handle to wl in the context of
1065*4882a593Smuzhiyun 		 * xtlv callback without changing the xtlv API.
1066*4882a593Smuzhiyun 		 */
1067*4882a593Smuzhiyun 		rtt_collect_event_data_display(
1068*4882a593Smuzhiyun 			rtt_collect_data_event_ver(len),
1069*4882a593Smuzhiyun 			ctx, p_data, len);
1070*4882a593Smuzhiyun 		break;
1071*4882a593Smuzhiyun 	case WL_PROXD_TLV_ID_COLLECT_CHAN_DATA:
1072*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1073*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_CHAN_DATA\n"));
1074*4882a593Smuzhiyun 		DHD_RTT(("\tchan est %u\n", (uint32) (len / sizeof(uint32))));
1075*4882a593Smuzhiyun 		for (i = 0; (uint16)i < (uint16)(len/sizeof(chan_data_entry)); i++) {
1076*4882a593Smuzhiyun 			uint32 *p = (uint32*)p_data;
1077*4882a593Smuzhiyun 			chan_data_entry = ltoh32_ua(p + i);
1078*4882a593Smuzhiyun 			DHD_RTT(("\t%u\n", chan_data_entry));
1079*4882a593Smuzhiyun 		}
1080*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_POP();
1081*4882a593Smuzhiyun 		break;
1082*4882a593Smuzhiyun 	case WL_PROXD_TLV_ID_MF_STATS_DATA:
1083*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_TLV_ID_MF_STATS_DATA\n"));
1084*4882a593Smuzhiyun 		DHD_RTT(("\tmf stats len=%u\n", len));
1085*4882a593Smuzhiyun 		rtt_prhex("", p_data, len);
1086*4882a593Smuzhiyun 		break;
1087*4882a593Smuzhiyun 	default:
1088*4882a593Smuzhiyun 		DHD_RTT_ERR(("> Unsupported TLV ID %d\n", tlvid));
1089*4882a593Smuzhiyun 		ret = BCME_ERROR;
1090*4882a593Smuzhiyun 		break;
1091*4882a593Smuzhiyun 	}
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun 	return ret;
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun #ifdef WL_CFG80211
1097*4882a593Smuzhiyun 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)1098*4882a593Smuzhiyun rtt_handle_config_options(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv,
1099*4882a593Smuzhiyun 	uint16 *p_buf_space_left, ftm_config_options_info_t *ftm_configs, int ftm_cfg_cnt)
1100*4882a593Smuzhiyun {
1101*4882a593Smuzhiyun 	int ret = BCME_OK;
1102*4882a593Smuzhiyun 	int cfg_idx = 0;
1103*4882a593Smuzhiyun 	uint32 flags = WL_PROXD_FLAG_NONE;
1104*4882a593Smuzhiyun 	uint32 flags_mask = WL_PROXD_FLAG_NONE;
1105*4882a593Smuzhiyun 	uint32 new_mask;		/* cmdline input */
1106*4882a593Smuzhiyun 	ftm_config_options_info_t *p_option_info;
1107*4882a593Smuzhiyun 	uint16 type = (session_id == WL_PROXD_SESSION_ID_GLOBAL) ?
1108*4882a593Smuzhiyun 			WL_PROXD_TLV_ID_FLAGS_MASK : WL_PROXD_TLV_ID_SESSION_FLAGS_MASK;
1109*4882a593Smuzhiyun 	for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) {
1110*4882a593Smuzhiyun 		p_option_info = (ftm_configs + cfg_idx);
1111*4882a593Smuzhiyun 		if (p_option_info != NULL) {
1112*4882a593Smuzhiyun 			new_mask = p_option_info->flags;
1113*4882a593Smuzhiyun 			/* update flags mask */
1114*4882a593Smuzhiyun 			flags_mask |= new_mask;
1115*4882a593Smuzhiyun 			if (p_option_info->enable) {
1116*4882a593Smuzhiyun 				flags |= new_mask;	/* set the bit on */
1117*4882a593Smuzhiyun 			} else {
1118*4882a593Smuzhiyun 				flags &= ~new_mask;	/* set the bit off */
1119*4882a593Smuzhiyun 			}
1120*4882a593Smuzhiyun 		}
1121*4882a593Smuzhiyun 	}
1122*4882a593Smuzhiyun 	flags = htol32(flags);
1123*4882a593Smuzhiyun 	flags_mask = htol32(flags_mask);
1124*4882a593Smuzhiyun 	/* setup flags_mask TLV */
1125*4882a593Smuzhiyun 	ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left,
1126*4882a593Smuzhiyun 		type, sizeof(uint32), (uint8 *)&flags_mask, BCM_XTLV_OPTION_ALIGN32);
1127*4882a593Smuzhiyun 	if (ret != BCME_OK) {
1128*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n",
1129*4882a593Smuzhiyun 			__FUNCTION__, ret));
1130*4882a593Smuzhiyun 		goto exit;
1131*4882a593Smuzhiyun 	}
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 	type = (session_id == WL_PROXD_SESSION_ID_GLOBAL)?
1134*4882a593Smuzhiyun 		WL_PROXD_TLV_ID_FLAGS : WL_PROXD_TLV_ID_SESSION_FLAGS;
1135*4882a593Smuzhiyun 	/* setup flags TLV */
1136*4882a593Smuzhiyun 	ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left,
1137*4882a593Smuzhiyun 			type, sizeof(uint32), (uint8 *)&flags, BCM_XTLV_OPTION_ALIGN32);
1138*4882a593Smuzhiyun 		if (ret != BCME_OK) {
1139*4882a593Smuzhiyun #ifdef RTT_DEBUG
1140*4882a593Smuzhiyun 			DHD_RTT(("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n",
1141*4882a593Smuzhiyun 				__FUNCTION__, ret));
1142*4882a593Smuzhiyun #endif
1143*4882a593Smuzhiyun 		}
1144*4882a593Smuzhiyun exit:
1145*4882a593Smuzhiyun 	return ret;
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun static int
rtt_handle_config_general(wl_proxd_session_id_t session_id,wl_proxd_tlv_t ** p_tlv,uint16 * p_buf_space_left,ftm_config_param_info_t * ftm_configs,int ftm_cfg_cnt)1149*4882a593Smuzhiyun rtt_handle_config_general(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv,
1150*4882a593Smuzhiyun 	uint16 *p_buf_space_left, ftm_config_param_info_t *ftm_configs, int ftm_cfg_cnt)
1151*4882a593Smuzhiyun {
1152*4882a593Smuzhiyun 	int ret = BCME_OK;
1153*4882a593Smuzhiyun 	int cfg_idx = 0;
1154*4882a593Smuzhiyun 	uint32 chanspec;
1155*4882a593Smuzhiyun 	ftm_config_param_info_t *p_config_param_info;
1156*4882a593Smuzhiyun 	void		*p_src_data;
1157*4882a593Smuzhiyun 	uint16	src_data_size;	/* size of data pointed by p_src_data as 'source' */
1158*4882a593Smuzhiyun 	for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) {
1159*4882a593Smuzhiyun 		p_config_param_info = (ftm_configs + cfg_idx);
1160*4882a593Smuzhiyun 		if (p_config_param_info != NULL) {
1161*4882a593Smuzhiyun 			switch (p_config_param_info->tlvid)	{
1162*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_BSS_INDEX:
1163*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_FTM_RETRIES:
1164*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_FTM_REQ_RETRIES:
1165*4882a593Smuzhiyun 				p_src_data = &p_config_param_info->data8;
1166*4882a593Smuzhiyun 				src_data_size = sizeof(uint8);
1167*4882a593Smuzhiyun 				break;
1168*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* uint16 */
1169*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_NUM_BURST:
1170*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_RX_MAX_BURST:
1171*4882a593Smuzhiyun 				p_src_data = &p_config_param_info->data16;
1172*4882a593Smuzhiyun 				src_data_size = sizeof(uint16);
1173*4882a593Smuzhiyun 				break;
1174*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_TX_POWER:		/* uint32 */
1175*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_RATESPEC:
1176*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_EVENT_MASK: /* wl_proxd_event_mask_t/uint32 */
1177*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_DEBUG_MASK:
1178*4882a593Smuzhiyun 				p_src_data = &p_config_param_info->data32;
1179*4882a593Smuzhiyun 				src_data_size = sizeof(uint32);
1180*4882a593Smuzhiyun 				break;
1181*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_CHANSPEC:		/* chanspec_t --> 32bit */
1182*4882a593Smuzhiyun 				chanspec = p_config_param_info->chanspec;
1183*4882a593Smuzhiyun 				p_src_data = (void *) &chanspec;
1184*4882a593Smuzhiyun 				src_data_size = sizeof(uint32);
1185*4882a593Smuzhiyun 				break;
1186*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_BSSID: /* mac address */
1187*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_PEER_MAC:
1188*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_CUR_ETHER_ADDR:
1189*4882a593Smuzhiyun 				p_src_data = &p_config_param_info->mac_addr;
1190*4882a593Smuzhiyun 				src_data_size = sizeof(struct ether_addr);
1191*4882a593Smuzhiyun 				break;
1192*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_BURST_DURATION:	/* wl_proxd_intvl_t */
1193*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_BURST_PERIOD:
1194*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_BURST_FTM_SEP:
1195*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_BURST_TIMEOUT:
1196*4882a593Smuzhiyun 			case WL_PROXD_TLV_ID_INIT_DELAY:
1197*4882a593Smuzhiyun 				p_src_data = &p_config_param_info->data_intvl;
1198*4882a593Smuzhiyun 				src_data_size = sizeof(wl_proxd_intvl_t);
1199*4882a593Smuzhiyun 				break;
1200*4882a593Smuzhiyun 			default:
1201*4882a593Smuzhiyun 				ret = BCME_BADARG;
1202*4882a593Smuzhiyun 				break;
1203*4882a593Smuzhiyun 			}
1204*4882a593Smuzhiyun 			if (ret != BCME_OK) {
1205*4882a593Smuzhiyun 				DHD_RTT_ERR(("%s bad TLV ID : %d\n",
1206*4882a593Smuzhiyun 					__FUNCTION__, p_config_param_info->tlvid));
1207*4882a593Smuzhiyun 				break;
1208*4882a593Smuzhiyun 			}
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 			ret = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left,
1211*4882a593Smuzhiyun 				p_config_param_info->tlvid, src_data_size, (uint8 *)p_src_data,
1212*4882a593Smuzhiyun 				BCM_XTLV_OPTION_ALIGN32);
1213*4882a593Smuzhiyun 			if (ret != BCME_OK) {
1214*4882a593Smuzhiyun 				DHD_RTT_ERR(("%s: bcm_pack_xltv_entry() failed,"
1215*4882a593Smuzhiyun 					" status=%d\n", __FUNCTION__, ret));
1216*4882a593Smuzhiyun 				break;
1217*4882a593Smuzhiyun 			}
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 		}
1220*4882a593Smuzhiyun 	}
1221*4882a593Smuzhiyun 	return ret;
1222*4882a593Smuzhiyun }
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun static int
dhd_rtt_ftm_enable(dhd_pub_t * dhd,bool enable)1225*4882a593Smuzhiyun dhd_rtt_ftm_enable(dhd_pub_t *dhd, bool enable)
1226*4882a593Smuzhiyun {
1227*4882a593Smuzhiyun 	ftm_subcmd_info_t subcmd_info;
1228*4882a593Smuzhiyun 	subcmd_info.name = (enable)? "enable" : "disable";
1229*4882a593Smuzhiyun 	subcmd_info.cmdid = (enable)? WL_PROXD_CMD_ENABLE: WL_PROXD_CMD_DISABLE;
1230*4882a593Smuzhiyun 	subcmd_info.handler = NULL;
1231*4882a593Smuzhiyun 	return dhd_rtt_common_set_handler(dhd, &subcmd_info,
1232*4882a593Smuzhiyun 			WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL);
1233*4882a593Smuzhiyun }
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun static int
dhd_rtt_start_session(dhd_pub_t * dhd,wl_proxd_session_id_t session_id,bool start)1236*4882a593Smuzhiyun dhd_rtt_start_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, bool start)
1237*4882a593Smuzhiyun {
1238*4882a593Smuzhiyun 	ftm_subcmd_info_t subcmd_info;
1239*4882a593Smuzhiyun 	subcmd_info.name = (start)? "start session" : "stop session";
1240*4882a593Smuzhiyun 	subcmd_info.cmdid = (start)? WL_PROXD_CMD_START_SESSION: WL_PROXD_CMD_STOP_SESSION;
1241*4882a593Smuzhiyun 	subcmd_info.handler = NULL;
1242*4882a593Smuzhiyun 	return dhd_rtt_common_set_handler(dhd, &subcmd_info,
1243*4882a593Smuzhiyun 			WL_PROXD_METHOD_FTM, session_id);
1244*4882a593Smuzhiyun }
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun static int
dhd_rtt_delete_session(dhd_pub_t * dhd,wl_proxd_session_id_t session_id)1247*4882a593Smuzhiyun dhd_rtt_delete_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id)
1248*4882a593Smuzhiyun {
1249*4882a593Smuzhiyun 	ftm_subcmd_info_t subcmd_info;
1250*4882a593Smuzhiyun 	subcmd_info.name = "delete session";
1251*4882a593Smuzhiyun 	subcmd_info.cmdid = WL_PROXD_CMD_DELETE_SESSION;
1252*4882a593Smuzhiyun 	subcmd_info.handler = NULL;
1253*4882a593Smuzhiyun 	return dhd_rtt_common_set_handler(dhd, &subcmd_info,
1254*4882a593Smuzhiyun 			WL_PROXD_METHOD_FTM, session_id);
1255*4882a593Smuzhiyun }
1256*4882a593Smuzhiyun #ifdef WL_NAN
1257*4882a593Smuzhiyun int
dhd_rtt_delete_nan_session(dhd_pub_t * dhd)1258*4882a593Smuzhiyun dhd_rtt_delete_nan_session(dhd_pub_t *dhd)
1259*4882a593Smuzhiyun {
1260*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
1261*4882a593Smuzhiyun 	struct wireless_dev *wdev = ndev_to_wdev(dev);
1262*4882a593Smuzhiyun 	struct wiphy *wiphy = wdev->wiphy;
1263*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1264*4882a593Smuzhiyun 	wl_cfgnan_terminate_directed_rtt_sessions(dev, cfg);
1265*4882a593Smuzhiyun 	return BCME_OK;
1266*4882a593Smuzhiyun }
1267*4882a593Smuzhiyun /* API to find out if the given Peer Mac from FTM events
1268*4882a593Smuzhiyun * is nan-peer. Based on this we will handle the SESSION_END
1269*4882a593Smuzhiyun * event. For nan-peer FTM_SESSION_END event is ignored and handled in
1270*4882a593Smuzhiyun * nan-ranging-cancel or nan-ranging-end event.
1271*4882a593Smuzhiyun */
1272*4882a593Smuzhiyun static bool
dhd_rtt_is_nan_peer(dhd_pub_t * dhd,struct ether_addr * peer_mac)1273*4882a593Smuzhiyun dhd_rtt_is_nan_peer(dhd_pub_t *dhd, struct ether_addr *peer_mac)
1274*4882a593Smuzhiyun {
1275*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
1276*4882a593Smuzhiyun 	struct wireless_dev *wdev = ndev_to_wdev(dev);
1277*4882a593Smuzhiyun 	struct wiphy *wiphy = wdev->wiphy;
1278*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1279*4882a593Smuzhiyun 	nan_ranging_inst_t *ranging_inst = NULL;
1280*4882a593Smuzhiyun 	bool ret = FALSE;
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 	if ((wl_cfgnan_is_enabled(cfg) == FALSE) || ETHER_ISNULLADDR(peer_mac)) {
1283*4882a593Smuzhiyun 		goto exit;
1284*4882a593Smuzhiyun 	}
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	ranging_inst = wl_cfgnan_check_for_ranging(cfg, peer_mac);
1287*4882a593Smuzhiyun 	if (ranging_inst) {
1288*4882a593Smuzhiyun 		DHD_RTT((" RTT peer is of type NAN\n"));
1289*4882a593Smuzhiyun 		ret = TRUE;
1290*4882a593Smuzhiyun 		goto exit;
1291*4882a593Smuzhiyun 	}
1292*4882a593Smuzhiyun exit:
1293*4882a593Smuzhiyun 	return ret;
1294*4882a593Smuzhiyun }
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun bool
dhd_rtt_nan_is_directed_setup_in_prog(dhd_pub_t * dhd)1297*4882a593Smuzhiyun dhd_rtt_nan_is_directed_setup_in_prog(dhd_pub_t *dhd)
1298*4882a593Smuzhiyun {
1299*4882a593Smuzhiyun 	bool setup_in_prog;
1300*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 	setup_in_prog = rtt_status->directed_cfg.directed_setup_status.directed_na_setup_inprog;
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	return setup_in_prog;
1305*4882a593Smuzhiyun }
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun bool
dhd_rtt_nan_is_directed_setup_in_prog_with_peer(dhd_pub_t * dhd,struct ether_addr * peer)1308*4882a593Smuzhiyun dhd_rtt_nan_is_directed_setup_in_prog_with_peer(dhd_pub_t *dhd,
1309*4882a593Smuzhiyun 		struct ether_addr *peer)
1310*4882a593Smuzhiyun {
1311*4882a593Smuzhiyun 	bool setup_in_prog = TRUE;
1312*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1313*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
1314*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1315*4882a593Smuzhiyun 	nan_ranging_inst_t *ranging_inst = NULL;
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	if (!dhd_rtt_nan_is_directed_setup_in_prog(dhd)) {
1318*4882a593Smuzhiyun 		setup_in_prog = FALSE;
1319*4882a593Smuzhiyun 		goto exit;
1320*4882a593Smuzhiyun 	}
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun 	ranging_inst = wl_cfgnan_check_for_ranging(cfg, peer);
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	if ((ranging_inst == NULL) ||
1325*4882a593Smuzhiyun 			(ranging_inst != rtt_status->directed_cfg.directed_setup_status.rng_inst)) {
1326*4882a593Smuzhiyun 		setup_in_prog = FALSE;
1327*4882a593Smuzhiyun 	}
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun exit:
1330*4882a593Smuzhiyun 	return setup_in_prog;
1331*4882a593Smuzhiyun }
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun void
dhd_rtt_nan_update_directed_setup_inprog(dhd_pub_t * dhd,nan_ranging_inst_t * rng_inst,bool inprog)1334*4882a593Smuzhiyun dhd_rtt_nan_update_directed_setup_inprog(dhd_pub_t *dhd,
1335*4882a593Smuzhiyun 	nan_ranging_inst_t *rng_inst, bool inprog)
1336*4882a593Smuzhiyun {
1337*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun 	rtt_status->directed_cfg.directed_setup_status.directed_na_setup_inprog = inprog;
1340*4882a593Smuzhiyun 	if (inprog) {
1341*4882a593Smuzhiyun 		ASSERT(rng_inst);
1342*4882a593Smuzhiyun 		rtt_status->directed_cfg.directed_setup_status.rng_inst = rng_inst;
1343*4882a593Smuzhiyun 	} else {
1344*4882a593Smuzhiyun 		rtt_status->directed_cfg.directed_setup_status.rng_inst = NULL;
1345*4882a593Smuzhiyun 	}
1346*4882a593Smuzhiyun }
1347*4882a593Smuzhiyun 
1348*4882a593Smuzhiyun bool
dhd_rtt_nan_directed_sessions_allowed(dhd_pub_t * dhd)1349*4882a593Smuzhiyun dhd_rtt_nan_directed_sessions_allowed(dhd_pub_t *dhd)
1350*4882a593Smuzhiyun {
1351*4882a593Smuzhiyun 	int max_sessions = 0;
1352*4882a593Smuzhiyun 	bool allowed = TRUE;
1353*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun 	max_sessions = rtt_status->max_nan_rtt_sessions;
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 	if (dhd_rtt_nan_is_directed_setup_in_prog(dhd)) {
1358*4882a593Smuzhiyun 		max_sessions--;
1359*4882a593Smuzhiyun 	}
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun 	if (rtt_status->directed_cfg.directed_sessions_cnt >= max_sessions) {
1362*4882a593Smuzhiyun 		allowed = FALSE;
1363*4882a593Smuzhiyun 	}
1364*4882a593Smuzhiyun 
1365*4882a593Smuzhiyun 	return allowed;
1366*4882a593Smuzhiyun }
1367*4882a593Smuzhiyun 
1368*4882a593Smuzhiyun bool
dhd_rtt_nan_all_directed_sessions_triggered(dhd_pub_t * dhd)1369*4882a593Smuzhiyun dhd_rtt_nan_all_directed_sessions_triggered(dhd_pub_t *dhd)
1370*4882a593Smuzhiyun {
1371*4882a593Smuzhiyun 	bool done;
1372*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun 	if ((rtt_status->cur_idx + 1) >= rtt_status->rtt_config.rtt_target_cnt) {
1375*4882a593Smuzhiyun 		done = TRUE;
1376*4882a593Smuzhiyun 	} else {
1377*4882a593Smuzhiyun 		done = FALSE;
1378*4882a593Smuzhiyun 	}
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun 	return done;
1381*4882a593Smuzhiyun }
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun void
dhd_rtt_nan_update_directed_sessions_cnt(dhd_pub_t * dhd,bool incr)1384*4882a593Smuzhiyun dhd_rtt_nan_update_directed_sessions_cnt(dhd_pub_t *dhd, bool incr)
1385*4882a593Smuzhiyun {
1386*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun 	if (incr) {
1389*4882a593Smuzhiyun 		rtt_status->directed_cfg.directed_sessions_cnt++;
1390*4882a593Smuzhiyun 	} else {
1391*4882a593Smuzhiyun 		rtt_status->directed_cfg.directed_sessions_cnt--;
1392*4882a593Smuzhiyun 	}
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun static void
dhd_rtt_event_trigger_failure(dhd_pub_t * dhd,rtt_target_info_t * rtt_target)1396*4882a593Smuzhiyun dhd_rtt_event_trigger_failure(dhd_pub_t *dhd, rtt_target_info_t *rtt_target)
1397*4882a593Smuzhiyun {
1398*4882a593Smuzhiyun 	wl_event_msg_t msg;
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
1401*4882a593Smuzhiyun 	wl_proxd_event_t p_event;
1402*4882a593Smuzhiyun 
1403*4882a593Smuzhiyun 	bzero(&msg, sizeof(wl_event_msg_t));
1404*4882a593Smuzhiyun 	bzero(&p_event, sizeof(p_event));
1405*4882a593Smuzhiyun 
1406*4882a593Smuzhiyun 	msg.event_type =  hton32(WLC_E_PROXD);
1407*4882a593Smuzhiyun 	msg.bsscfgidx  =  0;
1408*4882a593Smuzhiyun 	msg.datalen = hton32(sizeof(p_event));
1409*4882a593Smuzhiyun 	msg.addr = rtt_target->addr;
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun 	p_event.version = htol16(WL_PROXD_API_VERSION);
1412*4882a593Smuzhiyun 	p_event.type = htol16(WL_PROXD_EVENT_SESSION_END);
1413*4882a593Smuzhiyun 	p_event.len = htol16(OFFSETOF(wl_proxd_event_t, tlvs));
1414*4882a593Smuzhiyun 
1415*4882a593Smuzhiyun 	wl_cfg80211_event(dev, &msg, &p_event);
1416*4882a593Smuzhiyun }
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun static int
dhd_rtt_nan_start_session(dhd_pub_t * dhd,rtt_target_info_t * rtt_target)1419*4882a593Smuzhiyun dhd_rtt_nan_start_session(dhd_pub_t *dhd, rtt_target_info_t *rtt_target)
1420*4882a593Smuzhiyun {
1421*4882a593Smuzhiyun 	s32 err = BCME_OK;
1422*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
1423*4882a593Smuzhiyun 	struct wireless_dev *wdev = ndev_to_wdev(dev);
1424*4882a593Smuzhiyun 	struct wiphy *wiphy = wdev->wiphy;
1425*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1426*4882a593Smuzhiyun 	nan_ranging_inst_t *ranging_inst = NULL;
1427*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 	NAN_MUTEX_LOCK();
1430*4882a593Smuzhiyun 
1431*4882a593Smuzhiyun 	if (!rtt_status) {
1432*4882a593Smuzhiyun 		err = BCME_NOTENABLED;
1433*4882a593Smuzhiyun 		goto done;
1434*4882a593Smuzhiyun 	}
1435*4882a593Smuzhiyun 
1436*4882a593Smuzhiyun 	if (!wl_cfgnan_is_enabled(cfg)) { /* If nan is not enabled report error */
1437*4882a593Smuzhiyun 		err = BCME_NOTENABLED;
1438*4882a593Smuzhiyun 		goto done;
1439*4882a593Smuzhiyun 	}
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun 	/* Below Scenarios should be avoided by callers/schedulers */
1442*4882a593Smuzhiyun 	if (dhd_rtt_nan_is_directed_setup_in_prog(dhd)) {
1443*4882a593Smuzhiyun 		DHD_RTT_ERR(("dhd_rtt_nan_start_session failed, setup already in prog\n"));
1444*4882a593Smuzhiyun 		err = BCME_ERROR;
1445*4882a593Smuzhiyun 		ASSERT(0);
1446*4882a593Smuzhiyun 		goto done;
1447*4882a593Smuzhiyun 	}
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	if (!dhd_rtt_nan_directed_sessions_allowed(dhd)) {
1450*4882a593Smuzhiyun 		DHD_RTT_ERR(("dhd_rtt_nan_start_session failed, already max sessions running\n"));
1451*4882a593Smuzhiyun 		err = BCME_ERROR;
1452*4882a593Smuzhiyun 		ASSERT(0);
1453*4882a593Smuzhiyun 		goto done;
1454*4882a593Smuzhiyun 	}
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun 	ranging_inst = wl_cfgnan_get_ranging_inst(cfg,
1457*4882a593Smuzhiyun 			&rtt_target->addr, NAN_RANGING_ROLE_INITIATOR);
1458*4882a593Smuzhiyun 	if (!ranging_inst) {
1459*4882a593Smuzhiyun 		err = BCME_NORESOURCE;
1460*4882a593Smuzhiyun 		goto done;
1461*4882a593Smuzhiyun 	}
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	DHD_RTT(("Trigger nan based range request\n"));
1464*4882a593Smuzhiyun 	err = wl_cfgnan_trigger_ranging(bcmcfg_to_prmry_ndev(cfg),
1465*4882a593Smuzhiyun 			cfg, ranging_inst, NULL, NAN_RANGE_REQ_CMD, TRUE);
1466*4882a593Smuzhiyun 	if (unlikely(err)) {
1467*4882a593Smuzhiyun 		goto done;
1468*4882a593Smuzhiyun 	}
1469*4882a593Smuzhiyun 	ranging_inst->range_type = RTT_TYPE_NAN_DIRECTED;
1470*4882a593Smuzhiyun 	ranging_inst->range_role = NAN_RANGING_ROLE_INITIATOR;
1471*4882a593Smuzhiyun 	dhd_rtt_nan_update_directed_setup_inprog(dhd, ranging_inst, TRUE);
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun done:
1474*4882a593Smuzhiyun 	if (err) {
1475*4882a593Smuzhiyun 		DHD_RTT_ERR(("Failed to issue Nan Ranging Request err %d\n", err));
1476*4882a593Smuzhiyun 		/* Fake session end event which will help in
1477*4882a593Smuzhiyun 		* scheduling the new target in the deffered context instead of here
1478*4882a593Smuzhiyun 		* i.e, avoid scheduling work from itself
1479*4882a593Smuzhiyun 		*/
1480*4882a593Smuzhiyun 		dhd_rtt_event_trigger_failure(dhd, rtt_target);
1481*4882a593Smuzhiyun 	}
1482*4882a593Smuzhiyun 	NAN_MUTEX_UNLOCK();
1483*4882a593Smuzhiyun 	return err;
1484*4882a593Smuzhiyun }
1485*4882a593Smuzhiyun #endif /* WL_NAN */
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun static int
dhd_rtt_ftm_config(dhd_pub_t * dhd,wl_proxd_session_id_t session_id,ftm_config_category_t catagory,void * ftm_configs,int ftm_cfg_cnt)1488*4882a593Smuzhiyun dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id,
1489*4882a593Smuzhiyun 	ftm_config_category_t catagory, void *ftm_configs, int ftm_cfg_cnt)
1490*4882a593Smuzhiyun {
1491*4882a593Smuzhiyun 	ftm_subcmd_info_t subcmd_info;
1492*4882a593Smuzhiyun 	wl_proxd_tlv_t *p_tlv;
1493*4882a593Smuzhiyun 	/* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */
1494*4882a593Smuzhiyun 	wl_proxd_iov_t *p_proxd_iov;
1495*4882a593Smuzhiyun 	uint16 proxd_iovsize = 0;
1496*4882a593Smuzhiyun 	uint16 bufsize;
1497*4882a593Smuzhiyun 	uint16 buf_space_left;
1498*4882a593Smuzhiyun 	uint16 all_tlvsize;
1499*4882a593Smuzhiyun 	int ret = BCME_OK;
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	subcmd_info.name = "config";
1502*4882a593Smuzhiyun 	subcmd_info.cmdid = WL_PROXD_CMD_CONFIG;
1503*4882a593Smuzhiyun 
1504*4882a593Smuzhiyun 	p_proxd_iov = rtt_alloc_getset_buf(dhd, WL_PROXD_METHOD_FTM, session_id, subcmd_info.cmdid,
1505*4882a593Smuzhiyun 			FTM_IOC_BUFSZ, &proxd_iovsize);
1506*4882a593Smuzhiyun 
1507*4882a593Smuzhiyun 	if (p_proxd_iov == NULL) {
1508*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s : failed to allocate the iovar (size :%d)\n",
1509*4882a593Smuzhiyun 			__FUNCTION__, FTM_IOC_BUFSZ));
1510*4882a593Smuzhiyun 		return BCME_NOMEM;
1511*4882a593Smuzhiyun 	}
1512*4882a593Smuzhiyun 	/* setup TLVs */
1513*4882a593Smuzhiyun 	bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */
1514*4882a593Smuzhiyun 	p_tlv = &p_proxd_iov->tlvs[0];
1515*4882a593Smuzhiyun 	/* TLV buffer starts with a full size, will decrement for each packed TLV */
1516*4882a593Smuzhiyun 	buf_space_left = bufsize;
1517*4882a593Smuzhiyun 	if (catagory == FTM_CONFIG_CAT_OPTIONS) {
1518*4882a593Smuzhiyun 		ret = rtt_handle_config_options(session_id, &p_tlv, &buf_space_left,
1519*4882a593Smuzhiyun 				(ftm_config_options_info_t *)ftm_configs, ftm_cfg_cnt);
1520*4882a593Smuzhiyun 	} else if (catagory == FTM_CONFIG_CAT_GENERAL) {
1521*4882a593Smuzhiyun 		ret = rtt_handle_config_general(session_id, &p_tlv, &buf_space_left,
1522*4882a593Smuzhiyun 				(ftm_config_param_info_t *)ftm_configs, ftm_cfg_cnt);
1523*4882a593Smuzhiyun 	}
1524*4882a593Smuzhiyun 	if (ret == BCME_OK) {
1525*4882a593Smuzhiyun 		/* update the iov header, set len to include all TLVs + header */
1526*4882a593Smuzhiyun 		all_tlvsize = (bufsize - buf_space_left);
1527*4882a593Smuzhiyun 		p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
1528*4882a593Smuzhiyun 		ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov,
1529*4882a593Smuzhiyun 				all_tlvsize + WL_PROXD_IOV_HDR_SIZE, NULL, 0, TRUE);
1530*4882a593Smuzhiyun 		if (ret != BCME_OK) {
1531*4882a593Smuzhiyun 			DHD_RTT_ERR(("%s : failed to set config err %d\n", __FUNCTION__, ret));
1532*4882a593Smuzhiyun 		}
1533*4882a593Smuzhiyun 	}
1534*4882a593Smuzhiyun 	/* clean up */
1535*4882a593Smuzhiyun 	MFREE(dhd->osh, p_proxd_iov, proxd_iovsize);
1536*4882a593Smuzhiyun 	return ret;
1537*4882a593Smuzhiyun }
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun static int
dhd_rtt_get_version(dhd_pub_t * dhd,int * out_version)1540*4882a593Smuzhiyun dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version)
1541*4882a593Smuzhiyun {
1542*4882a593Smuzhiyun 	int ret;
1543*4882a593Smuzhiyun 	ftm_subcmd_info_t subcmd_info;
1544*4882a593Smuzhiyun 	subcmd_info.name = "ver";
1545*4882a593Smuzhiyun 	subcmd_info.cmdid = WL_PROXD_CMD_GET_VERSION;
1546*4882a593Smuzhiyun 	subcmd_info.handler = NULL;
1547*4882a593Smuzhiyun 	ret = dhd_rtt_common_get_handler(dhd, &subcmd_info,
1548*4882a593Smuzhiyun 			WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL);
1549*4882a593Smuzhiyun 	*out_version = (ret == BCME_OK) ? subcmd_info.version : 0;
1550*4882a593Smuzhiyun 	return ret;
1551*4882a593Smuzhiyun }
1552*4882a593Smuzhiyun #endif /* WL_CFG80211 */
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun chanspec_t
dhd_rtt_convert_to_chspec(wifi_channel_info channel)1555*4882a593Smuzhiyun dhd_rtt_convert_to_chspec(wifi_channel_info channel)
1556*4882a593Smuzhiyun {
1557*4882a593Smuzhiyun 	int bw;
1558*4882a593Smuzhiyun 	chanspec_t chanspec = 0;
1559*4882a593Smuzhiyun 	uint8 center_chan;
1560*4882a593Smuzhiyun 	uint8 primary_chan;
1561*4882a593Smuzhiyun 	/* set witdh to 20MHZ for 2.4G HZ */
1562*4882a593Smuzhiyun 	if (channel.center_freq >= 2400 && channel.center_freq <= 2500) {
1563*4882a593Smuzhiyun 		channel.width = WIFI_CHAN_WIDTH_20;
1564*4882a593Smuzhiyun 	}
1565*4882a593Smuzhiyun 	switch (channel.width) {
1566*4882a593Smuzhiyun 	case WIFI_CHAN_WIDTH_20:
1567*4882a593Smuzhiyun 		bw = WL_CHANSPEC_BW_20;
1568*4882a593Smuzhiyun 		primary_chan = wf_mhz2channel(channel.center_freq, 0);
1569*4882a593Smuzhiyun 		chanspec = wf_channel2chspec(primary_chan, bw);
1570*4882a593Smuzhiyun 		break;
1571*4882a593Smuzhiyun 	case WIFI_CHAN_WIDTH_40:
1572*4882a593Smuzhiyun 		bw = WL_CHANSPEC_BW_40;
1573*4882a593Smuzhiyun 		primary_chan = wf_mhz2channel(channel.center_freq, 0);
1574*4882a593Smuzhiyun 		chanspec = wf_channel2chspec(primary_chan, bw);
1575*4882a593Smuzhiyun 		break;
1576*4882a593Smuzhiyun 	case WIFI_CHAN_WIDTH_80:
1577*4882a593Smuzhiyun 		bw = WL_CHANSPEC_BW_80;
1578*4882a593Smuzhiyun 		primary_chan = wf_mhz2channel(channel.center_freq, 0);
1579*4882a593Smuzhiyun 		center_chan = wf_mhz2channel(channel.center_freq0, 0);
1580*4882a593Smuzhiyun 		chanspec = wf_chspec_80(center_chan, primary_chan);
1581*4882a593Smuzhiyun 		break;
1582*4882a593Smuzhiyun 	default:
1583*4882a593Smuzhiyun 		DHD_RTT_ERR(("doesn't support this bandwith : %d", channel.width));
1584*4882a593Smuzhiyun 		bw = -1;
1585*4882a593Smuzhiyun 		break;
1586*4882a593Smuzhiyun 	}
1587*4882a593Smuzhiyun 	return chanspec;
1588*4882a593Smuzhiyun }
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun int
dhd_rtt_idx_to_burst_duration(uint idx)1591*4882a593Smuzhiyun dhd_rtt_idx_to_burst_duration(uint idx)
1592*4882a593Smuzhiyun {
1593*4882a593Smuzhiyun 	if (idx >= ARRAY_SIZE(burst_duration_idx)) {
1594*4882a593Smuzhiyun 		return -1;
1595*4882a593Smuzhiyun 	}
1596*4882a593Smuzhiyun 	return burst_duration_idx[idx];
1597*4882a593Smuzhiyun }
1598*4882a593Smuzhiyun 
1599*4882a593Smuzhiyun int8
dhd_rtt_get_cur_target_idx(dhd_pub_t * dhd)1600*4882a593Smuzhiyun dhd_rtt_get_cur_target_idx(dhd_pub_t *dhd)
1601*4882a593Smuzhiyun {
1602*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun 	return rtt_status->cur_idx;
1605*4882a593Smuzhiyun }
1606*4882a593Smuzhiyun 
1607*4882a593Smuzhiyun int8
dhd_rtt_set_next_target_idx(dhd_pub_t * dhd,int start_idx)1608*4882a593Smuzhiyun dhd_rtt_set_next_target_idx(dhd_pub_t *dhd, int start_idx)
1609*4882a593Smuzhiyun {
1610*4882a593Smuzhiyun 	int idx;
1611*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1612*4882a593Smuzhiyun 
1613*4882a593Smuzhiyun 	for (idx = start_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
1614*4882a593Smuzhiyun 		/* skip the disabled device */
1615*4882a593Smuzhiyun 		if (rtt_status->rtt_config.target_info[idx].disable) {
1616*4882a593Smuzhiyun 			continue;
1617*4882a593Smuzhiyun 		} else {
1618*4882a593Smuzhiyun 			/* set the idx to cur_idx */
1619*4882a593Smuzhiyun 			rtt_status->cur_idx = idx;
1620*4882a593Smuzhiyun 			break;
1621*4882a593Smuzhiyun 		}
1622*4882a593Smuzhiyun 	}
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 	if (idx == rtt_status->rtt_config.rtt_target_cnt) {
1625*4882a593Smuzhiyun 		/* All targets trigerred */
1626*4882a593Smuzhiyun 		rtt_status->cur_idx = rtt_status->rtt_config.rtt_target_cnt;
1627*4882a593Smuzhiyun 	}
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 	return (int8)rtt_status->cur_idx;
1630*4882a593Smuzhiyun }
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun void
dhd_rtt_set_target_list_mode(dhd_pub_t * dhd)1633*4882a593Smuzhiyun dhd_rtt_set_target_list_mode(dhd_pub_t *dhd)
1634*4882a593Smuzhiyun {
1635*4882a593Smuzhiyun 	int8 idx;
1636*4882a593Smuzhiyun 	bool legacy = FALSE, nan = FALSE;
1637*4882a593Smuzhiyun 	rtt_target_info_t *rtt_target;
1638*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	rtt_status->rtt_config.target_list_mode = RNG_TARGET_LIST_MODE_INVALID;
1641*4882a593Smuzhiyun 	for (idx = rtt_status->start_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
1642*4882a593Smuzhiyun 		rtt_target = &rtt_status->rtt_config.target_info[idx];
1643*4882a593Smuzhiyun 		/* skip the disabled device */
1644*4882a593Smuzhiyun 		if (rtt_target->disable) {
1645*4882a593Smuzhiyun 			continue;
1646*4882a593Smuzhiyun 		} else {
1647*4882a593Smuzhiyun 			if (rtt_target->peer == RTT_PEER_NAN) {
1648*4882a593Smuzhiyun 				nan = TRUE;
1649*4882a593Smuzhiyun 			} else {
1650*4882a593Smuzhiyun 				legacy = TRUE;
1651*4882a593Smuzhiyun 			}
1652*4882a593Smuzhiyun 		}
1653*4882a593Smuzhiyun 	}
1654*4882a593Smuzhiyun 
1655*4882a593Smuzhiyun 	if ((nan == TRUE) && (legacy == TRUE)) {
1656*4882a593Smuzhiyun 		rtt_status->rtt_config.target_list_mode = RNG_TARGET_LIST_MODE_MIX;
1657*4882a593Smuzhiyun 	} else if (nan == TRUE) {
1658*4882a593Smuzhiyun 		rtt_status->rtt_config.target_list_mode = RNG_TARGET_LIST_MODE_NAN;
1659*4882a593Smuzhiyun 	} else if (legacy == TRUE) {
1660*4882a593Smuzhiyun 		rtt_status->rtt_config.target_list_mode = RNG_TARGET_LIST_MODE_LEGACY;
1661*4882a593Smuzhiyun 	}
1662*4882a593Smuzhiyun }
1663*4882a593Smuzhiyun 
1664*4882a593Smuzhiyun int
dhd_rtt_set_cfg(dhd_pub_t * dhd,rtt_config_params_t * params)1665*4882a593Smuzhiyun dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params)
1666*4882a593Smuzhiyun {
1667*4882a593Smuzhiyun 	int err = BCME_OK;
1668*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = NULL;
1669*4882a593Smuzhiyun 	struct net_device *dev = NULL;
1670*4882a593Smuzhiyun 
1671*4882a593Smuzhiyun 	NULL_CHECK(params, "params is NULL", err);
1672*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
1673*4882a593Smuzhiyun 
1674*4882a593Smuzhiyun 	dev = dhd_linux_get_primary_netdev(dhd);
1675*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
1676*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
1677*4882a593Smuzhiyun 	NULL_CHECK(dev, "dev is NULL", err);
1678*4882a593Smuzhiyun 
1679*4882a593Smuzhiyun 	DHD_RTT(("%s enter\n", __FUNCTION__));
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 	if (!HAS_11MC_CAP(rtt_status->rtt_capa.proto)) {
1682*4882a593Smuzhiyun 		DHD_RTT_ERR(("doesn't support RTT \n"));
1683*4882a593Smuzhiyun 		err = BCME_ERROR;
1684*4882a593Smuzhiyun 		goto exit;
1685*4882a593Smuzhiyun 	}
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 	/* check if work is being scheduled ...cancel/sync if so
1688*4882a593Smuzhiyun 	* Host REQ has more priority , so we to have cancel any
1689*4882a593Smuzhiyun 	* geofence sessions in progress...for that we need to make sure
1690*4882a593Smuzhiyun 	* work queue is IDLE & then cancel the geofence sessions
1691*4882a593Smuzhiyun 	*/
1692*4882a593Smuzhiyun 	cancel_work_sync(&rtt_status->work);
1693*4882a593Smuzhiyun 
1694*4882a593Smuzhiyun 	mutex_lock(&rtt_status->rtt_mutex);
1695*4882a593Smuzhiyun 
1696*4882a593Smuzhiyun 	if (rtt_status->status != RTT_STOPPED) {
1697*4882a593Smuzhiyun 		DHD_RTT_ERR(("rtt is already started, status : %d\n", rtt_status->status));
1698*4882a593Smuzhiyun 		err = BCME_BUSY;
1699*4882a593Smuzhiyun 		goto exit;
1700*4882a593Smuzhiyun 	}
1701*4882a593Smuzhiyun 	if (params->rtt_target_cnt > 0) {
1702*4882a593Smuzhiyun #ifdef WL_NAN
1703*4882a593Smuzhiyun 		/* cancel ongoing geofence RTT both initiators and responders */
1704*4882a593Smuzhiyun 		wl_cfgnan_suspend_all_geofence_rng_sessions(dev,
1705*4882a593Smuzhiyun 			RTT_GEO_SUSPN_HOST_DIR_RTT_TRIG, 0);
1706*4882a593Smuzhiyun #endif /* WL_NAN */
1707*4882a593Smuzhiyun 	} else {
1708*4882a593Smuzhiyun 		err = BCME_BADARG;
1709*4882a593Smuzhiyun 		goto exit;
1710*4882a593Smuzhiyun 	}
1711*4882a593Smuzhiyun 
1712*4882a593Smuzhiyun 	memset(rtt_status->rtt_config.target_info, 0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
1713*4882a593Smuzhiyun 	rtt_status->rtt_config.rtt_target_cnt = params->rtt_target_cnt;
1714*4882a593Smuzhiyun 	memcpy(rtt_status->rtt_config.target_info,
1715*4882a593Smuzhiyun 		params->target_info, TARGET_INFO_SIZE(params->rtt_target_cnt));
1716*4882a593Smuzhiyun 	rtt_status->status = RTT_STARTED;
1717*4882a593Smuzhiyun 	DHD_RTT_MEM(("dhd_rtt_set_cfg: RTT Started, target_cnt = %d\n", params->rtt_target_cnt));
1718*4882a593Smuzhiyun 
1719*4882a593Smuzhiyun 	/* This is the starting Directed RTT index */
1720*4882a593Smuzhiyun 	rtt_status->start_idx = dhd_rtt_set_next_target_idx(dhd, 0);
1721*4882a593Smuzhiyun 
1722*4882a593Smuzhiyun 	dhd_rtt_set_target_list_mode(dhd);
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun 	if (rtt_status->cur_idx < rtt_status->rtt_config.rtt_target_cnt) {
1725*4882a593Smuzhiyun #ifdef WL_NAN
1726*4882a593Smuzhiyun 		if (rtt_status->rtt_config.target_list_mode == RNG_TARGET_LIST_MODE_NAN) {
1727*4882a593Smuzhiyun 			/* reset directed cfg params */
1728*4882a593Smuzhiyun 			dhd_rtt_nan_update_directed_setup_inprog(dhd, NULL, FALSE);
1729*4882a593Smuzhiyun 			rtt_status->directed_cfg.directed_sessions_cnt = 0;
1730*4882a593Smuzhiyun 
1731*4882a593Smuzhiyun 			/*
1732*4882a593Smuzhiyun 			 * schedule proxd timeout
1733*4882a593Smuzhiyun 			 * Proxd timeout for NAN target list is scheduled as a whole,
1734*4882a593Smuzhiyun 			 * and not per target, unlike for legacy target list
1735*4882a593Smuzhiyun 			 */
1736*4882a593Smuzhiyun 			schedule_delayed_work(&rtt_status->proxd_timeout,
1737*4882a593Smuzhiyun 				msecs_to_jiffies(DHD_NAN_RTT_TIMER_INTERVAL_MS));
1738*4882a593Smuzhiyun 		}
1739*4882a593Smuzhiyun #endif /* WL_NAN */
1740*4882a593Smuzhiyun 		/* schedule RTT */
1741*4882a593Smuzhiyun 		dhd_rtt_schedule_rtt_work_thread(dhd, RTT_SCHED_HOST_TRIGGER);
1742*4882a593Smuzhiyun 	}
1743*4882a593Smuzhiyun exit:
1744*4882a593Smuzhiyun 	mutex_unlock(&rtt_status->rtt_mutex);
1745*4882a593Smuzhiyun 	return err;
1746*4882a593Smuzhiyun }
1747*4882a593Smuzhiyun 
1748*4882a593Smuzhiyun #ifdef WL_NAN
1749*4882a593Smuzhiyun void
dhd_rtt_initialize_geofence_cfg(dhd_pub_t * dhd)1750*4882a593Smuzhiyun dhd_rtt_initialize_geofence_cfg(dhd_pub_t *dhd)
1751*4882a593Smuzhiyun {
1752*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1753*4882a593Smuzhiyun 	if (!rtt_status) {
1754*4882a593Smuzhiyun 		return;
1755*4882a593Smuzhiyun 	}
1756*4882a593Smuzhiyun 
1757*4882a593Smuzhiyun 	GEOFENCE_RTT_LOCK(rtt_status);
1758*4882a593Smuzhiyun 	memset_s(&rtt_status->geofence_cfg, sizeof(rtt_status->geofence_cfg),
1759*4882a593Smuzhiyun 		0, sizeof(rtt_status->geofence_cfg));
1760*4882a593Smuzhiyun 
1761*4882a593Smuzhiyun 	/* initialize non zero params of geofence cfg */
1762*4882a593Smuzhiyun 	rtt_status->geofence_cfg.cur_target_idx = DHD_RTT_INVALID_TARGET_INDEX;
1763*4882a593Smuzhiyun 	rtt_status->geofence_cfg.geofence_rtt_interval = DHD_RTT_RETRY_TIMER_INTERVAL_MS;
1764*4882a593Smuzhiyun 	rtt_status->geofence_cfg.geofence_sessions_cnt = 0;
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun 	rtt_status->geofence_cfg.max_geofence_sessions =
1767*4882a593Smuzhiyun 		dhd_rtt_get_max_nan_rtt_sessions_supported(dhd);
1768*4882a593Smuzhiyun 	GEOFENCE_RTT_UNLOCK(rtt_status);
1769*4882a593Smuzhiyun 	return;
1770*4882a593Smuzhiyun }
1771*4882a593Smuzhiyun 
1772*4882a593Smuzhiyun #ifdef RTT_GEOFENCE_CONT
1773*4882a593Smuzhiyun void
dhd_rtt_get_geofence_cont_ind(dhd_pub_t * dhd,bool * geofence_cont)1774*4882a593Smuzhiyun dhd_rtt_get_geofence_cont_ind(dhd_pub_t *dhd, bool* geofence_cont)
1775*4882a593Smuzhiyun {
1776*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1777*4882a593Smuzhiyun 	if (!rtt_status) {
1778*4882a593Smuzhiyun 		return;
1779*4882a593Smuzhiyun 	}
1780*4882a593Smuzhiyun 	GEOFENCE_RTT_LOCK(rtt_status);
1781*4882a593Smuzhiyun 	*geofence_cont = rtt_status->geofence_cfg.geofence_cont;
1782*4882a593Smuzhiyun 	GEOFENCE_RTT_UNLOCK(rtt_status);
1783*4882a593Smuzhiyun }
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun void
dhd_rtt_set_geofence_cont_ind(dhd_pub_t * dhd,bool geofence_cont)1786*4882a593Smuzhiyun dhd_rtt_set_geofence_cont_ind(dhd_pub_t *dhd, bool geofence_cont)
1787*4882a593Smuzhiyun {
1788*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1789*4882a593Smuzhiyun 	if (!rtt_status) {
1790*4882a593Smuzhiyun 		return;
1791*4882a593Smuzhiyun 	}
1792*4882a593Smuzhiyun 	GEOFENCE_RTT_LOCK(rtt_status);
1793*4882a593Smuzhiyun 	rtt_status->geofence_cfg.geofence_cont = geofence_cont;
1794*4882a593Smuzhiyun 	DHD_RTT(("dhd_rtt_set_geofence_cont_override, geofence_cont = %d\n",
1795*4882a593Smuzhiyun 		rtt_status->geofence_cfg.geofence_cont));
1796*4882a593Smuzhiyun 	GEOFENCE_RTT_UNLOCK(rtt_status);
1797*4882a593Smuzhiyun }
1798*4882a593Smuzhiyun #endif /* RTT_GEOFENCE_CONT */
1799*4882a593Smuzhiyun 
1800*4882a593Smuzhiyun #ifdef RTT_GEOFENCE_INTERVAL
1801*4882a593Smuzhiyun void
dhd_rtt_set_geofence_rtt_interval(dhd_pub_t * dhd,int interval)1802*4882a593Smuzhiyun dhd_rtt_set_geofence_rtt_interval(dhd_pub_t *dhd, int interval)
1803*4882a593Smuzhiyun {
1804*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1805*4882a593Smuzhiyun 	if (!rtt_status) {
1806*4882a593Smuzhiyun 		return;
1807*4882a593Smuzhiyun 	}
1808*4882a593Smuzhiyun 	GEOFENCE_RTT_LOCK(rtt_status);
1809*4882a593Smuzhiyun 	rtt_status->geofence_cfg.geofence_rtt_interval = interval;
1810*4882a593Smuzhiyun 	DHD_RTT(("dhd_rtt_set_geofence_rtt_interval: geofence interval = %d\n",
1811*4882a593Smuzhiyun 		rtt_status->geofence_cfg.geofence_rtt_interval));
1812*4882a593Smuzhiyun 	GEOFENCE_RTT_UNLOCK(rtt_status);
1813*4882a593Smuzhiyun }
1814*4882a593Smuzhiyun #endif /* RTT_GEOFENCE_INTERVAL */
1815*4882a593Smuzhiyun 
1816*4882a593Smuzhiyun int
dhd_rtt_get_geofence_max_sessions(dhd_pub_t * dhd)1817*4882a593Smuzhiyun dhd_rtt_get_geofence_max_sessions(dhd_pub_t *dhd)
1818*4882a593Smuzhiyun {
1819*4882a593Smuzhiyun 	int max_sessions;
1820*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1821*4882a593Smuzhiyun 	rtt_geofence_cfg_t* geofence_cfg = &rtt_status->geofence_cfg;
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun 	max_sessions = geofence_cfg->max_geofence_sessions;
1824*4882a593Smuzhiyun 	if (dhd_rtt_is_geofence_setup_inprog(dhd)) {
1825*4882a593Smuzhiyun 		/* One slot busy with setup in prog */
1826*4882a593Smuzhiyun 		max_sessions -= 1;
1827*4882a593Smuzhiyun 	}
1828*4882a593Smuzhiyun 
1829*4882a593Smuzhiyun 	return max_sessions;
1830*4882a593Smuzhiyun }
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun /*
1833*4882a593Smuzhiyun  * Return True, if geofence
1834*4882a593Smuzhiyun  * session count maxed out
1835*4882a593Smuzhiyun  */
1836*4882a593Smuzhiyun bool
dhd_rtt_geofence_sessions_maxed_out(dhd_pub_t * dhd)1837*4882a593Smuzhiyun dhd_rtt_geofence_sessions_maxed_out(dhd_pub_t *dhd)
1838*4882a593Smuzhiyun {
1839*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1840*4882a593Smuzhiyun 	rtt_geofence_cfg_t* geofence_cfg = &rtt_status->geofence_cfg;
1841*4882a593Smuzhiyun 	bool ret = TRUE;
1842*4882a593Smuzhiyun 
1843*4882a593Smuzhiyun 	if (geofence_cfg->geofence_sessions_cnt <
1844*4882a593Smuzhiyun 		dhd_rtt_get_geofence_max_sessions(dhd)) {
1845*4882a593Smuzhiyun 		ret = FALSE;
1846*4882a593Smuzhiyun 	}
1847*4882a593Smuzhiyun 
1848*4882a593Smuzhiyun 	return ret;
1849*4882a593Smuzhiyun }
1850*4882a593Smuzhiyun 
1851*4882a593Smuzhiyun int
dhd_rtt_get_geofence_sessions_cnt(dhd_pub_t * dhd)1852*4882a593Smuzhiyun dhd_rtt_get_geofence_sessions_cnt(dhd_pub_t *dhd)
1853*4882a593Smuzhiyun {
1854*4882a593Smuzhiyun 
1855*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1856*4882a593Smuzhiyun 	rtt_geofence_cfg_t* geofence_cfg = &rtt_status->geofence_cfg;
1857*4882a593Smuzhiyun 
1858*4882a593Smuzhiyun 	return geofence_cfg->geofence_sessions_cnt;
1859*4882a593Smuzhiyun }
1860*4882a593Smuzhiyun 
1861*4882a593Smuzhiyun int
dhd_rtt_update_geofence_sessions_cnt(dhd_pub_t * dhd,bool incr,struct ether_addr * peer_addr)1862*4882a593Smuzhiyun dhd_rtt_update_geofence_sessions_cnt(dhd_pub_t *dhd, bool incr,
1863*4882a593Smuzhiyun 	struct ether_addr *peer_addr)
1864*4882a593Smuzhiyun {
1865*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1866*4882a593Smuzhiyun 	rtt_geofence_cfg_t* geofence_cfg = &rtt_status->geofence_cfg;
1867*4882a593Smuzhiyun 	int ret = BCME_OK;
1868*4882a593Smuzhiyun 
1869*4882a593Smuzhiyun 	if (incr) {
1870*4882a593Smuzhiyun 		//ASSERT(!dhd_rtt_geofence_sessions_maxed_out(dhd));
1871*4882a593Smuzhiyun 		if (dhd_rtt_geofence_sessions_maxed_out(dhd)) {
1872*4882a593Smuzhiyun 			ret = BCME_ERROR;
1873*4882a593Smuzhiyun 			goto exit;
1874*4882a593Smuzhiyun 		}
1875*4882a593Smuzhiyun 		geofence_cfg->geofence_sessions_cnt++;
1876*4882a593Smuzhiyun 	} else {
1877*4882a593Smuzhiyun 		if (peer_addr && dhd_rtt_is_geofence_setup_inprog_with_peer(dhd,
1878*4882a593Smuzhiyun 				peer_addr)) {
1879*4882a593Smuzhiyun 			/* Set geofence RTT in progress state to false */
1880*4882a593Smuzhiyun 			dhd_rtt_set_geofence_setup_status(dhd, FALSE, NULL);
1881*4882a593Smuzhiyun 		} else {
1882*4882a593Smuzhiyun 			//ASSERT(geofence_cfg->geofence_sessions_cnt > 0);
1883*4882a593Smuzhiyun 			if (geofence_cfg->geofence_sessions_cnt <= 0) {
1884*4882a593Smuzhiyun 				ret = BCME_ERROR;
1885*4882a593Smuzhiyun 				goto exit;
1886*4882a593Smuzhiyun 			}
1887*4882a593Smuzhiyun 			/* Decrement session count */
1888*4882a593Smuzhiyun 			geofence_cfg->geofence_sessions_cnt--;
1889*4882a593Smuzhiyun 		}
1890*4882a593Smuzhiyun 	}
1891*4882a593Smuzhiyun 	if (peer_addr) {
1892*4882a593Smuzhiyun 		WL_INFORM_MEM(("session cnt update, upd = %d, cnt = %d, peer : "MACDBG", "
1893*4882a593Smuzhiyun 			" ret = %d\n", incr, geofence_cfg->geofence_sessions_cnt,
1894*4882a593Smuzhiyun 			MAC2STRDBG(peer_addr), ret));
1895*4882a593Smuzhiyun 	} else {
1896*4882a593Smuzhiyun 		WL_INFORM_MEM(("session cnt update, upd = %d, cnt = %d, ret = %d\n",
1897*4882a593Smuzhiyun 			incr, geofence_cfg->geofence_sessions_cnt, ret));
1898*4882a593Smuzhiyun 	}
1899*4882a593Smuzhiyun 
1900*4882a593Smuzhiyun exit:
1901*4882a593Smuzhiyun 	return ret;
1902*4882a593Smuzhiyun }
1903*4882a593Smuzhiyun 
1904*4882a593Smuzhiyun int8
dhd_rtt_get_geofence_target_cnt(dhd_pub_t * dhd)1905*4882a593Smuzhiyun dhd_rtt_get_geofence_target_cnt(dhd_pub_t *dhd)
1906*4882a593Smuzhiyun {
1907*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1908*4882a593Smuzhiyun 	if (!rtt_status) {
1909*4882a593Smuzhiyun 		return 0;
1910*4882a593Smuzhiyun 	}
1911*4882a593Smuzhiyun 	return rtt_status->geofence_cfg.geofence_target_cnt;
1912*4882a593Smuzhiyun }
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun /* returns geofence RTT target list Head */
1915*4882a593Smuzhiyun rtt_geofence_target_info_t*
dhd_rtt_get_geofence_target_head(dhd_pub_t * dhd)1916*4882a593Smuzhiyun dhd_rtt_get_geofence_target_head(dhd_pub_t *dhd)
1917*4882a593Smuzhiyun {
1918*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1919*4882a593Smuzhiyun 	rtt_geofence_target_info_t* head = NULL;
1920*4882a593Smuzhiyun 
1921*4882a593Smuzhiyun 	if (!rtt_status) {
1922*4882a593Smuzhiyun 		return NULL;
1923*4882a593Smuzhiyun 	}
1924*4882a593Smuzhiyun 
1925*4882a593Smuzhiyun 	if (rtt_status->geofence_cfg.geofence_target_cnt) {
1926*4882a593Smuzhiyun 		head = &rtt_status->geofence_cfg.geofence_target_info[0];
1927*4882a593Smuzhiyun 	}
1928*4882a593Smuzhiyun 
1929*4882a593Smuzhiyun 	return head;
1930*4882a593Smuzhiyun }
1931*4882a593Smuzhiyun 
1932*4882a593Smuzhiyun int8
dhd_rtt_get_geofence_cur_target_idx(dhd_pub_t * dhd)1933*4882a593Smuzhiyun dhd_rtt_get_geofence_cur_target_idx(dhd_pub_t *dhd)
1934*4882a593Smuzhiyun {
1935*4882a593Smuzhiyun 	int8 target_cnt = 0, cur_idx = DHD_RTT_INVALID_TARGET_INDEX;
1936*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1937*4882a593Smuzhiyun 
1938*4882a593Smuzhiyun 	if (!rtt_status) {
1939*4882a593Smuzhiyun 		goto exit;
1940*4882a593Smuzhiyun 	}
1941*4882a593Smuzhiyun 
1942*4882a593Smuzhiyun 	target_cnt = rtt_status->geofence_cfg.geofence_target_cnt;
1943*4882a593Smuzhiyun 	if (target_cnt == 0) {
1944*4882a593Smuzhiyun 		goto exit;
1945*4882a593Smuzhiyun 	}
1946*4882a593Smuzhiyun 
1947*4882a593Smuzhiyun 	cur_idx = rtt_status->geofence_cfg.cur_target_idx;
1948*4882a593Smuzhiyun 	if (cur_idx >= target_cnt) {
1949*4882a593Smuzhiyun 		WL_INFORM_MEM(("dhd_rtt_get_geofence_cur_target_idx: "
1950*4882a593Smuzhiyun 			"cur_index exceeded (>=) target_cnt, cur_idx = %d, "
1951*4882a593Smuzhiyun 			"target_cnt = %d\n", cur_idx, target_cnt));
1952*4882a593Smuzhiyun 		ASSERT(cur_idx < target_cnt);
1953*4882a593Smuzhiyun 		cur_idx = DHD_RTT_INVALID_TARGET_INDEX;
1954*4882a593Smuzhiyun 	}
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun exit:
1957*4882a593Smuzhiyun 	return cur_idx;
1958*4882a593Smuzhiyun }
1959*4882a593Smuzhiyun 
1960*4882a593Smuzhiyun void
dhd_rtt_set_geofence_cur_target_idx(dhd_pub_t * dhd,int8 idx)1961*4882a593Smuzhiyun dhd_rtt_set_geofence_cur_target_idx(dhd_pub_t *dhd, int8 idx)
1962*4882a593Smuzhiyun {
1963*4882a593Smuzhiyun 	int8 target_cnt = 0;
1964*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1965*4882a593Smuzhiyun 
1966*4882a593Smuzhiyun 	target_cnt = rtt_status->geofence_cfg.geofence_target_cnt;
1967*4882a593Smuzhiyun 	ASSERT(idx < target_cnt);
1968*4882a593Smuzhiyun 	rtt_status->geofence_cfg.cur_target_idx = idx;
1969*4882a593Smuzhiyun 	return;
1970*4882a593Smuzhiyun }
1971*4882a593Smuzhiyun 
1972*4882a593Smuzhiyun void
dhd_rtt_move_geofence_cur_target_idx_to_next(dhd_pub_t * dhd)1973*4882a593Smuzhiyun dhd_rtt_move_geofence_cur_target_idx_to_next(dhd_pub_t *dhd)
1974*4882a593Smuzhiyun {
1975*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
1976*4882a593Smuzhiyun 
1977*4882a593Smuzhiyun 	if (!rtt_status) {
1978*4882a593Smuzhiyun 		return;
1979*4882a593Smuzhiyun 	}
1980*4882a593Smuzhiyun 
1981*4882a593Smuzhiyun 	if (rtt_status->geofence_cfg.geofence_target_cnt == 0) {
1982*4882a593Smuzhiyun 		/* Invalidate current idx if no targets */
1983*4882a593Smuzhiyun 		rtt_status->geofence_cfg.cur_target_idx =
1984*4882a593Smuzhiyun 			DHD_RTT_INVALID_TARGET_INDEX;
1985*4882a593Smuzhiyun 		/* Cancel pending retry timer if any */
1986*4882a593Smuzhiyun 		if (delayed_work_pending(&rtt_status->rtt_retry_timer)) {
1987*4882a593Smuzhiyun 			cancel_delayed_work(&rtt_status->rtt_retry_timer);
1988*4882a593Smuzhiyun 		}
1989*4882a593Smuzhiyun 		return;
1990*4882a593Smuzhiyun 	}
1991*4882a593Smuzhiyun 	rtt_status->geofence_cfg.cur_target_idx++;
1992*4882a593Smuzhiyun 
1993*4882a593Smuzhiyun 	if (rtt_status->geofence_cfg.cur_target_idx >=
1994*4882a593Smuzhiyun 		rtt_status->geofence_cfg.geofence_target_cnt) {
1995*4882a593Smuzhiyun 		/* Reset once all targets done */
1996*4882a593Smuzhiyun 		rtt_status->geofence_cfg.cur_target_idx = 0;
1997*4882a593Smuzhiyun 	}
1998*4882a593Smuzhiyun }
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun /* returns geofence current RTT target */
2001*4882a593Smuzhiyun rtt_geofence_target_info_t*
dhd_rtt_get_geofence_current_target(dhd_pub_t * dhd)2002*4882a593Smuzhiyun dhd_rtt_get_geofence_current_target(dhd_pub_t *dhd)
2003*4882a593Smuzhiyun {
2004*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
2005*4882a593Smuzhiyun 	rtt_geofence_target_info_t* cur_target = NULL;
2006*4882a593Smuzhiyun 	int cur_idx = 0;
2007*4882a593Smuzhiyun 
2008*4882a593Smuzhiyun 	if (!rtt_status) {
2009*4882a593Smuzhiyun 		return NULL;
2010*4882a593Smuzhiyun 	}
2011*4882a593Smuzhiyun 
2012*4882a593Smuzhiyun 	cur_idx = dhd_rtt_get_geofence_cur_target_idx(dhd);
2013*4882a593Smuzhiyun 	if (cur_idx >= 0) {
2014*4882a593Smuzhiyun 		cur_target = &rtt_status->geofence_cfg.geofence_target_info[cur_idx];
2015*4882a593Smuzhiyun 	}
2016*4882a593Smuzhiyun 
2017*4882a593Smuzhiyun 	return cur_target;
2018*4882a593Smuzhiyun }
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun /* returns geofence target from list for the peer */
2021*4882a593Smuzhiyun rtt_geofence_target_info_t*
dhd_rtt_get_geofence_target(dhd_pub_t * dhd,struct ether_addr * peer_addr,int8 * index)2022*4882a593Smuzhiyun dhd_rtt_get_geofence_target(dhd_pub_t *dhd, struct ether_addr* peer_addr, int8 *index)
2023*4882a593Smuzhiyun {
2024*4882a593Smuzhiyun 	int8 i;
2025*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
2026*4882a593Smuzhiyun 	int target_cnt;
2027*4882a593Smuzhiyun 	rtt_geofence_target_info_t *geofence_target_info, *tgt = NULL;
2028*4882a593Smuzhiyun 
2029*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
2030*4882a593Smuzhiyun 
2031*4882a593Smuzhiyun 	if (!rtt_status) {
2032*4882a593Smuzhiyun 		return NULL;
2033*4882a593Smuzhiyun 	}
2034*4882a593Smuzhiyun 
2035*4882a593Smuzhiyun 	target_cnt = rtt_status->geofence_cfg.geofence_target_cnt;
2036*4882a593Smuzhiyun 	geofence_target_info = rtt_status->geofence_cfg.geofence_target_info;
2037*4882a593Smuzhiyun 
2038*4882a593Smuzhiyun 	/* Loop through to find target */
2039*4882a593Smuzhiyun 	for (i = 0; i < target_cnt; i++) {
2040*4882a593Smuzhiyun 		if (geofence_target_info[i].valid == FALSE) {
2041*4882a593Smuzhiyun 			break;
2042*4882a593Smuzhiyun 		}
2043*4882a593Smuzhiyun 		if (!memcmp(peer_addr, &geofence_target_info[i].peer_addr,
2044*4882a593Smuzhiyun 				ETHER_ADDR_LEN)) {
2045*4882a593Smuzhiyun 			*index = i;
2046*4882a593Smuzhiyun 			tgt = &geofence_target_info[i];
2047*4882a593Smuzhiyun 		}
2048*4882a593Smuzhiyun 	}
2049*4882a593Smuzhiyun 	if (!tgt) {
2050*4882a593Smuzhiyun 		DHD_RTT(("dhd_rtt_get_geofence_target: Target not found in list,"
2051*4882a593Smuzhiyun 			" MAC ADDR: "MACDBG" \n", MAC2STRDBG(peer_addr)));
2052*4882a593Smuzhiyun 	}
2053*4882a593Smuzhiyun 	return tgt;
2054*4882a593Smuzhiyun }
2055*4882a593Smuzhiyun 
2056*4882a593Smuzhiyun /* add geofence target to the target list */
2057*4882a593Smuzhiyun int
dhd_rtt_add_geofence_target(dhd_pub_t * dhd,rtt_geofence_target_info_t * target)2058*4882a593Smuzhiyun dhd_rtt_add_geofence_target(dhd_pub_t *dhd, rtt_geofence_target_info_t *target)
2059*4882a593Smuzhiyun {
2060*4882a593Smuzhiyun 	int err = BCME_OK;
2061*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
2062*4882a593Smuzhiyun 	rtt_geofence_target_info_t  *geofence_target_info;
2063*4882a593Smuzhiyun 	int8 geofence_target_cnt, index;
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
2066*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
2067*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
2068*4882a593Smuzhiyun 
2069*4882a593Smuzhiyun 	GEOFENCE_RTT_LOCK(rtt_status);
2070*4882a593Smuzhiyun 
2071*4882a593Smuzhiyun 	/* Get the geofence_target via peer addr, index param is dumm here */
2072*4882a593Smuzhiyun 	geofence_target_info = dhd_rtt_get_geofence_target(dhd, &target->peer_addr, &index);
2073*4882a593Smuzhiyun 	if (geofence_target_info) {
2074*4882a593Smuzhiyun 		DHD_RTT(("Duplicate geofencing RTT add request dropped\n"));
2075*4882a593Smuzhiyun 		err = BCME_OK;
2076*4882a593Smuzhiyun 		goto exit;
2077*4882a593Smuzhiyun 	}
2078*4882a593Smuzhiyun 
2079*4882a593Smuzhiyun 	geofence_target_cnt = rtt_status->geofence_cfg.geofence_target_cnt;
2080*4882a593Smuzhiyun 	if (geofence_target_cnt >= RTT_MAX_GEOFENCE_TARGET_CNT) {
2081*4882a593Smuzhiyun 		DHD_RTT(("Queue full, Geofencing RTT add request dropped\n"));
2082*4882a593Smuzhiyun 		err = BCME_NORESOURCE;
2083*4882a593Smuzhiyun 		goto exit;
2084*4882a593Smuzhiyun 	}
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	/* Add Geofence RTT request and increment target count */
2087*4882a593Smuzhiyun 	geofence_target_info = rtt_status->geofence_cfg.geofence_target_info;
2088*4882a593Smuzhiyun 	/* src and dest buffer len same, pointers of same DS statically allocated */
2089*4882a593Smuzhiyun 	(void)memcpy_s(&geofence_target_info[geofence_target_cnt],
2090*4882a593Smuzhiyun 		sizeof(geofence_target_info[geofence_target_cnt]), target,
2091*4882a593Smuzhiyun 		sizeof(*target));
2092*4882a593Smuzhiyun 	geofence_target_info[geofence_target_cnt].valid = TRUE;
2093*4882a593Smuzhiyun 	rtt_status->geofence_cfg.geofence_target_cnt++;
2094*4882a593Smuzhiyun 	if (rtt_status->geofence_cfg.geofence_target_cnt == 1) {
2095*4882a593Smuzhiyun 		/* Adding first target */
2096*4882a593Smuzhiyun 		rtt_status->geofence_cfg.cur_target_idx = 0;
2097*4882a593Smuzhiyun 	}
2098*4882a593Smuzhiyun 
2099*4882a593Smuzhiyun 	WL_INFORM_MEM(("dhd_rtt_add_geofence_target: " MACDBG
2100*4882a593Smuzhiyun 		", cur_idx = %d, total cnt = %d\n", MAC2STRDBG(&target->peer_addr),
2101*4882a593Smuzhiyun 		rtt_status->geofence_cfg.cur_target_idx,
2102*4882a593Smuzhiyun 		rtt_status->geofence_cfg.geofence_target_cnt));
2103*4882a593Smuzhiyun 
2104*4882a593Smuzhiyun exit:
2105*4882a593Smuzhiyun 	GEOFENCE_RTT_UNLOCK(rtt_status);
2106*4882a593Smuzhiyun 	return err;
2107*4882a593Smuzhiyun }
2108*4882a593Smuzhiyun 
2109*4882a593Smuzhiyun /* removes geofence target from the target list */
2110*4882a593Smuzhiyun int
dhd_rtt_remove_geofence_target(dhd_pub_t * dhd,struct ether_addr * peer_addr)2111*4882a593Smuzhiyun dhd_rtt_remove_geofence_target(dhd_pub_t *dhd, struct ether_addr *peer_addr)
2112*4882a593Smuzhiyun {
2113*4882a593Smuzhiyun 	int err = BCME_OK;
2114*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
2115*4882a593Smuzhiyun 	rtt_geofence_target_info_t  *geofence_target_info;
2116*4882a593Smuzhiyun 	int8 geofence_target_cnt, j, index = 0;
2117*4882a593Smuzhiyun 	struct net_device *dev;
2118*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg;
2119*4882a593Smuzhiyun 
2120*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
2121*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
2122*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
2123*4882a593Smuzhiyun 
2124*4882a593Smuzhiyun 	dev = dhd_linux_get_primary_netdev(dhd);
2125*4882a593Smuzhiyun 	cfg = wl_get_cfg(dev);
2126*4882a593Smuzhiyun 
2127*4882a593Smuzhiyun 	GEOFENCE_RTT_LOCK(rtt_status);
2128*4882a593Smuzhiyun 
2129*4882a593Smuzhiyun 	geofence_target_cnt = dhd_rtt_get_geofence_target_cnt(dhd);
2130*4882a593Smuzhiyun 	if (geofence_target_cnt == 0) {
2131*4882a593Smuzhiyun 		DHD_RTT(("Queue Empty, Geofencing RTT remove request dropped\n"));
2132*4882a593Smuzhiyun 		goto exit;
2133*4882a593Smuzhiyun 	}
2134*4882a593Smuzhiyun 
2135*4882a593Smuzhiyun 	/* Get the geofence_target via peer addr */
2136*4882a593Smuzhiyun 	geofence_target_info = dhd_rtt_get_geofence_target(dhd, peer_addr, &index);
2137*4882a593Smuzhiyun 	if (geofence_target_info == NULL) {
2138*4882a593Smuzhiyun 		DHD_RTT(("Geofencing RTT target not found, remove request dropped\n"));
2139*4882a593Smuzhiyun 		err = BCME_NOTFOUND;
2140*4882a593Smuzhiyun 		goto exit;
2141*4882a593Smuzhiyun 	}
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 	/* left shift all the valid entries, as we dont keep holes in list */
2144*4882a593Smuzhiyun 	for (j = index; j < geofence_target_cnt; j++) {
2145*4882a593Smuzhiyun 		/*
2146*4882a593Smuzhiyun 		 * src and dest buffer len same, pointers of same DS
2147*4882a593Smuzhiyun 		 * statically allocated
2148*4882a593Smuzhiyun 		 */
2149*4882a593Smuzhiyun 		if ((j + 1) < geofence_target_cnt) {
2150*4882a593Smuzhiyun 			(void)memcpy_s(&geofence_target_info[j], sizeof(geofence_target_info[j]),
2151*4882a593Smuzhiyun 				&geofence_target_info[j + 1], sizeof(geofence_target_info[j + 1]));
2152*4882a593Smuzhiyun 		} else {
2153*4882a593Smuzhiyun 			/* reset the last target info */
2154*4882a593Smuzhiyun 			bzero(&geofence_target_info[j], sizeof(rtt_geofence_target_info_t));
2155*4882a593Smuzhiyun 		}
2156*4882a593Smuzhiyun 	}
2157*4882a593Smuzhiyun 
2158*4882a593Smuzhiyun 	rtt_status->geofence_cfg.geofence_target_cnt--;
2159*4882a593Smuzhiyun 	if (rtt_status->geofence_cfg.geofence_target_cnt == 0) {
2160*4882a593Smuzhiyun 		rtt_status->geofence_cfg.cur_target_idx =
2161*4882a593Smuzhiyun 			DHD_RTT_INVALID_TARGET_INDEX;
2162*4882a593Smuzhiyun 	} else {
2163*4882a593Smuzhiyun 		if (rtt_status->geofence_cfg.geofence_target_cnt ==
2164*4882a593Smuzhiyun 				rtt_status->geofence_cfg.cur_target_idx) {
2165*4882a593Smuzhiyun 			/*
2166*4882a593Smuzhiyun 			 * Wrap to first (next here) target again,
2167*4882a593Smuzhiyun 			 * as the last target, got removed,
2168*4882a593Smuzhiyun 			 * which was the current target (idx) also
2169*4882a593Smuzhiyun 			 */
2170*4882a593Smuzhiyun 			rtt_status->geofence_cfg.cur_target_idx = 0;
2171*4882a593Smuzhiyun 		}
2172*4882a593Smuzhiyun 		wl_cfgnan_update_geofence_target_idx(cfg);
2173*4882a593Smuzhiyun 	}
2174*4882a593Smuzhiyun 
2175*4882a593Smuzhiyun 	WL_INFORM_MEM(("dhd_rtt_remove_geofence_target: " MACDBG
2176*4882a593Smuzhiyun 		", cur_idx = %d, target_cnt = %d\n", MAC2STRDBG(peer_addr),
2177*4882a593Smuzhiyun 		rtt_status->geofence_cfg.cur_target_idx,
2178*4882a593Smuzhiyun 		rtt_status->geofence_cfg.geofence_target_cnt));
2179*4882a593Smuzhiyun 
2180*4882a593Smuzhiyun exit:
2181*4882a593Smuzhiyun 	GEOFENCE_RTT_UNLOCK(rtt_status);
2182*4882a593Smuzhiyun 	return err;
2183*4882a593Smuzhiyun }
2184*4882a593Smuzhiyun 
2185*4882a593Smuzhiyun /* deletes/empty geofence target list */
2186*4882a593Smuzhiyun int
dhd_rtt_delete_geofence_target_list(dhd_pub_t * dhd)2187*4882a593Smuzhiyun dhd_rtt_delete_geofence_target_list(dhd_pub_t *dhd)
2188*4882a593Smuzhiyun {
2189*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
2190*4882a593Smuzhiyun 
2191*4882a593Smuzhiyun 	int err = BCME_OK;
2192*4882a593Smuzhiyun 
2193*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
2194*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
2195*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
2196*4882a593Smuzhiyun 	GEOFENCE_RTT_LOCK(rtt_status);
2197*4882a593Smuzhiyun 	memset_s(&rtt_status->geofence_cfg, sizeof(rtt_geofence_cfg_t),
2198*4882a593Smuzhiyun 		0, sizeof(rtt_geofence_cfg_t));
2199*4882a593Smuzhiyun 	GEOFENCE_RTT_UNLOCK(rtt_status);
2200*4882a593Smuzhiyun 	return err;
2201*4882a593Smuzhiyun }
2202*4882a593Smuzhiyun 
2203*4882a593Smuzhiyun rtt_geofence_setup_status_t*
dhd_rtt_get_geofence_setup_status(dhd_pub_t * dhd)2204*4882a593Smuzhiyun dhd_rtt_get_geofence_setup_status(dhd_pub_t *dhd)
2205*4882a593Smuzhiyun {
2206*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
2207*4882a593Smuzhiyun 	rtt_geofence_cfg_t* geofence_cfg = &rtt_status->geofence_cfg;
2208*4882a593Smuzhiyun 	rtt_geofence_setup_status_t* rng_setup_status;
2209*4882a593Smuzhiyun 
2210*4882a593Smuzhiyun 	rng_setup_status = &geofence_cfg->geofence_setup_status;
2211*4882a593Smuzhiyun 	return rng_setup_status;
2212*4882a593Smuzhiyun }
2213*4882a593Smuzhiyun 
2214*4882a593Smuzhiyun bool
dhd_rtt_is_geofence_setup_inprog(dhd_pub_t * dhd)2215*4882a593Smuzhiyun dhd_rtt_is_geofence_setup_inprog(dhd_pub_t *dhd)
2216*4882a593Smuzhiyun {
2217*4882a593Smuzhiyun 	rtt_geofence_setup_status_t* rng_setup_status;
2218*4882a593Smuzhiyun 
2219*4882a593Smuzhiyun 	rng_setup_status = dhd_rtt_get_geofence_setup_status(dhd);
2220*4882a593Smuzhiyun 
2221*4882a593Smuzhiyun 	return rng_setup_status->geofence_setup_inprog;
2222*4882a593Smuzhiyun }
2223*4882a593Smuzhiyun 
2224*4882a593Smuzhiyun bool
dhd_rtt_is_geofence_setup_inprog_with_peer(dhd_pub_t * dhd,struct ether_addr * peer_addr)2225*4882a593Smuzhiyun dhd_rtt_is_geofence_setup_inprog_with_peer(dhd_pub_t *dhd,
2226*4882a593Smuzhiyun 		struct ether_addr *peer_addr)
2227*4882a593Smuzhiyun {
2228*4882a593Smuzhiyun 	rtt_geofence_setup_status_t* rng_setup_status;
2229*4882a593Smuzhiyun 	struct nan_ranging_inst *rng_inst = NULL;
2230*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
2231*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2232*4882a593Smuzhiyun 	bool ret = FALSE;
2233*4882a593Smuzhiyun 
2234*4882a593Smuzhiyun 	rng_setup_status = dhd_rtt_get_geofence_setup_status(dhd);
2235*4882a593Smuzhiyun 	if (rng_setup_status->geofence_setup_inprog == FALSE) {
2236*4882a593Smuzhiyun 		goto exit;
2237*4882a593Smuzhiyun 	}
2238*4882a593Smuzhiyun 	rng_inst = wl_cfgnan_check_for_ranging(cfg, peer_addr);
2239*4882a593Smuzhiyun 	if (rng_inst && (rng_inst == rng_setup_status->rng_inst)) {
2240*4882a593Smuzhiyun 		ret = TRUE;
2241*4882a593Smuzhiyun 	}
2242*4882a593Smuzhiyun 
2243*4882a593Smuzhiyun exit:
2244*4882a593Smuzhiyun 	return ret;
2245*4882a593Smuzhiyun }
2246*4882a593Smuzhiyun 
2247*4882a593Smuzhiyun /*
2248*4882a593Smuzhiyun  * Call with inprog as true and corresponding
2249*4882a593Smuzhiyun  * rng_inst, to take setup lock,
2250*4882a593Smuzhiyun  * call with inprog as False and rng_inst as NULL
2251*4882a593Smuzhiyun  * to unlock setup lock
2252*4882a593Smuzhiyun  */
2253*4882a593Smuzhiyun void
dhd_rtt_set_geofence_setup_status(dhd_pub_t * dhd,bool inprog,struct ether_addr * peer_addr)2254*4882a593Smuzhiyun dhd_rtt_set_geofence_setup_status(dhd_pub_t *dhd, bool inprog,
2255*4882a593Smuzhiyun 		struct ether_addr *peer_addr)
2256*4882a593Smuzhiyun {
2257*4882a593Smuzhiyun 	struct nan_ranging_inst *rng_inst = NULL;
2258*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
2259*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2260*4882a593Smuzhiyun 	rtt_geofence_setup_status_t* rng_setup_status;
2261*4882a593Smuzhiyun 
2262*4882a593Smuzhiyun 	rng_setup_status = dhd_rtt_get_geofence_setup_status(dhd);
2263*4882a593Smuzhiyun 	rng_setup_status->geofence_setup_inprog = inprog;
2264*4882a593Smuzhiyun 	if (inprog) {
2265*4882a593Smuzhiyun 		ASSERT(peer_addr);
2266*4882a593Smuzhiyun 		rng_inst = wl_cfgnan_check_for_ranging(cfg, peer_addr);
2267*4882a593Smuzhiyun 		ASSERT(rng_inst);
2268*4882a593Smuzhiyun 		if (rng_inst) {
2269*4882a593Smuzhiyun 			rng_setup_status->rng_inst = rng_inst;
2270*4882a593Smuzhiyun 		}
2271*4882a593Smuzhiyun 	} else {
2272*4882a593Smuzhiyun 		rng_setup_status->rng_inst = NULL;
2273*4882a593Smuzhiyun 	}
2274*4882a593Smuzhiyun }
2275*4882a593Smuzhiyun 
2276*4882a593Smuzhiyun int
dhd_rtt_sched_geofencing_target(dhd_pub_t * dhd)2277*4882a593Smuzhiyun dhd_rtt_sched_geofencing_target(dhd_pub_t *dhd)
2278*4882a593Smuzhiyun {
2279*4882a593Smuzhiyun 	rtt_geofence_target_info_t  *geofence_target_info;
2280*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
2281*4882a593Smuzhiyun 	int ret = BCME_OK;
2282*4882a593Smuzhiyun 	u8 rtt_invalid_reason = RTT_STATE_VALID;
2283*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2284*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
2285*4882a593Smuzhiyun 	rtt_geofence_cfg_t* geofence_cfg = &rtt_status->geofence_cfg;
2286*4882a593Smuzhiyun 	int8 target_cnt = 0, cur_idx = DHD_RTT_INVALID_TARGET_INDEX;
2287*4882a593Smuzhiyun 
2288*4882a593Smuzhiyun 	NAN_MUTEX_LOCK();
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun 	if (wl_cfgnan_is_enabled(cfg) == FALSE) {
2291*4882a593Smuzhiyun 		ret = BCME_NOTENABLED;
2292*4882a593Smuzhiyun 		goto done;
2293*4882a593Smuzhiyun 	}
2294*4882a593Smuzhiyun 
2295*4882a593Smuzhiyun 	DHD_RTT_ERR(("dhd_rtt_sched_geofencing_target: "
2296*4882a593Smuzhiyun 		" sched_reason = %d, sessions cnt = %d, cur target idx = %d\n",
2297*4882a593Smuzhiyun 		rtt_status->rtt_sched_reason, geofence_cfg->geofence_sessions_cnt,
2298*4882a593Smuzhiyun 		rtt_status->geofence_cfg.cur_target_idx));
2299*4882a593Smuzhiyun 
2300*4882a593Smuzhiyun 	//ASSERT(!dhd_rtt_geofence_sessions_maxed_out(dhd));
2301*4882a593Smuzhiyun 	if (dhd_rtt_geofence_sessions_maxed_out(dhd)) {
2302*4882a593Smuzhiyun 		ret = BCME_NORESOURCE;
2303*4882a593Smuzhiyun 		goto done;
2304*4882a593Smuzhiyun 	}
2305*4882a593Smuzhiyun 
2306*4882a593Smuzhiyun 	target_cnt = dhd_rtt_get_geofence_target_cnt(dhd);
2307*4882a593Smuzhiyun 
2308*4882a593Smuzhiyun 	if (target_cnt == 0) {
2309*4882a593Smuzhiyun 		DHD_RTT_MEM(("dhd_rtt_sched_geofencing_target: "
2310*4882a593Smuzhiyun 			"No geofence targets to schedule\n"));
2311*4882a593Smuzhiyun 		goto done;
2312*4882a593Smuzhiyun 	}
2313*4882a593Smuzhiyun 
2314*4882a593Smuzhiyun 	cur_idx = dhd_rtt_get_geofence_cur_target_idx(dhd);
2315*4882a593Smuzhiyun 	if (cur_idx == DHD_RTT_INVALID_TARGET_INDEX) {
2316*4882a593Smuzhiyun 		/*
2317*4882a593Smuzhiyun 		 * This Can be valid scenario, as cur_idx might
2318*4882a593Smuzhiyun 		 * get invalidated, after rtt thread sched and
2319*4882a593Smuzhiyun 		 * thread actually executing
2320*4882a593Smuzhiyun 		 */
2321*4882a593Smuzhiyun 		DHD_RTT_MEM(("dhd_rtt_sched_geofencing_target: "
2322*4882a593Smuzhiyun 			"cur idx is invalid, bail out\n"));
2323*4882a593Smuzhiyun 		goto done;
2324*4882a593Smuzhiyun 	}
2325*4882a593Smuzhiyun 
2326*4882a593Smuzhiyun 	/* Get current geofencing target */
2327*4882a593Smuzhiyun 	geofence_target_info = dhd_rtt_get_geofence_current_target(dhd);
2328*4882a593Smuzhiyun 	//ASSERT(geofence_target_info);
2329*4882a593Smuzhiyun 
2330*4882a593Smuzhiyun 	/* call cfg API for trigerring geofencing RTT */
2331*4882a593Smuzhiyun 	if (geofence_target_info) {
2332*4882a593Smuzhiyun 		/* check for dp/others concurrency */
2333*4882a593Smuzhiyun 		rtt_invalid_reason = dhd_rtt_invalid_states(dev,
2334*4882a593Smuzhiyun 				&geofence_target_info->peer_addr);
2335*4882a593Smuzhiyun 		if ((rtt_invalid_reason != RTT_STATE_VALID) ||
2336*4882a593Smuzhiyun 			wl_cfgnan_check_role_concurrency(cfg,
2337*4882a593Smuzhiyun 				&geofence_target_info->peer_addr)) {
2338*4882a593Smuzhiyun 			/* TODO: see if we can move to next target..
2339*4882a593Smuzhiyun 			* i.e, if invalid state is due to DP with same peer
2340*4882a593Smuzhiyun 			*/
2341*4882a593Smuzhiyun 			ret = BCME_BUSY;
2342*4882a593Smuzhiyun 			DHD_RTT_ERR(("DRV State is not valid for RTT, "
2343*4882a593Smuzhiyun 				"invalid_state = %d\n", rtt_invalid_reason));
2344*4882a593Smuzhiyun 			goto done;
2345*4882a593Smuzhiyun 		}
2346*4882a593Smuzhiyun 
2347*4882a593Smuzhiyun 		ret = wl_cfgnan_trigger_geofencing_ranging(dev,
2348*4882a593Smuzhiyun 				&geofence_target_info->peer_addr);
2349*4882a593Smuzhiyun 		if (ret == BCME_OK) {
2350*4882a593Smuzhiyun 			dhd_rtt_set_geofence_setup_status(dhd, TRUE,
2351*4882a593Smuzhiyun 				&geofence_target_info->peer_addr);
2352*4882a593Smuzhiyun 		}
2353*4882a593Smuzhiyun 	} else {
2354*4882a593Smuzhiyun 		DHD_RTT(("No RTT target to schedule\n"));
2355*4882a593Smuzhiyun 		ret = BCME_NOTFOUND;
2356*4882a593Smuzhiyun 	}
2357*4882a593Smuzhiyun 
2358*4882a593Smuzhiyun done:
2359*4882a593Smuzhiyun 	NAN_MUTEX_UNLOCK();
2360*4882a593Smuzhiyun 	return ret;
2361*4882a593Smuzhiyun }
2362*4882a593Smuzhiyun #endif /* WL_NAN */
2363*4882a593Smuzhiyun 
2364*4882a593Smuzhiyun #ifdef WL_CFG80211
2365*4882a593Smuzhiyun #ifdef WL_NAN
2366*4882a593Smuzhiyun static void
dhd_rtt_retry(dhd_pub_t * dhd)2367*4882a593Smuzhiyun dhd_rtt_retry(dhd_pub_t *dhd)
2368*4882a593Smuzhiyun {
2369*4882a593Smuzhiyun 
2370*4882a593Smuzhiyun 	/* Attempt RTT for current geofence target */
2371*4882a593Smuzhiyun 	wl_cfgnan_reset_geofence_ranging_for_cur_target(dhd,
2372*4882a593Smuzhiyun 		RTT_SCHED_RTT_RETRY_GEOFENCE);
2373*4882a593Smuzhiyun 
2374*4882a593Smuzhiyun }
2375*4882a593Smuzhiyun static void
dhd_rtt_retry_work(struct work_struct * work)2376*4882a593Smuzhiyun dhd_rtt_retry_work(struct work_struct *work)
2377*4882a593Smuzhiyun {
2378*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = NULL;
2379*4882a593Smuzhiyun 	dhd_pub_t *dhd = NULL;
2380*4882a593Smuzhiyun 	struct net_device *dev = NULL;
2381*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = NULL;
2382*4882a593Smuzhiyun 
2383*4882a593Smuzhiyun 	if (!work) {
2384*4882a593Smuzhiyun 		goto exit;
2385*4882a593Smuzhiyun 	}
2386*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2387*4882a593Smuzhiyun #pragma GCC diagnostic push
2388*4882a593Smuzhiyun #pragma GCC diagnostic ignored "-Wcast-qual"
2389*4882a593Smuzhiyun #endif
2390*4882a593Smuzhiyun 	rtt_status = container_of(work, rtt_status_info_t, rtt_retry_timer.work);
2391*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2392*4882a593Smuzhiyun #pragma GCC diagnostic pop
2393*4882a593Smuzhiyun #endif
2394*4882a593Smuzhiyun 
2395*4882a593Smuzhiyun 	dhd = rtt_status->dhd;
2396*4882a593Smuzhiyun 	if (dhd == NULL) {
2397*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s : dhd is NULL\n", __FUNCTION__));
2398*4882a593Smuzhiyun 		goto exit;
2399*4882a593Smuzhiyun 	}
2400*4882a593Smuzhiyun 	dev = dhd_linux_get_primary_netdev(dhd);
2401*4882a593Smuzhiyun 	cfg = wl_get_cfg(dev);
2402*4882a593Smuzhiyun 
2403*4882a593Smuzhiyun 	NAN_MUTEX_LOCK();
2404*4882a593Smuzhiyun 	(void) dhd_rtt_retry(dhd);
2405*4882a593Smuzhiyun 	NAN_MUTEX_UNLOCK();
2406*4882a593Smuzhiyun 
2407*4882a593Smuzhiyun exit:
2408*4882a593Smuzhiyun 	return;
2409*4882a593Smuzhiyun }
2410*4882a593Smuzhiyun #endif /* WL_NAN */
2411*4882a593Smuzhiyun 
2412*4882a593Smuzhiyun /*
2413*4882a593Smuzhiyun  * Return zero (0)
2414*4882a593Smuzhiyun  * for valid RTT state
2415*4882a593Smuzhiyun  * means if RTT is applicable
2416*4882a593Smuzhiyun  */
2417*4882a593Smuzhiyun uint8
dhd_rtt_invalid_states(struct net_device * ndev,struct ether_addr * peer_addr)2418*4882a593Smuzhiyun dhd_rtt_invalid_states(struct net_device *ndev, struct ether_addr *peer_addr)
2419*4882a593Smuzhiyun {
2420*4882a593Smuzhiyun 	uint8 invalid_reason = RTT_STATE_VALID;
2421*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2422*4882a593Smuzhiyun 
2423*4882a593Smuzhiyun 	UNUSED_PARAMETER(cfg);
2424*4882a593Smuzhiyun 	UNUSED_PARAMETER(invalid_reason);
2425*4882a593Smuzhiyun 
2426*4882a593Smuzhiyun 	/* Make sure peer addr is not NULL in caller */
2427*4882a593Smuzhiyun 	ASSERT(peer_addr);
2428*4882a593Smuzhiyun 	/*
2429*4882a593Smuzhiyun 	 * Keep adding prohibited drv states here
2430*4882a593Smuzhiyun 	 * Only generic conditions which block
2431*4882a593Smuzhiyun 	 * All RTTs like NDP connection
2432*4882a593Smuzhiyun 	 */
2433*4882a593Smuzhiyun 
2434*4882a593Smuzhiyun #ifdef WL_NAN
2435*4882a593Smuzhiyun 	if (wl_cfgnan_data_dp_exists_with_peer(cfg, peer_addr)) {
2436*4882a593Smuzhiyun 		invalid_reason = RTT_STATE_INV_REASON_NDP_EXIST;
2437*4882a593Smuzhiyun 		DHD_RTT(("NDP in progress/connected, RTT prohibited\n"));
2438*4882a593Smuzhiyun 		goto exit;
2439*4882a593Smuzhiyun 	}
2440*4882a593Smuzhiyun #endif /* WL_NAN */
2441*4882a593Smuzhiyun 
2442*4882a593Smuzhiyun 	/* Remove below #defines once more exit calls come */
2443*4882a593Smuzhiyun #ifdef WL_NAN
2444*4882a593Smuzhiyun exit:
2445*4882a593Smuzhiyun #endif /* WL_NAN */
2446*4882a593Smuzhiyun 	return invalid_reason;
2447*4882a593Smuzhiyun }
2448*4882a593Smuzhiyun #endif /* WL_CFG80211 */
2449*4882a593Smuzhiyun 
2450*4882a593Smuzhiyun void
dhd_rtt_schedule_rtt_work_thread(dhd_pub_t * dhd,int sched_reason)2451*4882a593Smuzhiyun dhd_rtt_schedule_rtt_work_thread(dhd_pub_t *dhd, int sched_reason)
2452*4882a593Smuzhiyun {
2453*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
2454*4882a593Smuzhiyun 	if (rtt_status == NULL) {
2455*4882a593Smuzhiyun 		ASSERT(0);
2456*4882a593Smuzhiyun 	} else {
2457*4882a593Smuzhiyun 		rtt_status->rtt_sched_reason = sched_reason;
2458*4882a593Smuzhiyun 		rtt_status->rtt_sched = TRUE;
2459*4882a593Smuzhiyun 		schedule_work(&rtt_status->work);
2460*4882a593Smuzhiyun 	}
2461*4882a593Smuzhiyun 	return;
2462*4882a593Smuzhiyun }
2463*4882a593Smuzhiyun 
2464*4882a593Smuzhiyun int
dhd_rtt_stop(dhd_pub_t * dhd,struct ether_addr * mac_list,int mac_cnt)2465*4882a593Smuzhiyun dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt)
2466*4882a593Smuzhiyun {
2467*4882a593Smuzhiyun 	int err = BCME_OK;
2468*4882a593Smuzhiyun #ifdef WL_CFG80211
2469*4882a593Smuzhiyun 	int i = 0, j = 0;
2470*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
2471*4882a593Smuzhiyun 	rtt_results_header_t *entry, *next;
2472*4882a593Smuzhiyun 	rtt_result_t *rtt_result, *next2;
2473*4882a593Smuzhiyun 	struct rtt_noti_callback *iter;
2474*4882a593Smuzhiyun 
2475*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
2476*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
2477*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
2478*4882a593Smuzhiyun 	if (rtt_status->status == RTT_STOPPED) {
2479*4882a593Smuzhiyun 		DHD_RTT_ERR(("rtt is not started\n"));
2480*4882a593Smuzhiyun 		return BCME_OK;
2481*4882a593Smuzhiyun 	}
2482*4882a593Smuzhiyun 	DHD_RTT(("%s enter\n", __FUNCTION__));
2483*4882a593Smuzhiyun 	mutex_lock(&rtt_status->rtt_mutex);
2484*4882a593Smuzhiyun 	for (i = 0; i < mac_cnt; i++) {
2485*4882a593Smuzhiyun 		for (j = 0; j < rtt_status->rtt_config.rtt_target_cnt; j++) {
2486*4882a593Smuzhiyun 			if (!bcmp(&mac_list[i], &rtt_status->rtt_config.target_info[j].addr,
2487*4882a593Smuzhiyun 				ETHER_ADDR_LEN)) {
2488*4882a593Smuzhiyun 				rtt_status->rtt_config.target_info[j].disable = TRUE;
2489*4882a593Smuzhiyun 			}
2490*4882a593Smuzhiyun 		}
2491*4882a593Smuzhiyun 	}
2492*4882a593Smuzhiyun 	if (rtt_status->all_cancel) {
2493*4882a593Smuzhiyun 		/* cancel all of request */
2494*4882a593Smuzhiyun 		rtt_status->status = RTT_STOPPED;
2495*4882a593Smuzhiyun 		DHD_RTT(("current RTT process is cancelled\n"));
2496*4882a593Smuzhiyun 		/* remove the rtt results in cache */
2497*4882a593Smuzhiyun 		if (!list_empty(&rtt_status->rtt_results_cache)) {
2498*4882a593Smuzhiyun 			/* Iterate rtt_results_header list */
2499*4882a593Smuzhiyun 			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2500*4882a593Smuzhiyun 			list_for_each_entry_safe(entry, next,
2501*4882a593Smuzhiyun 				&rtt_status->rtt_results_cache, list) {
2502*4882a593Smuzhiyun 				list_del(&entry->list);
2503*4882a593Smuzhiyun 				/* Iterate rtt_result list */
2504*4882a593Smuzhiyun 				list_for_each_entry_safe(rtt_result, next2,
2505*4882a593Smuzhiyun 					&entry->result_list, list) {
2506*4882a593Smuzhiyun 					list_del(&rtt_result->list);
2507*4882a593Smuzhiyun 					MFREE(dhd->osh, rtt_result,
2508*4882a593Smuzhiyun 						sizeof(rtt_result_t));
2509*4882a593Smuzhiyun 				}
2510*4882a593Smuzhiyun 				MFREE(dhd->osh, entry, sizeof(rtt_results_header_t));
2511*4882a593Smuzhiyun 			}
2512*4882a593Smuzhiyun 			GCC_DIAGNOSTIC_POP();
2513*4882a593Smuzhiyun 		}
2514*4882a593Smuzhiyun 		/* send the rtt complete event to wake up the user process */
2515*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2516*4882a593Smuzhiyun 		list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
2517*4882a593Smuzhiyun 			GCC_DIAGNOSTIC_POP();
2518*4882a593Smuzhiyun 			iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache);
2519*4882a593Smuzhiyun 		}
2520*4882a593Smuzhiyun 		/* reinitialize the HEAD */
2521*4882a593Smuzhiyun 		INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
2522*4882a593Smuzhiyun 		/* clear information for rtt_config */
2523*4882a593Smuzhiyun 		rtt_status->rtt_config.rtt_target_cnt = 0;
2524*4882a593Smuzhiyun 		memset(rtt_status->rtt_config.target_info, 0,
2525*4882a593Smuzhiyun 			TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
2526*4882a593Smuzhiyun 		rtt_status->cur_idx = 0;
2527*4882a593Smuzhiyun 		/* Cancel pending proxd timeout work if any */
2528*4882a593Smuzhiyun 		if (delayed_work_pending(&rtt_status->proxd_timeout)) {
2529*4882a593Smuzhiyun 			cancel_delayed_work(&rtt_status->proxd_timeout);
2530*4882a593Smuzhiyun 		}
2531*4882a593Smuzhiyun 		dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION);
2532*4882a593Smuzhiyun #ifdef WL_NAN
2533*4882a593Smuzhiyun 		dhd_rtt_delete_nan_session(dhd);
2534*4882a593Smuzhiyun #endif /* WL_NAN */
2535*4882a593Smuzhiyun 		dhd_rtt_ftm_enable(dhd, FALSE);
2536*4882a593Smuzhiyun 	}
2537*4882a593Smuzhiyun 	mutex_unlock(&rtt_status->rtt_mutex);
2538*4882a593Smuzhiyun #endif /* WL_CFG80211 */
2539*4882a593Smuzhiyun 	return err;
2540*4882a593Smuzhiyun }
2541*4882a593Smuzhiyun 
2542*4882a593Smuzhiyun #ifdef WL_CFG80211
2543*4882a593Smuzhiyun static void
dhd_rtt_timeout(dhd_pub_t * dhd)2544*4882a593Smuzhiyun dhd_rtt_timeout(dhd_pub_t *dhd)
2545*4882a593Smuzhiyun {
2546*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
2547*4882a593Smuzhiyun #ifndef DHD_DUMP_ON_RTT_TIMEOUT
2548*4882a593Smuzhiyun 	rtt_target_info_t *rtt_target = NULL;
2549*4882a593Smuzhiyun 	rtt_target_info_t *rtt_target_info = NULL;
2550*4882a593Smuzhiyun #ifdef WL_NAN
2551*4882a593Smuzhiyun 	int8 idx;
2552*4882a593Smuzhiyun 	nan_ranging_inst_t *ranging_inst = NULL;
2553*4882a593Smuzhiyun 	int ret = BCME_OK;
2554*4882a593Smuzhiyun 	uint32 status;
2555*4882a593Smuzhiyun 	struct net_device *ndev = dhd_linux_get_primary_netdev(dhd);
2556*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg =  wiphy_priv(ndev->ieee80211_ptr->wiphy);
2557*4882a593Smuzhiyun #endif /* WL_NAN */
2558*4882a593Smuzhiyun #endif /* !DHD_DUMP_ON_RTT_TIMEOUT */
2559*4882a593Smuzhiyun 
2560*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
2561*4882a593Smuzhiyun 	if (!rtt_status) {
2562*4882a593Smuzhiyun 		DHD_RTT_ERR(("Proxd timer expired but no RTT status\n"));
2563*4882a593Smuzhiyun 		goto exit;
2564*4882a593Smuzhiyun 	}
2565*4882a593Smuzhiyun 
2566*4882a593Smuzhiyun 	if (RTT_IS_STOPPED(rtt_status)) {
2567*4882a593Smuzhiyun 		DHD_RTT_ERR(("Proxd timer expired but no RTT Request\n"));
2568*4882a593Smuzhiyun 		goto exit;
2569*4882a593Smuzhiyun 	}
2570*4882a593Smuzhiyun 
2571*4882a593Smuzhiyun #ifdef DHD_DUMP_ON_RTT_TIMEOUT
2572*4882a593Smuzhiyun 	/* Dump, and Panic depending on memdump.info */
2573*4882a593Smuzhiyun #ifdef BCMDONGLEHOST
2574*4882a593Smuzhiyun 	if (dhd_query_bus_erros(dhd)) {
2575*4882a593Smuzhiyun 		goto exit;
2576*4882a593Smuzhiyun 	}
2577*4882a593Smuzhiyun #ifdef DHD_FW_COREDUMP
2578*4882a593Smuzhiyun 	if (dhd->memdump_enabled) {
2579*4882a593Smuzhiyun 		/* Behave based on user memdump info */
2580*4882a593Smuzhiyun 		dhd->memdump_type = DUMP_TYPE_PROXD_TIMEOUT;
2581*4882a593Smuzhiyun 		dhd_bus_mem_dump(dhd);
2582*4882a593Smuzhiyun 	}
2583*4882a593Smuzhiyun #endif /* DHD_FW_COREDUMP */
2584*4882a593Smuzhiyun #endif /* BCMDONGLEHOST */
2585*4882a593Smuzhiyun #else /* DHD_DUMP_ON_RTT_TIMEOUT */
2586*4882a593Smuzhiyun #ifdef WL_NAN
2587*4882a593Smuzhiyun 	if (rtt_status->rtt_config.target_list_mode == RNG_TARGET_LIST_MODE_NAN) {
2588*4882a593Smuzhiyun 		for (idx = rtt_status->start_idx;
2589*4882a593Smuzhiyun 				idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
2590*4882a593Smuzhiyun 			rtt_target = &rtt_status->rtt_config.target_info[idx];
2591*4882a593Smuzhiyun 			if ((!rtt_target->disable) &&
2592*4882a593Smuzhiyun 					(!dhd_rtt_get_report_header(rtt_status,
2593*4882a593Smuzhiyun 					NULL, &rtt_target->addr))) {
2594*4882a593Smuzhiyun 				if (wl_cfgnan_ranging_is_in_prog_for_peer(cfg, &rtt_target->addr)) {
2595*4882a593Smuzhiyun 					ranging_inst = wl_cfgnan_check_for_ranging(cfg,
2596*4882a593Smuzhiyun 							&rtt_target->addr);
2597*4882a593Smuzhiyun 					ret =  wl_cfgnan_cancel_ranging(ndev, cfg,
2598*4882a593Smuzhiyun 							&ranging_inst->range_id,
2599*4882a593Smuzhiyun 							NAN_RNG_TERM_FLAG_IMMEDIATE, &status);
2600*4882a593Smuzhiyun 					if (unlikely(ret) || unlikely(status)) {
2601*4882a593Smuzhiyun 						WL_ERR(("%s:nan range cancel failed ret = %d "
2602*4882a593Smuzhiyun 							"status = %d\n", __FUNCTION__,
2603*4882a593Smuzhiyun 							ret, status));
2604*4882a593Smuzhiyun 					}
2605*4882a593Smuzhiyun 				}
2606*4882a593Smuzhiyun 				dhd_rtt_create_failure_result(rtt_status, &rtt_target->addr);
2607*4882a593Smuzhiyun 			}
2608*4882a593Smuzhiyun 		}
2609*4882a593Smuzhiyun 		dhd_rtt_handle_rtt_session_end(dhd);
2610*4882a593Smuzhiyun 		/* reset directed cfg params */
2611*4882a593Smuzhiyun 		rtt_status->directed_cfg.directed_setup_status.rng_inst = NULL;
2612*4882a593Smuzhiyun 		rtt_status->directed_cfg.directed_setup_status.directed_na_setup_inprog = FALSE;
2613*4882a593Smuzhiyun 		rtt_status->directed_cfg.directed_sessions_cnt = 0;
2614*4882a593Smuzhiyun 	} else
2615*4882a593Smuzhiyun #endif /* WL_NAN */
2616*4882a593Smuzhiyun 	{
2617*4882a593Smuzhiyun 		/* Cancel RTT for target and proceed to next target */
2618*4882a593Smuzhiyun 		rtt_target_info = rtt_status->rtt_config.target_info;
2619*4882a593Smuzhiyun 		if ((!rtt_target_info) ||
2620*4882a593Smuzhiyun 				(rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt)) {
2621*4882a593Smuzhiyun 			goto exit;
2622*4882a593Smuzhiyun 		}
2623*4882a593Smuzhiyun 		rtt_target = &rtt_target_info[rtt_status->cur_idx];
2624*4882a593Smuzhiyun 		WL_ERR(("Proxd timer expired for Target: "MACDBG" \n",
2625*4882a593Smuzhiyun 			MAC2STRDBG(&rtt_target->addr)));
2626*4882a593Smuzhiyun 		/* For Legacy RTT */
2627*4882a593Smuzhiyun 		dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION);
2628*4882a593Smuzhiyun 		dhd_rtt_create_failure_result(rtt_status, &rtt_target->addr);
2629*4882a593Smuzhiyun 		dhd_rtt_handle_rtt_session_end(dhd);
2630*4882a593Smuzhiyun 	}
2631*4882a593Smuzhiyun #endif /* DHD_DUMP_ON_RTT_TIMEOUT */
2632*4882a593Smuzhiyun exit:
2633*4882a593Smuzhiyun 	return;
2634*4882a593Smuzhiyun }
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun static void
dhd_rtt_timeout_work(struct work_struct * work)2637*4882a593Smuzhiyun dhd_rtt_timeout_work(struct work_struct *work)
2638*4882a593Smuzhiyun {
2639*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = NULL;
2640*4882a593Smuzhiyun 	dhd_pub_t *dhd = NULL;
2641*4882a593Smuzhiyun 
2642*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2643*4882a593Smuzhiyun #pragma GCC diagnostic push
2644*4882a593Smuzhiyun #pragma GCC diagnostic ignored "-Wcast-qual"
2645*4882a593Smuzhiyun #endif
2646*4882a593Smuzhiyun 	rtt_status = container_of(work, rtt_status_info_t, proxd_timeout.work);
2647*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2648*4882a593Smuzhiyun #pragma GCC diagnostic pop
2649*4882a593Smuzhiyun #endif
2650*4882a593Smuzhiyun 
2651*4882a593Smuzhiyun 	dhd = rtt_status->dhd;
2652*4882a593Smuzhiyun 	if (dhd == NULL) {
2653*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s : dhd is NULL\n", __FUNCTION__));
2654*4882a593Smuzhiyun 		return;
2655*4882a593Smuzhiyun 	}
2656*4882a593Smuzhiyun 
2657*4882a593Smuzhiyun 	mutex_lock(&rtt_status->rtt_mutex);
2658*4882a593Smuzhiyun 	(void) dhd_rtt_timeout(dhd);
2659*4882a593Smuzhiyun 	mutex_unlock(&rtt_status->rtt_mutex);
2660*4882a593Smuzhiyun }
2661*4882a593Smuzhiyun 
2662*4882a593Smuzhiyun static void
dhd_rtt_set_ftm_config_ratespec(ftm_config_param_info_t * ftm_params,int * ftm_param_cnt,rtt_target_info_t * rtt_target)2663*4882a593Smuzhiyun dhd_rtt_set_ftm_config_ratespec(ftm_config_param_info_t *ftm_params,
2664*4882a593Smuzhiyun 		int *ftm_param_cnt, rtt_target_info_t *rtt_target)
2665*4882a593Smuzhiyun {
2666*4882a593Smuzhiyun 	bool use_default = FALSE;
2667*4882a593Smuzhiyun 	int nss;
2668*4882a593Smuzhiyun 	int mcs;
2669*4882a593Smuzhiyun 	uint32 rspec = 0;
2670*4882a593Smuzhiyun 
2671*4882a593Smuzhiyun 	if (!(rtt_target->bw && rtt_target->preamble)) {
2672*4882a593Smuzhiyun 		goto exit;
2673*4882a593Smuzhiyun 	}
2674*4882a593Smuzhiyun 	switch (rtt_target->preamble) {
2675*4882a593Smuzhiyun 		case RTT_PREAMBLE_LEGACY:
2676*4882a593Smuzhiyun 			rspec |= WL_RSPEC_ENCODE_RATE; /* 11abg */
2677*4882a593Smuzhiyun 			rspec |= WL_RATE_6M;
2678*4882a593Smuzhiyun 			break;
2679*4882a593Smuzhiyun 		case RTT_PREAMBLE_HT:
2680*4882a593Smuzhiyun 			rspec |= WL_RSPEC_ENCODE_HT; /* 11n HT */
2681*4882a593Smuzhiyun 			mcs = 0; /* default MCS 0 */
2682*4882a593Smuzhiyun 			rspec |= mcs;
2683*4882a593Smuzhiyun 			break;
2684*4882a593Smuzhiyun 		case RTT_PREAMBLE_VHT:
2685*4882a593Smuzhiyun 			rspec |= WL_RSPEC_ENCODE_VHT; /* 11ac VHT */
2686*4882a593Smuzhiyun 			mcs = 0; /* default MCS 0 */
2687*4882a593Smuzhiyun 			nss = 1; /* default Nss = 1  */
2688*4882a593Smuzhiyun 			rspec |= (nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs;
2689*4882a593Smuzhiyun 			break;
2690*4882a593Smuzhiyun 		default:
2691*4882a593Smuzhiyun 			DHD_RTT(("doesn't support this preamble : %d\n",
2692*4882a593Smuzhiyun 				rtt_target->preamble));
2693*4882a593Smuzhiyun 			use_default = TRUE;
2694*4882a593Smuzhiyun 			break;
2695*4882a593Smuzhiyun 	}
2696*4882a593Smuzhiyun 	switch (rtt_target->bw) {
2697*4882a593Smuzhiyun 		case RTT_BW_20:
2698*4882a593Smuzhiyun 			rspec |= WL_RSPEC_BW_20MHZ;
2699*4882a593Smuzhiyun 			break;
2700*4882a593Smuzhiyun 		case RTT_BW_40:
2701*4882a593Smuzhiyun 			rspec |= WL_RSPEC_BW_40MHZ;
2702*4882a593Smuzhiyun 			break;
2703*4882a593Smuzhiyun 		case RTT_BW_80:
2704*4882a593Smuzhiyun 			rspec |= WL_RSPEC_BW_80MHZ;
2705*4882a593Smuzhiyun 			break;
2706*4882a593Smuzhiyun 		default:
2707*4882a593Smuzhiyun 			DHD_RTT(("doesn't support this BW : %d\n",
2708*4882a593Smuzhiyun 				rtt_target->bw));
2709*4882a593Smuzhiyun 			use_default = TRUE;
2710*4882a593Smuzhiyun 			break;
2711*4882a593Smuzhiyun 	}
2712*4882a593Smuzhiyun 	if (!use_default) {
2713*4882a593Smuzhiyun 		ftm_params[*ftm_param_cnt].data32 = htol32(rspec);
2714*4882a593Smuzhiyun 		ftm_params[*ftm_param_cnt].tlvid =
2715*4882a593Smuzhiyun 			WL_PROXD_TLV_ID_RATESPEC;
2716*4882a593Smuzhiyun 		*ftm_param_cnt = *ftm_param_cnt + 1;
2717*4882a593Smuzhiyun 		DHD_RTT((">\t ratespec : %d\n", rspec));
2718*4882a593Smuzhiyun 	}
2719*4882a593Smuzhiyun 
2720*4882a593Smuzhiyun exit:
2721*4882a593Smuzhiyun 	return;
2722*4882a593Smuzhiyun 
2723*4882a593Smuzhiyun }
2724*4882a593Smuzhiyun 
2725*4882a593Smuzhiyun static void
dhd_rtt_set_ftm_config_param(ftm_config_param_info_t * ftm_params,int * ftm_param_cnt,rtt_target_info_t * rtt_target,uint16 tlvid)2726*4882a593Smuzhiyun dhd_rtt_set_ftm_config_param(ftm_config_param_info_t *ftm_params,
2727*4882a593Smuzhiyun 	int *ftm_param_cnt, rtt_target_info_t *rtt_target, uint16 tlvid)
2728*4882a593Smuzhiyun {
2729*4882a593Smuzhiyun 	char eabuf[ETHER_ADDR_STR_LEN];
2730*4882a593Smuzhiyun 	char chanbuf[CHANSPEC_STR_LEN];
2731*4882a593Smuzhiyun 
2732*4882a593Smuzhiyun 	switch (tlvid) {
2733*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_CUR_ETHER_ADDR:
2734*4882a593Smuzhiyun 			/* local mac address */
2735*4882a593Smuzhiyun 			if (!ETHER_ISNULLADDR(rtt_target->local_addr.octet)) {
2736*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].mac_addr = rtt_target->local_addr;
2737*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_CUR_ETHER_ADDR;
2738*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2739*4882a593Smuzhiyun 				bcm_ether_ntoa(&rtt_target->local_addr, eabuf);
2740*4882a593Smuzhiyun 				DHD_RTT((">\t local %s\n", eabuf));
2741*4882a593Smuzhiyun 			}
2742*4882a593Smuzhiyun 			break;
2743*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_PEER_MAC:
2744*4882a593Smuzhiyun 			/* target's mac address */
2745*4882a593Smuzhiyun 			if (!ETHER_ISNULLADDR(rtt_target->addr.octet)) {
2746*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].mac_addr = rtt_target->addr;
2747*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_PEER_MAC;
2748*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2749*4882a593Smuzhiyun 				bcm_ether_ntoa(&rtt_target->addr, eabuf);
2750*4882a593Smuzhiyun 				DHD_RTT((">\t target %s\n", eabuf));
2751*4882a593Smuzhiyun 			}
2752*4882a593Smuzhiyun 			break;
2753*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_CHANSPEC:
2754*4882a593Smuzhiyun 			/* target's chanspec */
2755*4882a593Smuzhiyun 			if (rtt_target->chanspec) {
2756*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].chanspec =
2757*4882a593Smuzhiyun 					htol32((uint32)rtt_target->chanspec);
2758*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_CHANSPEC;
2759*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2760*4882a593Smuzhiyun 				wf_chspec_ntoa(rtt_target->chanspec, chanbuf);
2761*4882a593Smuzhiyun 				DHD_RTT((">\t chanspec : %s\n", chanbuf));
2762*4882a593Smuzhiyun 			}
2763*4882a593Smuzhiyun 			break;
2764*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_NUM_BURST:
2765*4882a593Smuzhiyun 			/* num-burst */
2766*4882a593Smuzhiyun 			if (rtt_target->num_burst) {
2767*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].data16 = htol16(rtt_target->num_burst);
2768*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_NUM_BURST;
2769*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2770*4882a593Smuzhiyun 				DHD_RTT((">\t num of burst : %d\n", rtt_target->num_burst));
2771*4882a593Smuzhiyun 			}
2772*4882a593Smuzhiyun 			break;
2773*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_BURST_NUM_FTM:
2774*4882a593Smuzhiyun 			/* number of frame per burst */
2775*4882a593Smuzhiyun 			rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_80M;
2776*4882a593Smuzhiyun 			if (CHSPEC_IS80(rtt_target->chanspec)) {
2777*4882a593Smuzhiyun 				rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_80M;
2778*4882a593Smuzhiyun 			} else if (CHSPEC_IS40(rtt_target->chanspec)) {
2779*4882a593Smuzhiyun 				rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_40M;
2780*4882a593Smuzhiyun 			} else if (CHSPEC_IS20(rtt_target->chanspec)) {
2781*4882a593Smuzhiyun 				rtt_target->num_frames_per_burst = FTM_DEFAULT_CNT_20M;
2782*4882a593Smuzhiyun 			}
2783*4882a593Smuzhiyun 			ftm_params[*ftm_param_cnt].data16 =
2784*4882a593Smuzhiyun 				htol16(rtt_target->num_frames_per_burst);
2785*4882a593Smuzhiyun 			ftm_params[*ftm_param_cnt].tlvid =
2786*4882a593Smuzhiyun 				WL_PROXD_TLV_ID_BURST_NUM_FTM;
2787*4882a593Smuzhiyun 			*ftm_param_cnt = *ftm_param_cnt + 1;
2788*4882a593Smuzhiyun 			DHD_RTT((">\t number of frame per burst : %d\n",
2789*4882a593Smuzhiyun 				rtt_target->num_frames_per_burst));
2790*4882a593Smuzhiyun 			break;
2791*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_FTM_RETRIES:
2792*4882a593Smuzhiyun 			/* FTM retry count */
2793*4882a593Smuzhiyun 			if (rtt_target->num_retries_per_ftm) {
2794*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].data8 = rtt_target->num_retries_per_ftm;
2795*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_FTM_RETRIES;
2796*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2797*4882a593Smuzhiyun 				DHD_RTT((">\t retry count of FTM  : %d\n",
2798*4882a593Smuzhiyun 					rtt_target->num_retries_per_ftm));
2799*4882a593Smuzhiyun 			}
2800*4882a593Smuzhiyun 			break;
2801*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_FTM_REQ_RETRIES:
2802*4882a593Smuzhiyun 			/* FTM Request retry count */
2803*4882a593Smuzhiyun 			if (rtt_target->num_retries_per_ftmr) {
2804*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].data8 = rtt_target->num_retries_per_ftmr;
2805*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid =
2806*4882a593Smuzhiyun 					WL_PROXD_TLV_ID_FTM_REQ_RETRIES;
2807*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2808*4882a593Smuzhiyun 				DHD_RTT((">\t retry count of FTM Req : %d\n",
2809*4882a593Smuzhiyun 					rtt_target->num_retries_per_ftmr));
2810*4882a593Smuzhiyun 			}
2811*4882a593Smuzhiyun 			break;
2812*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_BURST_PERIOD:
2813*4882a593Smuzhiyun 			/* burst-period */
2814*4882a593Smuzhiyun 			if (rtt_target->burst_period) {
2815*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].data_intvl.intvl =
2816*4882a593Smuzhiyun 					htol32(rtt_target->burst_period); /* ms */
2817*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC;
2818*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_BURST_PERIOD;
2819*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2820*4882a593Smuzhiyun 				DHD_RTT((">\t burst period : %d ms\n", rtt_target->burst_period));
2821*4882a593Smuzhiyun 			}
2822*4882a593Smuzhiyun 			break;
2823*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_BURST_DURATION:
2824*4882a593Smuzhiyun 			/* burst-duration */
2825*4882a593Smuzhiyun 			rtt_target->burst_duration = FTM_MAX_BURST_DUR_TMO_MS;
2826*4882a593Smuzhiyun 			if (rtt_target->burst_duration) {
2827*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].data_intvl.intvl =
2828*4882a593Smuzhiyun 					htol32(rtt_target->burst_duration); /* ms */
2829*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC;
2830*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_BURST_DURATION;
2831*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2832*4882a593Smuzhiyun 				DHD_RTT((">\t burst duration : %d ms\n",
2833*4882a593Smuzhiyun 					rtt_target->burst_duration));
2834*4882a593Smuzhiyun 			}
2835*4882a593Smuzhiyun 			break;
2836*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_BURST_TIMEOUT:
2837*4882a593Smuzhiyun 			/* burst-timeout */
2838*4882a593Smuzhiyun 			rtt_target->burst_timeout = FTM_MAX_BURST_DUR_TMO_MS;
2839*4882a593Smuzhiyun 			if (rtt_target->burst_timeout) {
2840*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].data_intvl.intvl =
2841*4882a593Smuzhiyun 					htol32(rtt_target->burst_timeout); /* ms */
2842*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC;
2843*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_BURST_TIMEOUT;
2844*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2845*4882a593Smuzhiyun 				DHD_RTT((">\t burst timeout : %d ms\n",
2846*4882a593Smuzhiyun 					rtt_target->burst_timeout));
2847*4882a593Smuzhiyun 			}
2848*4882a593Smuzhiyun 			break;
2849*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_RATESPEC:
2850*4882a593Smuzhiyun 			dhd_rtt_set_ftm_config_ratespec(ftm_params,
2851*4882a593Smuzhiyun 				ftm_param_cnt, rtt_target);
2852*4882a593Smuzhiyun 			break;
2853*4882a593Smuzhiyun 		case WL_PROXD_TLV_ID_EVENT_MASK:
2854*4882a593Smuzhiyun 			{
2855*4882a593Smuzhiyun 				/* set burst end and session end in ev mask by def */
2856*4882a593Smuzhiyun 				uint32 event_mask = ((1 << WL_PROXD_EVENT_BURST_END) |
2857*4882a593Smuzhiyun 						(1 << WL_PROXD_EVENT_SESSION_END));
2858*4882a593Smuzhiyun 				/* only burst end for directed nan-rtt target */
2859*4882a593Smuzhiyun 				if (rtt_target && (rtt_target->peer == RTT_PEER_NAN)) {
2860*4882a593Smuzhiyun 					event_mask = (1 << WL_PROXD_EVENT_BURST_END);
2861*4882a593Smuzhiyun 				}
2862*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].event_mask = event_mask;
2863*4882a593Smuzhiyun 				ftm_params[*ftm_param_cnt].tlvid = WL_PROXD_TLV_ID_EVENT_MASK;
2864*4882a593Smuzhiyun 				*ftm_param_cnt = *ftm_param_cnt + 1;
2865*4882a593Smuzhiyun 			}
2866*4882a593Smuzhiyun 			break;
2867*4882a593Smuzhiyun 		default:
2868*4882a593Smuzhiyun 			DHD_RTT_ERR(("Invalid FTM Param Config, tlvid = %d\n", tlvid));
2869*4882a593Smuzhiyun 			break;
2870*4882a593Smuzhiyun 	}
2871*4882a593Smuzhiyun 
2872*4882a593Smuzhiyun 	return;
2873*4882a593Smuzhiyun }
2874*4882a593Smuzhiyun 
2875*4882a593Smuzhiyun static int
dhd_rtt_start(dhd_pub_t * dhd)2876*4882a593Smuzhiyun dhd_rtt_start(dhd_pub_t *dhd)
2877*4882a593Smuzhiyun {
2878*4882a593Smuzhiyun 	int err = BCME_OK;
2879*4882a593Smuzhiyun 	int err_at = 0;
2880*4882a593Smuzhiyun 	int ftm_cfg_cnt = 0;
2881*4882a593Smuzhiyun 	int ftm_param_cnt = 0;
2882*4882a593Smuzhiyun 	ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS];
2883*4882a593Smuzhiyun 	ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS];
2884*4882a593Smuzhiyun 	rtt_target_info_t *rtt_target;
2885*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
2886*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
2887*4882a593Smuzhiyun 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
2888*4882a593Smuzhiyun 	u8 rtt_invalid_reason = RTT_STATE_VALID;
2889*4882a593Smuzhiyun 	int rtt_sched_type = RTT_TYPE_INVALID;
2890*4882a593Smuzhiyun 
2891*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
2892*4882a593Smuzhiyun 
2893*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
2894*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
2895*4882a593Smuzhiyun 
2896*4882a593Smuzhiyun 	DHD_RTT(("Enter %s\n", __FUNCTION__));
2897*4882a593Smuzhiyun 
2898*4882a593Smuzhiyun 	if (RTT_IS_STOPPED(rtt_status)) {
2899*4882a593Smuzhiyun 		DHD_RTT(("No Directed RTT target to process, check for geofence\n"));
2900*4882a593Smuzhiyun 		goto geofence;
2901*4882a593Smuzhiyun 	}
2902*4882a593Smuzhiyun 
2903*4882a593Smuzhiyun 	if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) {
2904*4882a593Smuzhiyun 		err = BCME_RANGE;
2905*4882a593Smuzhiyun 		err_at = 1;
2906*4882a593Smuzhiyun 		DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx));
2907*4882a593Smuzhiyun 		if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) {
2908*4882a593Smuzhiyun 			DHD_RTT_ERR(("STA is set as Target/Responder \n"));
2909*4882a593Smuzhiyun 			err = BCME_ERROR;
2910*4882a593Smuzhiyun 		}
2911*4882a593Smuzhiyun 		goto exit;
2912*4882a593Smuzhiyun 	}
2913*4882a593Smuzhiyun 
2914*4882a593Smuzhiyun 	/* Get a target information */
2915*4882a593Smuzhiyun 	rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
2916*4882a593Smuzhiyun 
2917*4882a593Smuzhiyun 	DHD_RTT(("%s enter\n", __FUNCTION__));
2918*4882a593Smuzhiyun 
2919*4882a593Smuzhiyun 	if (ETHER_ISNULLADDR(rtt_target->addr.octet)) {
2920*4882a593Smuzhiyun 		err = BCME_BADADDR;
2921*4882a593Smuzhiyun 		err_at = 2;
2922*4882a593Smuzhiyun 		DHD_RTT(("RTT Target addr is NULL\n"));
2923*4882a593Smuzhiyun 		goto exit;
2924*4882a593Smuzhiyun 	}
2925*4882a593Smuzhiyun 
2926*4882a593Smuzhiyun 	/* check for dp/others concurrency */
2927*4882a593Smuzhiyun 	rtt_invalid_reason = dhd_rtt_invalid_states(dev, &rtt_target->addr);
2928*4882a593Smuzhiyun 	if (rtt_invalid_reason != RTT_STATE_VALID) {
2929*4882a593Smuzhiyun 		err = BCME_BUSY;
2930*4882a593Smuzhiyun 		err_at = 3;
2931*4882a593Smuzhiyun 		DHD_RTT(("DRV State is not valid for RTT\n"));
2932*4882a593Smuzhiyun 		goto exit;
2933*4882a593Smuzhiyun 	}
2934*4882a593Smuzhiyun 
2935*4882a593Smuzhiyun 	/* enable ftm */
2936*4882a593Smuzhiyun 	err = dhd_rtt_ftm_enable(dhd, TRUE);
2937*4882a593Smuzhiyun 	if (err) {
2938*4882a593Smuzhiyun 		DHD_RTT_ERR(("failed to enable FTM (%d)\n", err));
2939*4882a593Smuzhiyun 		err_at = 4;
2940*4882a593Smuzhiyun 		goto exit;
2941*4882a593Smuzhiyun 	}
2942*4882a593Smuzhiyun 	rtt_status->status = RTT_ENABLED;
2943*4882a593Smuzhiyun 
2944*4882a593Smuzhiyun #ifdef WL_NAN
2945*4882a593Smuzhiyun 	if (rtt_target->peer == RTT_PEER_NAN) {
2946*4882a593Smuzhiyun 		rtt_sched_type = RTT_TYPE_NAN_DIRECTED;
2947*4882a593Smuzhiyun 		/* apply event mask */
2948*4882a593Smuzhiyun 		DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
2949*4882a593Smuzhiyun 			rtt_target, WL_PROXD_TLV_ID_EVENT_MASK);
2950*4882a593Smuzhiyun 		dhd_rtt_ftm_config(dhd, 0, FTM_CONFIG_CAT_GENERAL,
2951*4882a593Smuzhiyun 			ftm_params, ftm_param_cnt);
2952*4882a593Smuzhiyun 		/* Ignore return value..failure taken care inside the API */
2953*4882a593Smuzhiyun 		dhd_rtt_nan_start_session(dhd, rtt_target);
2954*4882a593Smuzhiyun 		goto exit;
2955*4882a593Smuzhiyun 	}
2956*4882a593Smuzhiyun #endif /* WL_NAN */
2957*4882a593Smuzhiyun 
2958*4882a593Smuzhiyun 	/* delete session of index default sesession  */
2959*4882a593Smuzhiyun 	err = dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION);
2960*4882a593Smuzhiyun 	if (err < 0 && err != BCME_NOTFOUND) {
2961*4882a593Smuzhiyun 		DHD_RTT_ERR(("failed to delete session of FTM (%d)\n", err));
2962*4882a593Smuzhiyun 		err_at = 5;
2963*4882a593Smuzhiyun 		goto exit;
2964*4882a593Smuzhiyun 	}
2965*4882a593Smuzhiyun 
2966*4882a593Smuzhiyun 	memset(ftm_configs, 0, sizeof(ftm_configs));
2967*4882a593Smuzhiyun 	memset(ftm_params, 0, sizeof(ftm_params));
2968*4882a593Smuzhiyun 
2969*4882a593Smuzhiyun 	/* configure the session 1 as initiator */
2970*4882a593Smuzhiyun 	if  (ftm_cfg_cnt < FTM_MAX_CONFIGS) {
2971*4882a593Smuzhiyun 		ftm_configs[ftm_cfg_cnt].enable = TRUE;
2972*4882a593Smuzhiyun 		ftm_configs[ftm_cfg_cnt++].flags =
2973*4882a593Smuzhiyun 			WL_PROXD_SESSION_FLAG_INITIATOR | WL_PROXD_SESSION_FLAG_RANDMAC;
2974*4882a593Smuzhiyun 		dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS,
2975*4882a593Smuzhiyun 				ftm_configs, ftm_cfg_cnt);
2976*4882a593Smuzhiyun 	} else {
2977*4882a593Smuzhiyun 		DHD_RTT_ERR(("Max FTM Config Options exceeded\n"));
2978*4882a593Smuzhiyun 		err = BCME_ERROR;
2979*4882a593Smuzhiyun 		err_at = 6;
2980*4882a593Smuzhiyun 		goto exit;
2981*4882a593Smuzhiyun 	}
2982*4882a593Smuzhiyun 
2983*4882a593Smuzhiyun 	memset(ioctl_buf, 0, WLC_IOCTL_SMLEN);
2984*4882a593Smuzhiyun 	/* Rand Mac for newer version in place of cur_eth */
2985*4882a593Smuzhiyun 	if (dhd->wlc_ver_major < RTT_IOV_CUR_ETH_OBSOLETE) {
2986*4882a593Smuzhiyun 		err = wldev_iovar_getbuf(dev, "cur_etheraddr", NULL, 0,
2987*4882a593Smuzhiyun 				ioctl_buf, WLC_IOCTL_SMLEN, NULL);
2988*4882a593Smuzhiyun 		if (err) {
2989*4882a593Smuzhiyun 			DHD_RTT_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
2990*4882a593Smuzhiyun 			err_at = 7;
2991*4882a593Smuzhiyun 			goto exit;
2992*4882a593Smuzhiyun 		}
2993*4882a593Smuzhiyun 		memcpy(rtt_target->local_addr.octet, ioctl_buf, ETHER_ADDR_LEN);
2994*4882a593Smuzhiyun 
2995*4882a593Smuzhiyun 		/* local mac address */
2996*4882a593Smuzhiyun 		DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
2997*4882a593Smuzhiyun 			rtt_target, WL_PROXD_TLV_ID_CUR_ETHER_ADDR);
2998*4882a593Smuzhiyun 	}
2999*4882a593Smuzhiyun 	/* target's mac address */
3000*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3001*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_PEER_MAC);
3002*4882a593Smuzhiyun 
3003*4882a593Smuzhiyun 	/* target's chanspec */
3004*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3005*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_CHANSPEC);
3006*4882a593Smuzhiyun 
3007*4882a593Smuzhiyun 	/* num-burst */
3008*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3009*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_NUM_BURST);
3010*4882a593Smuzhiyun 
3011*4882a593Smuzhiyun 	/* number of frame per burst */
3012*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3013*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_BURST_NUM_FTM);
3014*4882a593Smuzhiyun 
3015*4882a593Smuzhiyun 	/* FTM retry count */
3016*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3017*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_FTM_RETRIES);
3018*4882a593Smuzhiyun 
3019*4882a593Smuzhiyun 	/* FTM Request retry count */
3020*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3021*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_FTM_REQ_RETRIES);
3022*4882a593Smuzhiyun 
3023*4882a593Smuzhiyun 	/* burst-period */
3024*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3025*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_BURST_PERIOD);
3026*4882a593Smuzhiyun 
3027*4882a593Smuzhiyun 	/* Setting both duration and timeout to MAX duration
3028*4882a593Smuzhiyun 	 * to handle the congestion environments.
3029*4882a593Smuzhiyun 	 * Hence ignoring the user config.
3030*4882a593Smuzhiyun 	 */
3031*4882a593Smuzhiyun 	/* burst-duration */
3032*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3033*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_BURST_DURATION);
3034*4882a593Smuzhiyun 
3035*4882a593Smuzhiyun 	/* burst-timeout */
3036*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3037*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_BURST_TIMEOUT);
3038*4882a593Smuzhiyun 
3039*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3040*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_RATESPEC);
3041*4882a593Smuzhiyun 
3042*4882a593Smuzhiyun 	/* event_mask..applicable for only Legacy RTT.
3043*4882a593Smuzhiyun 	 * For nan-rtt config happens from firmware
3044*4882a593Smuzhiyun 	 */
3045*4882a593Smuzhiyun 	DHD_RTT_CHK_SET_PARAM(ftm_params, ftm_param_cnt,
3046*4882a593Smuzhiyun 		rtt_target, WL_PROXD_TLV_ID_EVENT_MASK);
3047*4882a593Smuzhiyun 
3048*4882a593Smuzhiyun #if !defined(WL_USE_RANDOMIZED_SCAN)
3049*4882a593Smuzhiyun 	/* legacy rtt randmac */
3050*4882a593Smuzhiyun 	dhd_set_rand_mac_oui(dhd);
3051*4882a593Smuzhiyun #endif /* !defined(WL_USE_RANDOMIZED_SCAN */
3052*4882a593Smuzhiyun 	dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_GENERAL,
3053*4882a593Smuzhiyun 			ftm_params, ftm_param_cnt);
3054*4882a593Smuzhiyun 
3055*4882a593Smuzhiyun 	rtt_sched_type = RTT_TYPE_LEGACY;
3056*4882a593Smuzhiyun 	err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE);
3057*4882a593Smuzhiyun 	if (err) {
3058*4882a593Smuzhiyun 		DHD_RTT_ERR(("failed to start session of FTM : error %d\n", err));
3059*4882a593Smuzhiyun 		err_at = 8;
3060*4882a593Smuzhiyun 	} else {
3061*4882a593Smuzhiyun 		/* schedule proxd timeout */
3062*4882a593Smuzhiyun 		schedule_delayed_work(&rtt_status->proxd_timeout,
3063*4882a593Smuzhiyun 			msecs_to_jiffies(DHD_NAN_RTT_TIMER_INTERVAL_MS));
3064*4882a593Smuzhiyun 
3065*4882a593Smuzhiyun 	}
3066*4882a593Smuzhiyun 
3067*4882a593Smuzhiyun 	goto exit;
3068*4882a593Smuzhiyun geofence:
3069*4882a593Smuzhiyun #ifdef WL_NAN
3070*4882a593Smuzhiyun 	/* sched geofencing rtt */
3071*4882a593Smuzhiyun 	rtt_sched_type = RTT_TYPE_NAN_GEOFENCE;
3072*4882a593Smuzhiyun 	if ((err = dhd_rtt_sched_geofencing_target(dhd)) != BCME_OK) {
3073*4882a593Smuzhiyun 		DHD_RTT_ERR(("geofencing sched failed, err = %d\n", err));
3074*4882a593Smuzhiyun 		err_at = 9;
3075*4882a593Smuzhiyun 	}
3076*4882a593Smuzhiyun #endif /* WL_NAN */
3077*4882a593Smuzhiyun 
3078*4882a593Smuzhiyun exit:
3079*4882a593Smuzhiyun 	if (err) {
3080*4882a593Smuzhiyun 		/* RTT Failed */
3081*4882a593Smuzhiyun 		DHD_RTT_ERR(("dhd_rtt_start: Failed & RTT_STOPPED, err = %d,"
3082*4882a593Smuzhiyun 			" err_at = %d, rtt_sched_type = %d, rtt_invalid_reason = %d\n"
3083*4882a593Smuzhiyun 			" sched_reason = %d",
3084*4882a593Smuzhiyun 			err, err_at, rtt_sched_type, rtt_invalid_reason,
3085*4882a593Smuzhiyun 			rtt_status->rtt_sched_reason));
3086*4882a593Smuzhiyun 		rtt_status->status = RTT_STOPPED;
3087*4882a593Smuzhiyun 		/* disable FTM */
3088*4882a593Smuzhiyun 		dhd_rtt_ftm_enable(dhd, FALSE);
3089*4882a593Smuzhiyun 	}
3090*4882a593Smuzhiyun 	rtt_status->rtt_sched = FALSE;
3091*4882a593Smuzhiyun 	return err;
3092*4882a593Smuzhiyun }
3093*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3094*4882a593Smuzhiyun 
3095*4882a593Smuzhiyun int
dhd_rtt_register_noti_callback(dhd_pub_t * dhd,void * ctx,dhd_rtt_compl_noti_fn noti_fn)3096*4882a593Smuzhiyun dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn)
3097*4882a593Smuzhiyun {
3098*4882a593Smuzhiyun 	int err = BCME_OK;
3099*4882a593Smuzhiyun 	struct rtt_noti_callback *cb = NULL, *iter;
3100*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
3101*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
3102*4882a593Smuzhiyun 	NULL_CHECK(noti_fn, "noti_fn is NULL", err);
3103*4882a593Smuzhiyun 
3104*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
3105*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
3106*4882a593Smuzhiyun 	spin_lock_bh(&noti_list_lock);
3107*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3108*4882a593Smuzhiyun 	list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
3109*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_POP();
3110*4882a593Smuzhiyun 		if (iter->noti_fn == noti_fn) {
3111*4882a593Smuzhiyun 			goto exit;
3112*4882a593Smuzhiyun 		}
3113*4882a593Smuzhiyun 	}
3114*4882a593Smuzhiyun 	cb = (struct rtt_noti_callback *)MALLOCZ(dhd->osh, sizeof(struct rtt_noti_callback));
3115*4882a593Smuzhiyun 	if (!cb) {
3116*4882a593Smuzhiyun 		err = -ENOMEM;
3117*4882a593Smuzhiyun 		goto exit;
3118*4882a593Smuzhiyun 	}
3119*4882a593Smuzhiyun 	cb->noti_fn = noti_fn;
3120*4882a593Smuzhiyun 	cb->ctx = ctx;
3121*4882a593Smuzhiyun 	list_add(&cb->list, &rtt_status->noti_fn_list);
3122*4882a593Smuzhiyun exit:
3123*4882a593Smuzhiyun 	spin_unlock_bh(&noti_list_lock);
3124*4882a593Smuzhiyun 	return err;
3125*4882a593Smuzhiyun }
3126*4882a593Smuzhiyun 
3127*4882a593Smuzhiyun int
dhd_rtt_unregister_noti_callback(dhd_pub_t * dhd,dhd_rtt_compl_noti_fn noti_fn)3128*4882a593Smuzhiyun dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn)
3129*4882a593Smuzhiyun {
3130*4882a593Smuzhiyun 	int err = BCME_OK;
3131*4882a593Smuzhiyun 	struct rtt_noti_callback *cb = NULL, *iter;
3132*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
3133*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
3134*4882a593Smuzhiyun 	NULL_CHECK(noti_fn, "noti_fn is NULL", err);
3135*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
3136*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
3137*4882a593Smuzhiyun 	spin_lock_bh(&noti_list_lock);
3138*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3139*4882a593Smuzhiyun 	list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
3140*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_POP();
3141*4882a593Smuzhiyun 		if (iter->noti_fn == noti_fn) {
3142*4882a593Smuzhiyun 			cb = iter;
3143*4882a593Smuzhiyun 			list_del(&cb->list);
3144*4882a593Smuzhiyun 			break;
3145*4882a593Smuzhiyun 		}
3146*4882a593Smuzhiyun 	}
3147*4882a593Smuzhiyun 
3148*4882a593Smuzhiyun 	spin_unlock_bh(&noti_list_lock);
3149*4882a593Smuzhiyun 	if (cb) {
3150*4882a593Smuzhiyun 		MFREE(dhd->osh, cb, sizeof(struct rtt_noti_callback));
3151*4882a593Smuzhiyun 	}
3152*4882a593Smuzhiyun 	return err;
3153*4882a593Smuzhiyun }
3154*4882a593Smuzhiyun 
3155*4882a593Smuzhiyun static wifi_rate_v1
dhd_rtt_convert_rate_to_host(uint32 rspec)3156*4882a593Smuzhiyun dhd_rtt_convert_rate_to_host(uint32 rspec)
3157*4882a593Smuzhiyun {
3158*4882a593Smuzhiyun 	wifi_rate_v1 host_rate;
3159*4882a593Smuzhiyun 	uint32 bandwidth;
3160*4882a593Smuzhiyun 	memset(&host_rate, 0, sizeof(wifi_rate_v1));
3161*4882a593Smuzhiyun 	if (RSPEC_ISLEGACY(rspec)) {
3162*4882a593Smuzhiyun 		host_rate.preamble = 0;
3163*4882a593Smuzhiyun 	} else if (RSPEC_ISHT(rspec)) {
3164*4882a593Smuzhiyun 		host_rate.preamble = 2;
3165*4882a593Smuzhiyun 		host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK;
3166*4882a593Smuzhiyun 	} else if (RSPEC_ISVHT(rspec)) {
3167*4882a593Smuzhiyun 		host_rate.preamble = 3;
3168*4882a593Smuzhiyun 		host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK;
3169*4882a593Smuzhiyun 		host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
3170*4882a593Smuzhiyun 	}
3171*4882a593Smuzhiyun 
3172*4882a593Smuzhiyun 	bandwidth = RSPEC_BW(rspec);
3173*4882a593Smuzhiyun 	switch (bandwidth) {
3174*4882a593Smuzhiyun 	case WL_RSPEC_BW_20MHZ:
3175*4882a593Smuzhiyun 		host_rate.bw = RTT_RATE_20M;
3176*4882a593Smuzhiyun 		break;
3177*4882a593Smuzhiyun 	case WL_RSPEC_BW_40MHZ:
3178*4882a593Smuzhiyun 		host_rate.bw = RTT_RATE_40M;
3179*4882a593Smuzhiyun 		break;
3180*4882a593Smuzhiyun 	case WL_RSPEC_BW_80MHZ:
3181*4882a593Smuzhiyun 		host_rate.bw = RTT_RATE_80M;
3182*4882a593Smuzhiyun 		break;
3183*4882a593Smuzhiyun 	case WL_RSPEC_BW_160MHZ:
3184*4882a593Smuzhiyun 		host_rate.bw = RTT_RATE_160M;
3185*4882a593Smuzhiyun 		break;
3186*4882a593Smuzhiyun 	default:
3187*4882a593Smuzhiyun 		host_rate.bw = RTT_RATE_20M;
3188*4882a593Smuzhiyun 		break;
3189*4882a593Smuzhiyun 	}
3190*4882a593Smuzhiyun 
3191*4882a593Smuzhiyun 	host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */
3192*4882a593Smuzhiyun 	DHD_RTT(("bit rate : %d\n", host_rate.bitrate));
3193*4882a593Smuzhiyun 	return host_rate;
3194*4882a593Smuzhiyun }
3195*4882a593Smuzhiyun 
3196*4882a593Smuzhiyun #define FTM_FRAME_TYPES	{"SETUP", "TRIGGER", "TIMESTAMP"}
3197*4882a593Smuzhiyun static int
dhd_rtt_convert_results_to_host_v1(rtt_result_t * rtt_result,const uint8 * p_data,uint16 tlvid,uint16 len)3198*4882a593Smuzhiyun dhd_rtt_convert_results_to_host_v1(rtt_result_t *rtt_result, const uint8 *p_data,
3199*4882a593Smuzhiyun 	uint16 tlvid, uint16 len)
3200*4882a593Smuzhiyun {
3201*4882a593Smuzhiyun 	int i;
3202*4882a593Smuzhiyun 	int err = BCME_OK;
3203*4882a593Smuzhiyun 	char eabuf[ETHER_ADDR_STR_LEN];
3204*4882a593Smuzhiyun 	wl_proxd_result_flags_t flags;
3205*4882a593Smuzhiyun 	wl_proxd_session_state_t session_state;
3206*4882a593Smuzhiyun 	wl_proxd_status_t proxd_status;
3207*4882a593Smuzhiyun #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
3208*4882a593Smuzhiyun 	struct osl_timespec ts;
3209*4882a593Smuzhiyun #endif /* LINUX_VER >= 2.6.39 */
3210*4882a593Smuzhiyun 	uint32 ratespec;
3211*4882a593Smuzhiyun 	uint32 avg_dist;
3212*4882a593Smuzhiyun 	const wl_proxd_rtt_result_v1_t *p_data_info = NULL;
3213*4882a593Smuzhiyun 	const wl_proxd_rtt_sample_v1_t *p_sample_avg = NULL;
3214*4882a593Smuzhiyun 	const wl_proxd_rtt_sample_v1_t *p_sample = NULL;
3215*4882a593Smuzhiyun 	wl_proxd_intvl_t rtt;
3216*4882a593Smuzhiyun 	wl_proxd_intvl_t p_time;
3217*4882a593Smuzhiyun 	uint16 num_rtt = 0, snr = 0, bitflips = 0;
3218*4882a593Smuzhiyun 	wl_proxd_phy_error_t tof_phy_error = 0;
3219*4882a593Smuzhiyun 	wl_proxd_phy_error_t tof_phy_tgt_error = 0;
3220*4882a593Smuzhiyun 	wl_proxd_snr_t tof_target_snr = 0;
3221*4882a593Smuzhiyun 	wl_proxd_bitflips_t tof_target_bitflips = 0;
3222*4882a593Smuzhiyun 	int16 rssi = 0;
3223*4882a593Smuzhiyun 	int32 dist = 0;
3224*4882a593Smuzhiyun 	uint8 num_ftm = 0;
3225*4882a593Smuzhiyun 	char *ftm_frame_types[] = FTM_FRAME_TYPES;
3226*4882a593Smuzhiyun 	rtt_report_t *rtt_report = &(rtt_result->report);
3227*4882a593Smuzhiyun 
3228*4882a593Smuzhiyun 	BCM_REFERENCE(ftm_frame_types);
3229*4882a593Smuzhiyun 	BCM_REFERENCE(dist);
3230*4882a593Smuzhiyun 	BCM_REFERENCE(rssi);
3231*4882a593Smuzhiyun 	BCM_REFERENCE(tof_target_bitflips);
3232*4882a593Smuzhiyun 	BCM_REFERENCE(tof_target_snr);
3233*4882a593Smuzhiyun 	BCM_REFERENCE(tof_phy_tgt_error);
3234*4882a593Smuzhiyun 	BCM_REFERENCE(tof_phy_error);
3235*4882a593Smuzhiyun 	BCM_REFERENCE(bitflips);
3236*4882a593Smuzhiyun 	BCM_REFERENCE(snr);
3237*4882a593Smuzhiyun 	BCM_REFERENCE(session_state);
3238*4882a593Smuzhiyun 	BCM_REFERENCE(ftm_session_state_value_to_logstr);
3239*4882a593Smuzhiyun 
3240*4882a593Smuzhiyun 	NULL_CHECK(rtt_report, "rtt_report is NULL", err);
3241*4882a593Smuzhiyun 	NULL_CHECK(p_data, "p_data is NULL", err);
3242*4882a593Smuzhiyun 	DHD_RTT(("%s enter\n", __FUNCTION__));
3243*4882a593Smuzhiyun 	p_data_info = (const wl_proxd_rtt_result_v1_t *) p_data;
3244*4882a593Smuzhiyun 	/* unpack and format 'flags' for display */
3245*4882a593Smuzhiyun 	flags = ltoh16_ua(&p_data_info->flags);
3246*4882a593Smuzhiyun 
3247*4882a593Smuzhiyun 	/* session state and status */
3248*4882a593Smuzhiyun 	session_state = ltoh16_ua(&p_data_info->state);
3249*4882a593Smuzhiyun 	proxd_status = ltoh32_ua(&p_data_info->status);
3250*4882a593Smuzhiyun 	bcm_ether_ntoa((&(p_data_info->peer)), eabuf);
3251*4882a593Smuzhiyun 	DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n",
3252*4882a593Smuzhiyun 		eabuf,
3253*4882a593Smuzhiyun 		session_state,
3254*4882a593Smuzhiyun 		ftm_session_state_value_to_logstr(session_state),
3255*4882a593Smuzhiyun 		proxd_status,
3256*4882a593Smuzhiyun 		ftm_status_value_to_logstr(proxd_status)));
3257*4882a593Smuzhiyun 
3258*4882a593Smuzhiyun 	/* show avg_dist (1/256m units), burst_num */
3259*4882a593Smuzhiyun 	avg_dist = ltoh32_ua(&p_data_info->avg_dist);
3260*4882a593Smuzhiyun 	if (avg_dist == 0xffffffff) {	/* report 'failure' case */
3261*4882a593Smuzhiyun 		DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n",
3262*4882a593Smuzhiyun 		ltoh16_ua(&p_data_info->burst_num),
3263*4882a593Smuzhiyun 		p_data_info->num_valid_rtt)); /* in a session */
3264*4882a593Smuzhiyun 		avg_dist = FTM_INVALID;
3265*4882a593Smuzhiyun 	}
3266*4882a593Smuzhiyun 	else {
3267*4882a593Smuzhiyun 		DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n",
3268*4882a593Smuzhiyun 			avg_dist >> 8, /* 1/256m units */
3269*4882a593Smuzhiyun 			((avg_dist & 0xff) * 625) >> 4,
3270*4882a593Smuzhiyun 			ltoh16_ua(&p_data_info->burst_num),
3271*4882a593Smuzhiyun 			p_data_info->num_valid_rtt,
3272*4882a593Smuzhiyun 			p_data_info->num_ftm)); /* in a session */
3273*4882a593Smuzhiyun 	}
3274*4882a593Smuzhiyun 	/* show 'avg_rtt' sample */
3275*4882a593Smuzhiyun 	p_sample_avg = &p_data_info->avg_rtt;
3276*4882a593Smuzhiyun 	ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu));
3277*4882a593Smuzhiyun 	DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d ratespec=0x%08x\n",
3278*4882a593Smuzhiyun 		(int16) ltoh16_ua(&p_sample_avg->rssi),
3279*4882a593Smuzhiyun 		ltoh32_ua(&p_sample_avg->rtt.intvl),
3280*4882a593Smuzhiyun 		ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu)),
3281*4882a593Smuzhiyun 		ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10,
3282*4882a593Smuzhiyun 		ltoh32_ua(&p_sample_avg->ratespec)));
3283*4882a593Smuzhiyun 
3284*4882a593Smuzhiyun 	/* set peer address */
3285*4882a593Smuzhiyun 	rtt_report->addr = p_data_info->peer;
3286*4882a593Smuzhiyun 	/* burst num */
3287*4882a593Smuzhiyun 	rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num);
3288*4882a593Smuzhiyun 	/* success num */
3289*4882a593Smuzhiyun 	rtt_report->success_num = p_data_info->num_valid_rtt;
3290*4882a593Smuzhiyun 	/* actual number of FTM supported by peer */
3291*4882a593Smuzhiyun 	rtt_report->num_per_burst_peer = p_data_info->num_ftm;
3292*4882a593Smuzhiyun 	rtt_report->negotiated_burst_num = p_data_info->num_ftm;
3293*4882a593Smuzhiyun 	/* status */
3294*4882a593Smuzhiyun 	rtt_report->status = ftm_get_statusmap_info(proxd_status,
3295*4882a593Smuzhiyun 			&ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info));
3296*4882a593Smuzhiyun 
3297*4882a593Smuzhiyun 	/* rssi (0.5db) */
3298*4882a593Smuzhiyun 	rtt_report->rssi = ABS((wl_proxd_rssi_t)ltoh16_ua(&p_data_info->avg_rtt.rssi)) * 2;
3299*4882a593Smuzhiyun 
3300*4882a593Smuzhiyun 	/* rx rate */
3301*4882a593Smuzhiyun 	ratespec = ltoh32_ua(&p_data_info->avg_rtt.ratespec);
3302*4882a593Smuzhiyun 	rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec);
3303*4882a593Smuzhiyun 	/* tx rate */
3304*4882a593Smuzhiyun 	if (flags & WL_PROXD_RESULT_FLAG_VHTACK) {
3305*4882a593Smuzhiyun 		rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0x2010010);
3306*4882a593Smuzhiyun 	} else {
3307*4882a593Smuzhiyun 		rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0xc);
3308*4882a593Smuzhiyun 	}
3309*4882a593Smuzhiyun 	/* rtt_sd */
3310*4882a593Smuzhiyun 	rtt.tmu = ltoh16_ua(&p_data_info->avg_rtt.rtt.tmu);
3311*4882a593Smuzhiyun 	rtt.intvl = ltoh32_ua(&p_data_info->avg_rtt.rtt.intvl);
3312*4882a593Smuzhiyun 	rtt_report->rtt = (wifi_timespan)FTM_INTVL2NSEC(&rtt) * 1000; /* nano -> pico seconds */
3313*4882a593Smuzhiyun 	rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */
3314*4882a593Smuzhiyun 	DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt));
3315*4882a593Smuzhiyun 	DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi));
3316*4882a593Smuzhiyun 
3317*4882a593Smuzhiyun 	/* average distance */
3318*4882a593Smuzhiyun 	if (avg_dist != FTM_INVALID) {
3319*4882a593Smuzhiyun 		rtt_report->distance = (avg_dist >> 8) * 1000; /* meter -> mm */
3320*4882a593Smuzhiyun 		rtt_report->distance += (avg_dist & 0xff) * 1000 / 256;
3321*4882a593Smuzhiyun 	} else {
3322*4882a593Smuzhiyun 		rtt_report->distance = FTM_INVALID;
3323*4882a593Smuzhiyun 	}
3324*4882a593Smuzhiyun 	/* time stamp */
3325*4882a593Smuzhiyun 	/* get the time elapsed from boot time */
3326*4882a593Smuzhiyun #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
3327*4882a593Smuzhiyun 	osl_get_monotonic_boottime(&ts);
3328*4882a593Smuzhiyun 	rtt_report->ts = (uint64)TIMESPEC_TO_US(ts);
3329*4882a593Smuzhiyun #endif /* LINUX_VER >= 2.6.39 */
3330*4882a593Smuzhiyun 
3331*4882a593Smuzhiyun 	if (proxd_status == WL_PROXD_E_REMOTE_FAIL) {
3332*4882a593Smuzhiyun 		/* retry time  after failure */
3333*4882a593Smuzhiyun 		p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl);
3334*4882a593Smuzhiyun 		p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu);
3335*4882a593Smuzhiyun 		rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */
3336*4882a593Smuzhiyun 		DHD_RTT((">\tretry_after: %d%s\n",
3337*4882a593Smuzhiyun 			ltoh32_ua(&p_data_info->u.retry_after.intvl),
3338*4882a593Smuzhiyun 			ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu))));
3339*4882a593Smuzhiyun 	} else {
3340*4882a593Smuzhiyun 		/* burst duration */
3341*4882a593Smuzhiyun 		p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl);
3342*4882a593Smuzhiyun 		p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu);
3343*4882a593Smuzhiyun 		rtt_report->burst_duration =  FTM_INTVL2MSEC(&p_time); /* s -> ms */
3344*4882a593Smuzhiyun 		DHD_RTT((">\tburst_duration: %d%s\n",
3345*4882a593Smuzhiyun 			ltoh32_ua(&p_data_info->u.burst_duration.intvl),
3346*4882a593Smuzhiyun 			ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu))));
3347*4882a593Smuzhiyun 		DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report->burst_duration));
3348*4882a593Smuzhiyun 	}
3349*4882a593Smuzhiyun 
3350*4882a593Smuzhiyun 	/* display detail if available */
3351*4882a593Smuzhiyun 	num_rtt = ltoh16_ua(&p_data_info->num_rtt);
3352*4882a593Smuzhiyun 	if (num_rtt > 0) {
3353*4882a593Smuzhiyun 		DHD_RTT((">\tnum rtt: %d samples\n", num_rtt));
3354*4882a593Smuzhiyun 		p_sample = &p_data_info->rtt[0];
3355*4882a593Smuzhiyun 		for (i = 0; i < num_rtt; i++) {
3356*4882a593Smuzhiyun 			snr = 0;
3357*4882a593Smuzhiyun 			bitflips = 0;
3358*4882a593Smuzhiyun 			tof_phy_error = 0;
3359*4882a593Smuzhiyun 			tof_phy_tgt_error = 0;
3360*4882a593Smuzhiyun 			tof_target_snr = 0;
3361*4882a593Smuzhiyun 			tof_target_bitflips = 0;
3362*4882a593Smuzhiyun 			rssi = 0;
3363*4882a593Smuzhiyun 			dist = 0;
3364*4882a593Smuzhiyun 			num_ftm = p_data_info->num_ftm;
3365*4882a593Smuzhiyun 			/* FTM frames 1,4,7,11 have valid snr, rssi and bitflips */
3366*4882a593Smuzhiyun 			if ((i % num_ftm) == 1) {
3367*4882a593Smuzhiyun 				rssi = (wl_proxd_rssi_t) ltoh16_ua(&p_sample->rssi);
3368*4882a593Smuzhiyun 				snr = (wl_proxd_snr_t) ltoh16_ua(&p_sample->snr);
3369*4882a593Smuzhiyun 				bitflips = (wl_proxd_bitflips_t) ltoh16_ua(&p_sample->bitflips);
3370*4882a593Smuzhiyun 				tof_phy_error =
3371*4882a593Smuzhiyun 					(wl_proxd_phy_error_t)
3372*4882a593Smuzhiyun 					ltoh32_ua(&p_sample->tof_phy_error);
3373*4882a593Smuzhiyun 				tof_phy_tgt_error =
3374*4882a593Smuzhiyun 					(wl_proxd_phy_error_t)
3375*4882a593Smuzhiyun 					ltoh32_ua(&p_sample->tof_tgt_phy_error);
3376*4882a593Smuzhiyun 				tof_target_snr =
3377*4882a593Smuzhiyun 					(wl_proxd_snr_t)
3378*4882a593Smuzhiyun 					ltoh16_ua(&p_sample->tof_tgt_snr);
3379*4882a593Smuzhiyun 				tof_target_bitflips =
3380*4882a593Smuzhiyun 					(wl_proxd_bitflips_t)
3381*4882a593Smuzhiyun 					ltoh16_ua(&p_sample->tof_tgt_bitflips);
3382*4882a593Smuzhiyun 				dist = ltoh32_ua(&p_sample->distance);
3383*4882a593Smuzhiyun 			} else {
3384*4882a593Smuzhiyun 				rssi = -1;
3385*4882a593Smuzhiyun 				snr = 0;
3386*4882a593Smuzhiyun 				bitflips = 0;
3387*4882a593Smuzhiyun 				dist = 0;
3388*4882a593Smuzhiyun 				tof_target_bitflips = 0;
3389*4882a593Smuzhiyun 				tof_target_snr = 0;
3390*4882a593Smuzhiyun 				tof_phy_tgt_error = 0;
3391*4882a593Smuzhiyun 			}
3392*4882a593Smuzhiyun 			DHD_RTT((">\t sample[%d]: id=%d rssi=%d snr=0x%x bitflips=%d"
3393*4882a593Smuzhiyun 				" tof_phy_error %x tof_phy_tgt_error %x target_snr=0x%x"
3394*4882a593Smuzhiyun 				" target_bitflips=%d dist=%d rtt=%d%s status %s"
3395*4882a593Smuzhiyun 				" Type %s coreid=%d\n",
3396*4882a593Smuzhiyun 				i, p_sample->id, rssi, snr,
3397*4882a593Smuzhiyun 				bitflips, tof_phy_error, tof_phy_tgt_error,
3398*4882a593Smuzhiyun 				tof_target_snr,
3399*4882a593Smuzhiyun 				tof_target_bitflips, dist,
3400*4882a593Smuzhiyun 				ltoh32_ua(&p_sample->rtt.intvl),
3401*4882a593Smuzhiyun 				ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)),
3402*4882a593Smuzhiyun 				ftm_status_value_to_logstr(ltoh32_ua(&p_sample->status)),
3403*4882a593Smuzhiyun 				ftm_frame_types[i % num_ftm], p_sample->coreid));
3404*4882a593Smuzhiyun 			p_sample++;
3405*4882a593Smuzhiyun 		}
3406*4882a593Smuzhiyun 	}
3407*4882a593Smuzhiyun 	return err;
3408*4882a593Smuzhiyun }
3409*4882a593Smuzhiyun 
3410*4882a593Smuzhiyun static int
dhd_rtt_convert_results_to_host_v2(rtt_result_t * rtt_result,const uint8 * p_data,uint16 tlvid,uint16 len)3411*4882a593Smuzhiyun dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data,
3412*4882a593Smuzhiyun 	uint16 tlvid, uint16 len)
3413*4882a593Smuzhiyun {
3414*4882a593Smuzhiyun 	int i;
3415*4882a593Smuzhiyun 	int err = BCME_OK;
3416*4882a593Smuzhiyun 	char eabuf[ETHER_ADDR_STR_LEN];
3417*4882a593Smuzhiyun 	wl_proxd_result_flags_t flags;
3418*4882a593Smuzhiyun 	wl_proxd_session_state_t session_state;
3419*4882a593Smuzhiyun 	wl_proxd_status_t proxd_status;
3420*4882a593Smuzhiyun #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
3421*4882a593Smuzhiyun 	struct osl_timespec ts;
3422*4882a593Smuzhiyun #endif /* LINUX_VER >= 2.6.39 */
3423*4882a593Smuzhiyun 	uint32 ratespec;
3424*4882a593Smuzhiyun 	uint32 avg_dist;
3425*4882a593Smuzhiyun 	const wl_proxd_rtt_result_v2_t *p_data_info = NULL;
3426*4882a593Smuzhiyun 	const wl_proxd_rtt_sample_v2_t *p_sample_avg = NULL;
3427*4882a593Smuzhiyun 	const wl_proxd_rtt_sample_v2_t *p_sample = NULL;
3428*4882a593Smuzhiyun 	uint16 num_rtt = 0;
3429*4882a593Smuzhiyun 	wl_proxd_intvl_t rtt;
3430*4882a593Smuzhiyun 	wl_proxd_intvl_t p_time;
3431*4882a593Smuzhiyun 	uint16 snr = 0, bitflips = 0;
3432*4882a593Smuzhiyun 	wl_proxd_phy_error_t tof_phy_error = 0;
3433*4882a593Smuzhiyun 	wl_proxd_phy_error_t tof_phy_tgt_error = 0;
3434*4882a593Smuzhiyun 	wl_proxd_snr_t tof_target_snr = 0;
3435*4882a593Smuzhiyun 	wl_proxd_bitflips_t tof_target_bitflips = 0;
3436*4882a593Smuzhiyun 	int16 rssi = 0;
3437*4882a593Smuzhiyun 	int32 dist = 0;
3438*4882a593Smuzhiyun 	uint32 chanspec = 0;
3439*4882a593Smuzhiyun 	uint8 num_ftm = 0;
3440*4882a593Smuzhiyun 	char *ftm_frame_types[] =  FTM_FRAME_TYPES;
3441*4882a593Smuzhiyun 	rtt_report_t *rtt_report = &(rtt_result->report);
3442*4882a593Smuzhiyun 
3443*4882a593Smuzhiyun 	BCM_REFERENCE(ftm_frame_types);
3444*4882a593Smuzhiyun 	BCM_REFERENCE(dist);
3445*4882a593Smuzhiyun 	BCM_REFERENCE(rssi);
3446*4882a593Smuzhiyun 	BCM_REFERENCE(tof_target_bitflips);
3447*4882a593Smuzhiyun 	BCM_REFERENCE(tof_target_snr);
3448*4882a593Smuzhiyun 	BCM_REFERENCE(tof_phy_tgt_error);
3449*4882a593Smuzhiyun 	BCM_REFERENCE(tof_phy_error);
3450*4882a593Smuzhiyun 	BCM_REFERENCE(bitflips);
3451*4882a593Smuzhiyun 	BCM_REFERENCE(snr);
3452*4882a593Smuzhiyun 	BCM_REFERENCE(chanspec);
3453*4882a593Smuzhiyun 	BCM_REFERENCE(session_state);
3454*4882a593Smuzhiyun 	BCM_REFERENCE(ftm_session_state_value_to_logstr);
3455*4882a593Smuzhiyun 
3456*4882a593Smuzhiyun 	NULL_CHECK(rtt_report, "rtt_report is NULL", err);
3457*4882a593Smuzhiyun 	NULL_CHECK(p_data, "p_data is NULL", err);
3458*4882a593Smuzhiyun 	DHD_RTT(("%s enter\n", __FUNCTION__));
3459*4882a593Smuzhiyun 	p_data_info = (const wl_proxd_rtt_result_v2_t *) p_data;
3460*4882a593Smuzhiyun 	/* unpack and format 'flags' for display */
3461*4882a593Smuzhiyun 	flags = ltoh16_ua(&p_data_info->flags);
3462*4882a593Smuzhiyun 	/* session state and status */
3463*4882a593Smuzhiyun 	session_state = ltoh16_ua(&p_data_info->state);
3464*4882a593Smuzhiyun 	proxd_status = ltoh32_ua(&p_data_info->status);
3465*4882a593Smuzhiyun 	bcm_ether_ntoa((&(p_data_info->peer)), eabuf);
3466*4882a593Smuzhiyun 
3467*4882a593Smuzhiyun 	if ((proxd_status != BCME_OK) || (p_data_info->num_meas == 0)) {
3468*4882a593Smuzhiyun 		DHD_RTT_ERR((">\tTarget(%s) session state=%d(%s), status=%d(%s) "
3469*4882a593Smuzhiyun 			"num_meas_ota %d num_valid_rtt %d result_flags %x\n",
3470*4882a593Smuzhiyun 			eabuf, session_state,
3471*4882a593Smuzhiyun 			ftm_session_state_value_to_logstr(session_state),
3472*4882a593Smuzhiyun 			proxd_status, ftm_status_value_to_logstr(proxd_status),
3473*4882a593Smuzhiyun 			p_data_info->num_meas, p_data_info->num_valid_rtt,
3474*4882a593Smuzhiyun 			p_data_info->flags));
3475*4882a593Smuzhiyun 	} else {
3476*4882a593Smuzhiyun 		DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n",
3477*4882a593Smuzhiyun 		eabuf, session_state,
3478*4882a593Smuzhiyun 		ftm_session_state_value_to_logstr(session_state),
3479*4882a593Smuzhiyun 		proxd_status, ftm_status_value_to_logstr(proxd_status)));
3480*4882a593Smuzhiyun 	}
3481*4882a593Smuzhiyun 	/* show avg_dist (1/256m units), burst_num */
3482*4882a593Smuzhiyun 	avg_dist = ltoh32_ua(&p_data_info->avg_dist);
3483*4882a593Smuzhiyun 	if (avg_dist == 0xffffffff) {	/* report 'failure' case */
3484*4882a593Smuzhiyun 		DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n",
3485*4882a593Smuzhiyun 		ltoh16_ua(&p_data_info->burst_num),
3486*4882a593Smuzhiyun 		p_data_info->num_valid_rtt)); /* in a session */
3487*4882a593Smuzhiyun 		avg_dist = FTM_INVALID;
3488*4882a593Smuzhiyun 	} else {
3489*4882a593Smuzhiyun 		DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d "
3490*4882a593Smuzhiyun 			"num_meas_ota=%d, result_flags=%x\n", avg_dist >> 8, /* 1/256m units */
3491*4882a593Smuzhiyun 			((avg_dist & 0xff) * 625) >> 4,
3492*4882a593Smuzhiyun 			ltoh16_ua(&p_data_info->burst_num),
3493*4882a593Smuzhiyun 			p_data_info->num_valid_rtt,
3494*4882a593Smuzhiyun 			p_data_info->num_ftm, p_data_info->num_meas,
3495*4882a593Smuzhiyun 			p_data_info->flags)); /* in a session */
3496*4882a593Smuzhiyun 	}
3497*4882a593Smuzhiyun 	rtt_result->rtt_detail.num_ota_meas = p_data_info->num_meas;
3498*4882a593Smuzhiyun 	rtt_result->rtt_detail.result_flags = p_data_info->flags;
3499*4882a593Smuzhiyun 	/* show 'avg_rtt' sample */
3500*4882a593Smuzhiyun 	/* in v2, avg_rtt is the first element of the variable rtt[] */
3501*4882a593Smuzhiyun 	p_sample_avg = &p_data_info->rtt[0];
3502*4882a593Smuzhiyun 	ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu));
3503*4882a593Smuzhiyun 	DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d"
3504*4882a593Smuzhiyun 		"ratespec=0x%08x chanspec=0x%08x\n",
3505*4882a593Smuzhiyun 		(int16) ltoh16_ua(&p_sample_avg->rssi),
3506*4882a593Smuzhiyun 		ltoh32_ua(&p_sample_avg->rtt.intvl),
3507*4882a593Smuzhiyun 		ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample_avg->rtt.tmu)),
3508*4882a593Smuzhiyun 		ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10,
3509*4882a593Smuzhiyun 		ltoh32_ua(&p_sample_avg->ratespec),
3510*4882a593Smuzhiyun 		ltoh32_ua(&p_sample_avg->chanspec)));
3511*4882a593Smuzhiyun 
3512*4882a593Smuzhiyun 	/* set peer address */
3513*4882a593Smuzhiyun 	rtt_report->addr = p_data_info->peer;
3514*4882a593Smuzhiyun 
3515*4882a593Smuzhiyun 	/* burst num */
3516*4882a593Smuzhiyun 	rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num);
3517*4882a593Smuzhiyun 
3518*4882a593Smuzhiyun 	/* success num */
3519*4882a593Smuzhiyun 	rtt_report->success_num = p_data_info->num_valid_rtt;
3520*4882a593Smuzhiyun 
3521*4882a593Smuzhiyun 	/* num-ftm configured */
3522*4882a593Smuzhiyun 	rtt_report->ftm_num = p_data_info->num_ftm;
3523*4882a593Smuzhiyun 
3524*4882a593Smuzhiyun 	/* actual number of FTM supported by peer */
3525*4882a593Smuzhiyun 	rtt_report->num_per_burst_peer = p_data_info->num_ftm;
3526*4882a593Smuzhiyun 	rtt_report->negotiated_burst_num = p_data_info->num_ftm;
3527*4882a593Smuzhiyun 
3528*4882a593Smuzhiyun 	/* status */
3529*4882a593Smuzhiyun 	rtt_report->status = ftm_get_statusmap_info(proxd_status,
3530*4882a593Smuzhiyun 			&ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info));
3531*4882a593Smuzhiyun 
3532*4882a593Smuzhiyun 	/* Framework expects status as SUCCESS else all results will be
3533*4882a593Smuzhiyun 	* set to zero even if we have partial valid result.
3534*4882a593Smuzhiyun 	* So setting status as SUCCESS if we have a valid_rtt
3535*4882a593Smuzhiyun 	* On burst timeout we stop burst with "timeout" reason and
3536*4882a593Smuzhiyun 	* on msch end we set status as "cancel"
3537*4882a593Smuzhiyun 	*/
3538*4882a593Smuzhiyun 	if ((proxd_status == WL_PROXD_E_TIMEOUT ||
3539*4882a593Smuzhiyun 		proxd_status == WL_PROXD_E_CANCELED) &&
3540*4882a593Smuzhiyun 		rtt_report->success_num) {
3541*4882a593Smuzhiyun 		rtt_report->status = RTT_STATUS_SUCCESS;
3542*4882a593Smuzhiyun 	}
3543*4882a593Smuzhiyun 
3544*4882a593Smuzhiyun 	/* rssi (0.5db) */
3545*4882a593Smuzhiyun 	rtt_report->rssi = ABS((wl_proxd_rssi_t)ltoh16_ua(&p_sample_avg->rssi)) * 2;
3546*4882a593Smuzhiyun 
3547*4882a593Smuzhiyun 	/* rx rate */
3548*4882a593Smuzhiyun 	ratespec = ltoh32_ua(&p_sample_avg->ratespec);
3549*4882a593Smuzhiyun 	rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec);
3550*4882a593Smuzhiyun 
3551*4882a593Smuzhiyun 	/* tx rate */
3552*4882a593Smuzhiyun 	if (flags & WL_PROXD_RESULT_FLAG_VHTACK) {
3553*4882a593Smuzhiyun 		rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0x2010010);
3554*4882a593Smuzhiyun 	} else {
3555*4882a593Smuzhiyun 		rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0xc);
3556*4882a593Smuzhiyun 	}
3557*4882a593Smuzhiyun 
3558*4882a593Smuzhiyun 	/* rtt_sd */
3559*4882a593Smuzhiyun 	rtt.tmu = ltoh16_ua(&p_sample_avg->rtt.tmu);
3560*4882a593Smuzhiyun 	rtt.intvl = ltoh32_ua(&p_sample_avg->rtt.intvl);
3561*4882a593Smuzhiyun 	rtt_report->rtt = (wifi_timespan)FTM_INTVL2NSEC(&rtt) * 1000; /* nano -> pico seconds */
3562*4882a593Smuzhiyun 	rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */
3563*4882a593Smuzhiyun 	DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt));
3564*4882a593Smuzhiyun 	DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi));
3565*4882a593Smuzhiyun 
3566*4882a593Smuzhiyun 	/* average distance */
3567*4882a593Smuzhiyun 	if (avg_dist != FTM_INVALID) {
3568*4882a593Smuzhiyun 		rtt_report->distance = (avg_dist >> 8) * 1000; /* meter -> mm */
3569*4882a593Smuzhiyun 		rtt_report->distance += (avg_dist & 0xff) * 1000 / 256;
3570*4882a593Smuzhiyun 		/* rtt_sd is in 0.1 ns.
3571*4882a593Smuzhiyun 		* host needs distance_sd in milli mtrs
3572*4882a593Smuzhiyun 		* (0.1 * rtt_sd/2 * 10^-9) * C * 1000
3573*4882a593Smuzhiyun 		*/
3574*4882a593Smuzhiyun 		rtt_report->distance_sd = rtt_report->rtt_sd * 15; /* mm */
3575*4882a593Smuzhiyun 	} else {
3576*4882a593Smuzhiyun 		rtt_report->distance = FTM_INVALID;
3577*4882a593Smuzhiyun 	}
3578*4882a593Smuzhiyun 	/* time stamp */
3579*4882a593Smuzhiyun 	/* get the time elapsed from boot time */
3580*4882a593Smuzhiyun #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
3581*4882a593Smuzhiyun 	osl_get_monotonic_boottime(&ts);
3582*4882a593Smuzhiyun 	rtt_report->ts = (uint64)TIMESPEC_TO_US(ts);
3583*4882a593Smuzhiyun #endif /* LINUX_VER >= 2.6.39 */
3584*4882a593Smuzhiyun 
3585*4882a593Smuzhiyun 	if (proxd_status == WL_PROXD_E_REMOTE_FAIL) {
3586*4882a593Smuzhiyun 		/* retry time  after failure */
3587*4882a593Smuzhiyun 		p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl);
3588*4882a593Smuzhiyun 		p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu);
3589*4882a593Smuzhiyun 		rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */
3590*4882a593Smuzhiyun 		DHD_RTT((">\tretry_after: %d%s\n",
3591*4882a593Smuzhiyun 			ltoh32_ua(&p_data_info->u.retry_after.intvl),
3592*4882a593Smuzhiyun 			ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu))));
3593*4882a593Smuzhiyun 	} else {
3594*4882a593Smuzhiyun 		/* burst duration */
3595*4882a593Smuzhiyun 		p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl);
3596*4882a593Smuzhiyun 		p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu);
3597*4882a593Smuzhiyun 		rtt_report->burst_duration =  FTM_INTVL2MSEC(&p_time); /* s -> ms */
3598*4882a593Smuzhiyun 		DHD_RTT((">\tburst_duration: %d%s\n",
3599*4882a593Smuzhiyun 			ltoh32_ua(&p_data_info->u.burst_duration.intvl),
3600*4882a593Smuzhiyun 			ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu))));
3601*4882a593Smuzhiyun 		DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report->burst_duration));
3602*4882a593Smuzhiyun 	}
3603*4882a593Smuzhiyun 	/* display detail if available */
3604*4882a593Smuzhiyun 	num_rtt = ltoh16_ua(&p_data_info->num_rtt);
3605*4882a593Smuzhiyun 	if (num_rtt > 0) {
3606*4882a593Smuzhiyun 		DHD_RTT((">\tnum rtt: %d samples\n", num_rtt));
3607*4882a593Smuzhiyun 		p_sample = &p_data_info->rtt[1];
3608*4882a593Smuzhiyun 		for (i = 0; i < num_rtt; i++) {
3609*4882a593Smuzhiyun 			snr = 0;
3610*4882a593Smuzhiyun 			bitflips = 0;
3611*4882a593Smuzhiyun 			tof_phy_error = 0;
3612*4882a593Smuzhiyun 			tof_phy_tgt_error = 0;
3613*4882a593Smuzhiyun 			tof_target_snr = 0;
3614*4882a593Smuzhiyun 			tof_target_bitflips = 0;
3615*4882a593Smuzhiyun 			rssi = 0;
3616*4882a593Smuzhiyun 			dist = 0;
3617*4882a593Smuzhiyun 			num_ftm = p_data_info->num_ftm;
3618*4882a593Smuzhiyun 			/* FTM frames 1,4,7,11 have valid snr, rssi and bitflips */
3619*4882a593Smuzhiyun 			if ((i % num_ftm) == 1) {
3620*4882a593Smuzhiyun 				rssi = (wl_proxd_rssi_t) ltoh16_ua(&p_sample->rssi);
3621*4882a593Smuzhiyun 				snr = (wl_proxd_snr_t) ltoh16_ua(&p_sample->snr);
3622*4882a593Smuzhiyun 				bitflips = (wl_proxd_bitflips_t) ltoh16_ua(&p_sample->bitflips);
3623*4882a593Smuzhiyun 				tof_phy_error =
3624*4882a593Smuzhiyun 					(wl_proxd_phy_error_t)
3625*4882a593Smuzhiyun 					ltoh32_ua(&p_sample->tof_phy_error);
3626*4882a593Smuzhiyun 				tof_phy_tgt_error =
3627*4882a593Smuzhiyun 					(wl_proxd_phy_error_t)
3628*4882a593Smuzhiyun 					ltoh32_ua(&p_sample->tof_tgt_phy_error);
3629*4882a593Smuzhiyun 				tof_target_snr =
3630*4882a593Smuzhiyun 					(wl_proxd_snr_t)
3631*4882a593Smuzhiyun 					ltoh16_ua(&p_sample->tof_tgt_snr);
3632*4882a593Smuzhiyun 				tof_target_bitflips =
3633*4882a593Smuzhiyun 					(wl_proxd_bitflips_t)
3634*4882a593Smuzhiyun 					ltoh16_ua(&p_sample->tof_tgt_bitflips);
3635*4882a593Smuzhiyun 				dist = ltoh32_ua(&p_sample->distance);
3636*4882a593Smuzhiyun 				chanspec = ltoh32_ua(&p_sample->chanspec);
3637*4882a593Smuzhiyun 			} else {
3638*4882a593Smuzhiyun 				rssi = -1;
3639*4882a593Smuzhiyun 				snr = 0;
3640*4882a593Smuzhiyun 				bitflips = 0;
3641*4882a593Smuzhiyun 				dist = 0;
3642*4882a593Smuzhiyun 				tof_target_bitflips = 0;
3643*4882a593Smuzhiyun 				tof_target_snr = 0;
3644*4882a593Smuzhiyun 				tof_phy_tgt_error = 0;
3645*4882a593Smuzhiyun 			}
3646*4882a593Smuzhiyun 			DHD_RTT((">\t sample[%d]: id=%d rssi=%d snr=0x%x bitflips=%d"
3647*4882a593Smuzhiyun 				" tof_phy_error %x tof_phy_tgt_error %x target_snr=0x%x"
3648*4882a593Smuzhiyun 				" target_bitflips=%d dist=%d rtt=%d%s status %s Type %s"
3649*4882a593Smuzhiyun 				" coreid=%d chanspec=0x%08x\n",
3650*4882a593Smuzhiyun 				i, p_sample->id, rssi, snr,
3651*4882a593Smuzhiyun 				bitflips, tof_phy_error, tof_phy_tgt_error,
3652*4882a593Smuzhiyun 				tof_target_snr,
3653*4882a593Smuzhiyun 				tof_target_bitflips, dist,
3654*4882a593Smuzhiyun 				ltoh32_ua(&p_sample->rtt.intvl),
3655*4882a593Smuzhiyun 				ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)),
3656*4882a593Smuzhiyun 				ftm_status_value_to_logstr(ltoh32_ua(&p_sample->status)),
3657*4882a593Smuzhiyun 				ftm_frame_types[i % num_ftm], p_sample->coreid,
3658*4882a593Smuzhiyun 				chanspec));
3659*4882a593Smuzhiyun 			p_sample++;
3660*4882a593Smuzhiyun 		}
3661*4882a593Smuzhiyun 	}
3662*4882a593Smuzhiyun 	return err;
3663*4882a593Smuzhiyun }
3664*4882a593Smuzhiyun #ifdef WL_CFG80211
3665*4882a593Smuzhiyun /* Common API for handling Session End.
3666*4882a593Smuzhiyun * This API will flush out the results for a peer MAC.
3667*4882a593Smuzhiyun *
3668*4882a593Smuzhiyun * @For legacy FTM session, this API will be called
3669*4882a593Smuzhiyun * when legacy FTM_SESSION_END event is received.
3670*4882a593Smuzhiyun * @For legacy Nan-RTT , this API will be called when
3671*4882a593Smuzhiyun * we are cancelling the nan-ranging session or on
3672*4882a593Smuzhiyun * nan-ranging-end event.
3673*4882a593Smuzhiyun */
3674*4882a593Smuzhiyun 
3675*4882a593Smuzhiyun static bool
dhd_rtt_all_directed_targets_done(dhd_pub_t * dhd)3676*4882a593Smuzhiyun dhd_rtt_all_directed_targets_done(dhd_pub_t *dhd)
3677*4882a593Smuzhiyun {
3678*4882a593Smuzhiyun 	int8 idx;
3679*4882a593Smuzhiyun 	bool done = TRUE;
3680*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
3681*4882a593Smuzhiyun 
3682*4882a593Smuzhiyun 	for (idx = rtt_status->start_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
3683*4882a593Smuzhiyun 		if (!rtt_status->rtt_config.target_info[idx].disable) {
3684*4882a593Smuzhiyun 			if (!dhd_rtt_get_report_header(rtt_status,
3685*4882a593Smuzhiyun 					NULL, &rtt_status->rtt_config.target_info[idx].addr)) {
3686*4882a593Smuzhiyun 				done = FALSE;
3687*4882a593Smuzhiyun 				break;
3688*4882a593Smuzhiyun 			}
3689*4882a593Smuzhiyun 		}
3690*4882a593Smuzhiyun 	}
3691*4882a593Smuzhiyun 	return done;
3692*4882a593Smuzhiyun }
3693*4882a593Smuzhiyun 
3694*4882a593Smuzhiyun static void
dhd_rtt_handle_rtt_session_end(dhd_pub_t * dhd)3695*4882a593Smuzhiyun dhd_rtt_handle_rtt_session_end(dhd_pub_t *dhd)
3696*4882a593Smuzhiyun {
3697*4882a593Smuzhiyun 
3698*4882a593Smuzhiyun 	struct rtt_noti_callback *iter;
3699*4882a593Smuzhiyun 	rtt_results_header_t *entry, *next;
3700*4882a593Smuzhiyun 	rtt_result_t *next2;
3701*4882a593Smuzhiyun 	rtt_result_t *rtt_result;
3702*4882a593Smuzhiyun 	bool all_targets_done = FALSE;
3703*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
3704*4882a593Smuzhiyun #ifdef WL_NAN
3705*4882a593Smuzhiyun 	struct net_device *ndev = dhd_linux_get_primary_netdev(dhd);
3706*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(ndev->ieee80211_ptr->wiphy);
3707*4882a593Smuzhiyun #endif /* WL_NAN */
3708*4882a593Smuzhiyun 
3709*4882a593Smuzhiyun 	/* check if all targets results received */
3710*4882a593Smuzhiyun 	all_targets_done = dhd_rtt_all_directed_targets_done(dhd);
3711*4882a593Smuzhiyun 	if (all_targets_done) {
3712*4882a593Smuzhiyun 		DHD_RTT_MEM(("RTT_STOPPED\n"));
3713*4882a593Smuzhiyun 		rtt_status->status = RTT_STOPPED;
3714*4882a593Smuzhiyun 		/* notify the completed information to others */
3715*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3716*4882a593Smuzhiyun 		list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
3717*4882a593Smuzhiyun 			iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache);
3718*4882a593Smuzhiyun 		}
3719*4882a593Smuzhiyun 		/* remove the rtt results in cache */
3720*4882a593Smuzhiyun 		if (!list_empty(&rtt_status->rtt_results_cache)) {
3721*4882a593Smuzhiyun 			/* Iterate rtt_results_header list */
3722*4882a593Smuzhiyun 			list_for_each_entry_safe(entry, next,
3723*4882a593Smuzhiyun 				&rtt_status->rtt_results_cache, list) {
3724*4882a593Smuzhiyun 				list_del(&entry->list);
3725*4882a593Smuzhiyun 				/* Iterate rtt_result list */
3726*4882a593Smuzhiyun 				list_for_each_entry_safe(rtt_result, next2,
3727*4882a593Smuzhiyun 					&entry->result_list, list) {
3728*4882a593Smuzhiyun 					list_del(&rtt_result->list);
3729*4882a593Smuzhiyun 					MFREE(dhd->osh, rtt_result,
3730*4882a593Smuzhiyun 						sizeof(rtt_result_t));
3731*4882a593Smuzhiyun 				}
3732*4882a593Smuzhiyun 				MFREE(dhd->osh, entry, sizeof(rtt_results_header_t));
3733*4882a593Smuzhiyun 			}
3734*4882a593Smuzhiyun 		}
3735*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_POP();
3736*4882a593Smuzhiyun 		/* reinitialize the HEAD */
3737*4882a593Smuzhiyun 		INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
3738*4882a593Smuzhiyun 		/* clear information for rtt_config */
3739*4882a593Smuzhiyun 		rtt_status->rtt_config.rtt_target_cnt = 0;
3740*4882a593Smuzhiyun 		memset_s(rtt_status->rtt_config.target_info, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT),
3741*4882a593Smuzhiyun 			0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
3742*4882a593Smuzhiyun 		rtt_status->cur_idx = 0;
3743*4882a593Smuzhiyun 
3744*4882a593Smuzhiyun 		/* Cancel pending proxd timeout work if any */
3745*4882a593Smuzhiyun 		if (delayed_work_pending(&rtt_status->proxd_timeout)) {
3746*4882a593Smuzhiyun 			cancel_delayed_work(&rtt_status->proxd_timeout);
3747*4882a593Smuzhiyun 		}
3748*4882a593Smuzhiyun #ifdef WL_NAN
3749*4882a593Smuzhiyun 		/* Reset for Geofence */
3750*4882a593Smuzhiyun 		wl_cfgnan_reset_geofence_ranging(cfg, NULL,
3751*4882a593Smuzhiyun 			RTT_SCHED_RNG_RPT_DIRECTED, FALSE);
3752*4882a593Smuzhiyun #endif /* WL_NAN */
3753*4882a593Smuzhiyun 	} else {
3754*4882a593Smuzhiyun 		/* Targets still pending */
3755*4882a593Smuzhiyun 		if (rtt_status->rtt_config.target_list_mode == RNG_TARGET_LIST_MODE_LEGACY) {
3756*4882a593Smuzhiyun 			/* Pure legacy target list */
3757*4882a593Smuzhiyun 
3758*4882a593Smuzhiyun 			/* Cancel pending proxd timeout work if any */
3759*4882a593Smuzhiyun 			if (delayed_work_pending(&rtt_status->proxd_timeout)) {
3760*4882a593Smuzhiyun 				cancel_delayed_work(&rtt_status->proxd_timeout);
3761*4882a593Smuzhiyun 			}
3762*4882a593Smuzhiyun 
3763*4882a593Smuzhiyun 			dhd_rtt_set_next_target_idx(dhd, (rtt_status->cur_idx + 1));
3764*4882a593Smuzhiyun 			if (rtt_status->cur_idx < rtt_status->rtt_config.rtt_target_cnt) {
3765*4882a593Smuzhiyun 				/* restart to measure RTT from next device */
3766*4882a593Smuzhiyun 				DHD_INFO(("restart to measure rtt\n"));
3767*4882a593Smuzhiyun 				rtt_status->rtt_sched = TRUE;
3768*4882a593Smuzhiyun 				schedule_work(&rtt_status->work);
3769*4882a593Smuzhiyun 			}
3770*4882a593Smuzhiyun 		}
3771*4882a593Smuzhiyun #ifdef WL_NAN
3772*4882a593Smuzhiyun 		else if (rtt_status->rtt_config.target_list_mode == RNG_TARGET_LIST_MODE_NAN) {
3773*4882a593Smuzhiyun 			/* Pure NAN target list */
3774*4882a593Smuzhiyun 			dhd_rtt_trigger_pending_targets_on_session_end(dhd);
3775*4882a593Smuzhiyun 		}
3776*4882a593Smuzhiyun #endif /* WL_NAN */
3777*4882a593Smuzhiyun 	}
3778*4882a593Smuzhiyun }
3779*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3780*4882a593Smuzhiyun 
3781*4882a593Smuzhiyun #ifdef WL_CFG80211
3782*4882a593Smuzhiyun static int
dhd_rtt_create_failure_result(rtt_status_info_t * rtt_status,struct ether_addr * addr)3783*4882a593Smuzhiyun dhd_rtt_create_failure_result(rtt_status_info_t *rtt_status,
3784*4882a593Smuzhiyun 	struct ether_addr *addr)
3785*4882a593Smuzhiyun {
3786*4882a593Smuzhiyun 	rtt_results_header_t *rtt_results_header = NULL;
3787*4882a593Smuzhiyun 	rtt_target_info_t *rtt_target_info;
3788*4882a593Smuzhiyun 	int ret = BCME_OK;
3789*4882a593Smuzhiyun 	rtt_result_t *rtt_result;
3790*4882a593Smuzhiyun 
3791*4882a593Smuzhiyun 	/* allocate new header for rtt_results */
3792*4882a593Smuzhiyun 	rtt_results_header = (rtt_results_header_t *)MALLOCZ(rtt_status->dhd->osh,
3793*4882a593Smuzhiyun 		sizeof(rtt_results_header_t));
3794*4882a593Smuzhiyun 	if (!rtt_results_header) {
3795*4882a593Smuzhiyun 		ret = -ENOMEM;
3796*4882a593Smuzhiyun 		goto exit;
3797*4882a593Smuzhiyun 	}
3798*4882a593Smuzhiyun 	rtt_target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
3799*4882a593Smuzhiyun 	/* Initialize the head of list for rtt result */
3800*4882a593Smuzhiyun 	INIT_LIST_HEAD(&rtt_results_header->result_list);
3801*4882a593Smuzhiyun 	/* same src and dest len */
3802*4882a593Smuzhiyun 	(void)memcpy_s(&rtt_results_header->peer_mac,
3803*4882a593Smuzhiyun 		ETHER_ADDR_LEN, addr, ETHER_ADDR_LEN);
3804*4882a593Smuzhiyun 	list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache);
3805*4882a593Smuzhiyun 
3806*4882a593Smuzhiyun 	/* allocate rtt_results for new results */
3807*4882a593Smuzhiyun 	rtt_result = (rtt_result_t *)MALLOCZ(rtt_status->dhd->osh,
3808*4882a593Smuzhiyun 		sizeof(rtt_result_t));
3809*4882a593Smuzhiyun 	if (!rtt_result) {
3810*4882a593Smuzhiyun 		ret = -ENOMEM;
3811*4882a593Smuzhiyun 		/* Free rtt result header */
3812*4882a593Smuzhiyun 		MFREE(rtt_status->dhd->osh, rtt_results_header, sizeof(rtt_results_header_t));
3813*4882a593Smuzhiyun 		goto exit;
3814*4882a593Smuzhiyun 	}
3815*4882a593Smuzhiyun 	/* fill out the results from the configuration param */
3816*4882a593Smuzhiyun 	rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst;
3817*4882a593Smuzhiyun 	rtt_result->report.type = RTT_TWO_WAY;
3818*4882a593Smuzhiyun 	DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num));
3819*4882a593Smuzhiyun 	rtt_result->report_len = RTT_REPORT_SIZE;
3820*4882a593Smuzhiyun 	rtt_result->report.status = RTT_STATUS_FAIL_NO_RSP;
3821*4882a593Smuzhiyun 	/* same src and dest len */
3822*4882a593Smuzhiyun 	(void)memcpy_s(&rtt_result->report.addr, ETHER_ADDR_LEN,
3823*4882a593Smuzhiyun 		&rtt_target_info->addr, ETHER_ADDR_LEN);
3824*4882a593Smuzhiyun 	rtt_result->report.distance = FTM_INVALID;
3825*4882a593Smuzhiyun 	list_add_tail(&rtt_result->list, &rtt_results_header->result_list);
3826*4882a593Smuzhiyun 	rtt_results_header->result_cnt++;
3827*4882a593Smuzhiyun 	rtt_results_header->result_tot_len += rtt_result->report_len;
3828*4882a593Smuzhiyun exit:
3829*4882a593Smuzhiyun 	return ret;
3830*4882a593Smuzhiyun }
3831*4882a593Smuzhiyun 
3832*4882a593Smuzhiyun static bool
dhd_rtt_get_report_header(rtt_status_info_t * rtt_status,rtt_results_header_t ** rtt_results_header,struct ether_addr * addr)3833*4882a593Smuzhiyun dhd_rtt_get_report_header(rtt_status_info_t *rtt_status,
3834*4882a593Smuzhiyun 	rtt_results_header_t **rtt_results_header, struct ether_addr *addr)
3835*4882a593Smuzhiyun {
3836*4882a593Smuzhiyun 	rtt_results_header_t *entry;
3837*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3838*4882a593Smuzhiyun 	/* find a rtt_report_header for this mac address */
3839*4882a593Smuzhiyun 	list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) {
3840*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_POP();
3841*4882a593Smuzhiyun 		if (!memcmp(&entry->peer_mac, addr, ETHER_ADDR_LEN))  {
3842*4882a593Smuzhiyun 			/* found a rtt_report_header for peer_mac in the list */
3843*4882a593Smuzhiyun 			if (rtt_results_header) {
3844*4882a593Smuzhiyun 				*rtt_results_header = entry;
3845*4882a593Smuzhiyun 			}
3846*4882a593Smuzhiyun 			return TRUE;
3847*4882a593Smuzhiyun 		}
3848*4882a593Smuzhiyun 	}
3849*4882a593Smuzhiyun 	return FALSE;
3850*4882a593Smuzhiyun }
3851*4882a593Smuzhiyun 
3852*4882a593Smuzhiyun #ifdef WL_NAN
3853*4882a593Smuzhiyun int
dhd_rtt_handle_nan_rtt_session_end(dhd_pub_t * dhd,struct ether_addr * peer)3854*4882a593Smuzhiyun dhd_rtt_handle_nan_rtt_session_end(dhd_pub_t *dhd, struct ether_addr *peer)
3855*4882a593Smuzhiyun {
3856*4882a593Smuzhiyun 	bool is_new = TRUE;
3857*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = GET_RTTSTATE(dhd);
3858*4882a593Smuzhiyun 	mutex_lock(&rtt_status->rtt_mutex);
3859*4882a593Smuzhiyun 	is_new = !dhd_rtt_get_report_header(rtt_status, NULL, peer);
3860*4882a593Smuzhiyun 
3861*4882a593Smuzhiyun 	if (is_new) { /* no FTM result..create failure result */
3862*4882a593Smuzhiyun 		dhd_rtt_create_failure_result(rtt_status, peer);
3863*4882a593Smuzhiyun 	}
3864*4882a593Smuzhiyun 	DHD_RTT_MEM(("RTT Session End for NAN peer "MACDBG"\n", MAC2STRDBG(peer)));
3865*4882a593Smuzhiyun 	dhd_rtt_handle_rtt_session_end(dhd);
3866*4882a593Smuzhiyun 	mutex_unlock(&rtt_status->rtt_mutex);
3867*4882a593Smuzhiyun 	return BCME_OK;
3868*4882a593Smuzhiyun }
3869*4882a593Smuzhiyun 
3870*4882a593Smuzhiyun static bool
dhd_rtt_is_valid_measurement(rtt_result_t * rtt_result)3871*4882a593Smuzhiyun dhd_rtt_is_valid_measurement(rtt_result_t *rtt_result)
3872*4882a593Smuzhiyun {
3873*4882a593Smuzhiyun 	bool ret = FALSE;
3874*4882a593Smuzhiyun 
3875*4882a593Smuzhiyun 	if (rtt_result && (rtt_result->report.success_num != 0)) {
3876*4882a593Smuzhiyun 		ret = TRUE;
3877*4882a593Smuzhiyun 	}
3878*4882a593Smuzhiyun 	return ret;
3879*4882a593Smuzhiyun }
3880*4882a593Smuzhiyun 
3881*4882a593Smuzhiyun static void
dhd_rtt_trigger_pending_targets_on_session_end(dhd_pub_t * dhd)3882*4882a593Smuzhiyun dhd_rtt_trigger_pending_targets_on_session_end(dhd_pub_t *dhd)
3883*4882a593Smuzhiyun {
3884*4882a593Smuzhiyun 	if (!(dhd_rtt_nan_is_directed_setup_in_prog(dhd)) &&
3885*4882a593Smuzhiyun 			(!dhd_rtt_nan_all_directed_sessions_triggered(dhd)) &&
3886*4882a593Smuzhiyun 			(!dhd_rtt_nan_directed_sessions_allowed(dhd))) {
3887*4882a593Smuzhiyun 		/* Trigger next target from here */
3888*4882a593Smuzhiyun 		dhd_rtt_set_next_target_idx(dhd,
3889*4882a593Smuzhiyun 				(dhd_rtt_get_cur_target_idx(dhd) + 1));
3890*4882a593Smuzhiyun 		dhd_rtt_schedule_rtt_work_thread(dhd, RTT_SCHED_RNG_DIR_EXCESS_TARGET);
3891*4882a593Smuzhiyun 	}
3892*4882a593Smuzhiyun }
3893*4882a593Smuzhiyun #endif /* WL_NAN */
3894*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3895*4882a593Smuzhiyun 
3896*4882a593Smuzhiyun static int
dhd_rtt_parse_result_event(wl_proxd_event_t * proxd_ev_data,int tlvs_len,rtt_result_t * rtt_result)3897*4882a593Smuzhiyun dhd_rtt_parse_result_event(wl_proxd_event_t *proxd_ev_data,
3898*4882a593Smuzhiyun 	int tlvs_len, rtt_result_t *rtt_result)
3899*4882a593Smuzhiyun {
3900*4882a593Smuzhiyun 	int ret = BCME_OK;
3901*4882a593Smuzhiyun 
3902*4882a593Smuzhiyun 	/* unpack TLVs and invokes the cbfn to print the event content TLVs */
3903*4882a593Smuzhiyun 	ret = bcm_unpack_xtlv_buf((void *) rtt_result,
3904*4882a593Smuzhiyun 			(uint8 *)&proxd_ev_data->tlvs[0], tlvs_len,
3905*4882a593Smuzhiyun 			BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn);
3906*4882a593Smuzhiyun 	if (ret != BCME_OK) {
3907*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s : Failed to unpack xtlv for an event\n",
3908*4882a593Smuzhiyun 			__FUNCTION__));
3909*4882a593Smuzhiyun 		goto exit;
3910*4882a593Smuzhiyun 	}
3911*4882a593Smuzhiyun 	/* fill out the results from the configuration param */
3912*4882a593Smuzhiyun 	rtt_result->report.type = RTT_TWO_WAY;
3913*4882a593Smuzhiyun 	DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num));
3914*4882a593Smuzhiyun 	rtt_result->report_len = RTT_REPORT_SIZE;
3915*4882a593Smuzhiyun 	rtt_result->detail_len = sizeof(rtt_result->rtt_detail);
3916*4882a593Smuzhiyun 
3917*4882a593Smuzhiyun exit:
3918*4882a593Smuzhiyun 	return ret;
3919*4882a593Smuzhiyun 
3920*4882a593Smuzhiyun }
3921*4882a593Smuzhiyun 
3922*4882a593Smuzhiyun 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)3923*4882a593Smuzhiyun dhd_rtt_handle_directed_rtt_burst_end(dhd_pub_t *dhd, struct ether_addr *peer_addr,
3924*4882a593Smuzhiyun         wl_proxd_event_t *proxd_ev_data, int tlvs_len, rtt_result_t *rtt_result, bool is_nan)
3925*4882a593Smuzhiyun {
3926*4882a593Smuzhiyun 	int ret = BCME_OK;
3927*4882a593Smuzhiyun 
3928*4882a593Smuzhiyun #ifdef WL_CFG80211
3929*4882a593Smuzhiyun 	int err_at = 0;
3930*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
3931*4882a593Smuzhiyun 	bool is_new = TRUE;
3932*4882a593Smuzhiyun 	rtt_results_header_t *rtt_results_header = NULL;
3933*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3934*4882a593Smuzhiyun 
3935*4882a593Smuzhiyun #ifdef WL_CFG80211
3936*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
3937*4882a593Smuzhiyun 	is_new = !dhd_rtt_get_report_header(rtt_status,
3938*4882a593Smuzhiyun 		&rtt_results_header, peer_addr);
3939*4882a593Smuzhiyun 
3940*4882a593Smuzhiyun 	if (tlvs_len > 0) {
3941*4882a593Smuzhiyun 		if (is_new) {
3942*4882a593Smuzhiyun 			/* allocate new header for rtt_results */
3943*4882a593Smuzhiyun 			rtt_results_header = (rtt_results_header_t *)MALLOCZ(rtt_status->dhd->osh,
3944*4882a593Smuzhiyun 				sizeof(rtt_results_header_t));
3945*4882a593Smuzhiyun 			if (!rtt_results_header) {
3946*4882a593Smuzhiyun 				ret = BCME_NORESOURCE;
3947*4882a593Smuzhiyun 				err_at = 1;
3948*4882a593Smuzhiyun 				goto exit;
3949*4882a593Smuzhiyun 			}
3950*4882a593Smuzhiyun 			/* Initialize the head of list for rtt result */
3951*4882a593Smuzhiyun 			INIT_LIST_HEAD(&rtt_results_header->result_list);
3952*4882a593Smuzhiyun 			/* same src and header len */
3953*4882a593Smuzhiyun 			(void)memcpy_s(&rtt_results_header->peer_mac, ETHER_ADDR_LEN,
3954*4882a593Smuzhiyun 				peer_addr, ETHER_ADDR_LEN);
3955*4882a593Smuzhiyun 			list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache);
3956*4882a593Smuzhiyun 		}
3957*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3958*4882a593Smuzhiyun 
3959*4882a593Smuzhiyun 		ret = dhd_rtt_parse_result_event(proxd_ev_data, tlvs_len, rtt_result);
3960*4882a593Smuzhiyun #ifdef WL_CFG80211
3961*4882a593Smuzhiyun 		if (ret == BCME_OK) {
3962*4882a593Smuzhiyun 			list_add_tail(&rtt_result->list, &rtt_results_header->result_list);
3963*4882a593Smuzhiyun 			rtt_results_header->result_cnt++;
3964*4882a593Smuzhiyun 			rtt_results_header->result_tot_len += rtt_result->report_len +
3965*4882a593Smuzhiyun 				rtt_result->detail_len;
3966*4882a593Smuzhiyun 		} else {
3967*4882a593Smuzhiyun 			err_at = 2;
3968*4882a593Smuzhiyun 			goto exit;
3969*4882a593Smuzhiyun 		}
3970*4882a593Smuzhiyun 	} else {
3971*4882a593Smuzhiyun 		ret = BCME_ERROR;
3972*4882a593Smuzhiyun 		err_at = 4;
3973*4882a593Smuzhiyun 		goto exit;
3974*4882a593Smuzhiyun 	}
3975*4882a593Smuzhiyun 
3976*4882a593Smuzhiyun exit:
3977*4882a593Smuzhiyun 	if (ret != BCME_OK) {
3978*4882a593Smuzhiyun 		DHD_RTT_ERR(("dhd_rtt_handle_directed_rtt_burst_end: failed, "
3979*4882a593Smuzhiyun 			" ret = %d, err_at = %d\n", ret, err_at));
3980*4882a593Smuzhiyun 		if (rtt_results_header) {
3981*4882a593Smuzhiyun 			list_del(&rtt_results_header->list);
3982*4882a593Smuzhiyun 			MFREE(dhd->osh, rtt_results_header,
3983*4882a593Smuzhiyun 				sizeof(rtt_results_header_t));
3984*4882a593Smuzhiyun 		}
3985*4882a593Smuzhiyun 	}
3986*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3987*4882a593Smuzhiyun 	return ret;
3988*4882a593Smuzhiyun }
3989*4882a593Smuzhiyun 
3990*4882a593Smuzhiyun #ifdef WL_NAN
3991*4882a593Smuzhiyun static	void
dhd_rtt_nan_range_report(struct bcm_cfg80211 * cfg,rtt_result_t * rtt_result,bool is_geofence)3992*4882a593Smuzhiyun dhd_rtt_nan_range_report(struct bcm_cfg80211 *cfg,
3993*4882a593Smuzhiyun 		rtt_result_t *rtt_result, bool is_geofence)
3994*4882a593Smuzhiyun {
3995*4882a593Smuzhiyun 	wl_nan_ev_rng_rpt_ind_t range_res;
3996*4882a593Smuzhiyun 	int rtt_status;
3997*4882a593Smuzhiyun 
3998*4882a593Smuzhiyun 	UNUSED_PARAMETER(range_res);
3999*4882a593Smuzhiyun 
4000*4882a593Smuzhiyun 	if (!rtt_result)
4001*4882a593Smuzhiyun 		return;
4002*4882a593Smuzhiyun 
4003*4882a593Smuzhiyun 	rtt_status = rtt_result->report.status;
4004*4882a593Smuzhiyun 	bzero(&range_res, sizeof(range_res));
4005*4882a593Smuzhiyun 	range_res.dist_mm = rtt_result->report.distance;
4006*4882a593Smuzhiyun 	/* same src and header len, ignoring ret val here */
4007*4882a593Smuzhiyun 	(void)memcpy_s(&range_res.peer_m_addr, ETHER_ADDR_LEN,
4008*4882a593Smuzhiyun 		&rtt_result->report.addr, ETHER_ADDR_LEN);
4009*4882a593Smuzhiyun 	wl_cfgnan_process_range_report(cfg, &range_res, rtt_status);
4010*4882a593Smuzhiyun 
4011*4882a593Smuzhiyun 	return;
4012*4882a593Smuzhiyun }
4013*4882a593Smuzhiyun 
4014*4882a593Smuzhiyun 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)4015*4882a593Smuzhiyun dhd_rtt_handle_nan_burst_end(dhd_pub_t *dhd, struct ether_addr *peer_addr,
4016*4882a593Smuzhiyun 	wl_proxd_event_t *proxd_ev_data, int tlvs_len)
4017*4882a593Smuzhiyun {
4018*4882a593Smuzhiyun 	struct net_device *ndev = NULL;
4019*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = NULL;
4020*4882a593Smuzhiyun 	nan_ranging_inst_t *rng_inst = NULL;
4021*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = NULL;
4022*4882a593Smuzhiyun 	rtt_result_t *rtt_result = NULL;
4023*4882a593Smuzhiyun 	bool geofence_rtt = FALSE;
4024*4882a593Smuzhiyun 	int ret = BCME_OK;
4025*4882a593Smuzhiyun 	rtt_result_t nan_rtt_res;
4026*4882a593Smuzhiyun 	uint8 ftm_retry_cnt = 0;
4027*4882a593Smuzhiyun 	int burst_status = -1;
4028*4882a593Smuzhiyun 
4029*4882a593Smuzhiyun 	ndev = dhd_linux_get_primary_netdev(dhd);
4030*4882a593Smuzhiyun 	cfg =  wiphy_priv(ndev->ieee80211_ptr->wiphy);
4031*4882a593Smuzhiyun 
4032*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
4033*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", ret);
4034*4882a593Smuzhiyun 	NAN_MUTEX_LOCK();
4035*4882a593Smuzhiyun 	mutex_lock(&rtt_status->rtt_mutex);
4036*4882a593Smuzhiyun 
4037*4882a593Smuzhiyun 	if ((wl_cfgnan_is_enabled(cfg) == FALSE) ||
4038*4882a593Smuzhiyun 		ETHER_ISNULLADDR(peer_addr)) {
4039*4882a593Smuzhiyun 		DHD_RTT_ERR(("Received Burst End with NULL ether addr, "
4040*4882a593Smuzhiyun 			"or nan disable, nan_enable = %d\n", wl_cfgnan_is_enabled(cfg)));
4041*4882a593Smuzhiyun 		ret = BCME_UNSUPPORTED;
4042*4882a593Smuzhiyun 		goto exit;
4043*4882a593Smuzhiyun 	}
4044*4882a593Smuzhiyun 
4045*4882a593Smuzhiyun 	rng_inst = wl_cfgnan_check_for_ranging(cfg, peer_addr);
4046*4882a593Smuzhiyun 	if (rng_inst) {
4047*4882a593Smuzhiyun 		geofence_rtt = (rng_inst->range_type
4048*4882a593Smuzhiyun 			== RTT_TYPE_NAN_GEOFENCE);
4049*4882a593Smuzhiyun 	} else {
4050*4882a593Smuzhiyun 		DHD_RTT_ERR(("Received Burst End without Ranging Instance\n"));
4051*4882a593Smuzhiyun 		ret = BCME_ERROR;
4052*4882a593Smuzhiyun 		goto exit;
4053*4882a593Smuzhiyun 	}
4054*4882a593Smuzhiyun 
4055*4882a593Smuzhiyun 	if (rng_inst->range_role == NAN_RANGING_ROLE_RESPONDER) {
4056*4882a593Smuzhiyun 		ret = BCME_OK;
4057*4882a593Smuzhiyun 		goto exit;
4058*4882a593Smuzhiyun 	}
4059*4882a593Smuzhiyun 
4060*4882a593Smuzhiyun 	bzero(&nan_rtt_res, sizeof(nan_rtt_res));
4061*4882a593Smuzhiyun 	ret = dhd_rtt_parse_result_event(proxd_ev_data, tlvs_len, &nan_rtt_res);
4062*4882a593Smuzhiyun 	if (ret != BCME_OK) {
4063*4882a593Smuzhiyun 		DHD_RTT_ERR(("Failed to parse RTT result %d\n", ret));
4064*4882a593Smuzhiyun 		goto exit;
4065*4882a593Smuzhiyun 	}
4066*4882a593Smuzhiyun 
4067*4882a593Smuzhiyun 	burst_status = nan_rtt_res.report.status;
4068*4882a593Smuzhiyun 	if (nan_rtt_res.rtt_detail.num_ota_meas <= 1) {
4069*4882a593Smuzhiyun 		/* Wait for some time(CRBs) for ftm protocol to go through */
4070*4882a593Smuzhiyun 		if (rng_inst->ftm_ssn_retry_count < NAN_RTT_FTM_SSN_RETRIES) {
4071*4882a593Smuzhiyun 			rng_inst->ftm_ssn_retry_count++;
4072*4882a593Smuzhiyun 			ftm_retry_cnt = rng_inst->ftm_ssn_retry_count;
4073*4882a593Smuzhiyun 			ret = BCME_ERROR;
4074*4882a593Smuzhiyun 			goto exit;
4075*4882a593Smuzhiyun 		}
4076*4882a593Smuzhiyun 		/* retries over...report the result as is to host */
4077*4882a593Smuzhiyun 	}
4078*4882a593Smuzhiyun 
4079*4882a593Smuzhiyun 	BCM_REFERENCE(dhd_rtt_is_valid_measurement);
4080*4882a593Smuzhiyun 
4081*4882a593Smuzhiyun 	if (geofence_rtt) {
4082*4882a593Smuzhiyun 		rtt_result = &nan_rtt_res;
4083*4882a593Smuzhiyun 	} else {
4084*4882a593Smuzhiyun 		if (RTT_IS_STOPPED(rtt_status)) {
4085*4882a593Smuzhiyun 			/* Ignore the Proxd event */
4086*4882a593Smuzhiyun 			DHD_RTT((" event handler rtt is stopped \n"));
4087*4882a593Smuzhiyun 			if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) {
4088*4882a593Smuzhiyun 				DHD_RTT(("Device is target/Responder. Recv the event. \n"));
4089*4882a593Smuzhiyun 			} else {
4090*4882a593Smuzhiyun 				ret = BCME_UNSUPPORTED;
4091*4882a593Smuzhiyun 				goto exit;
4092*4882a593Smuzhiyun 			}
4093*4882a593Smuzhiyun 		}
4094*4882a593Smuzhiyun 		/* allocate rtt_results for new results */
4095*4882a593Smuzhiyun 		rtt_result = (rtt_result_t *)MALLOCZ(dhd->osh, sizeof(rtt_result_t));
4096*4882a593Smuzhiyun 		if (!rtt_result) {
4097*4882a593Smuzhiyun 			ret = BCME_NORESOURCE;
4098*4882a593Smuzhiyun 			goto exit;
4099*4882a593Smuzhiyun 		}
4100*4882a593Smuzhiyun 		ret = dhd_rtt_handle_directed_rtt_burst_end(dhd, peer_addr,
4101*4882a593Smuzhiyun 			proxd_ev_data, tlvs_len, rtt_result, TRUE);
4102*4882a593Smuzhiyun 		if (ret != BCME_OK) {
4103*4882a593Smuzhiyun 			goto exit;
4104*4882a593Smuzhiyun 		}
4105*4882a593Smuzhiyun 
4106*4882a593Smuzhiyun 	}
4107*4882a593Smuzhiyun 
4108*4882a593Smuzhiyun exit:
4109*4882a593Smuzhiyun 	mutex_unlock(&rtt_status->rtt_mutex);
4110*4882a593Smuzhiyun 	if (ret == BCME_OK) {
4111*4882a593Smuzhiyun 		/* Nothing to do for Responder */
4112*4882a593Smuzhiyun 		if (rng_inst->range_role == NAN_RANGING_ROLE_INITIATOR) {
4113*4882a593Smuzhiyun 			dhd_rtt_nan_range_report(cfg, rtt_result, geofence_rtt);
4114*4882a593Smuzhiyun 		}
4115*4882a593Smuzhiyun 	} else {
4116*4882a593Smuzhiyun 		DHD_RTT_ERR(("nan-rtt: Burst End handling failed err %d is_geofence %d "
4117*4882a593Smuzhiyun 			"retry cnt %d burst status %d", ret, geofence_rtt,
4118*4882a593Smuzhiyun 			ftm_retry_cnt, burst_status));
4119*4882a593Smuzhiyun 		if (rtt_result && !geofence_rtt) {
4120*4882a593Smuzhiyun 			MFREE(dhd->osh, rtt_result,
4121*4882a593Smuzhiyun 				sizeof(rtt_result_t));
4122*4882a593Smuzhiyun 		}
4123*4882a593Smuzhiyun 	}
4124*4882a593Smuzhiyun 	NAN_MUTEX_UNLOCK();
4125*4882a593Smuzhiyun 	return ret;
4126*4882a593Smuzhiyun }
4127*4882a593Smuzhiyun #endif /* WL_NAN */
4128*4882a593Smuzhiyun 
4129*4882a593Smuzhiyun int
dhd_rtt_event_handler(dhd_pub_t * dhd,wl_event_msg_t * event,void * event_data)4130*4882a593Smuzhiyun dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
4131*4882a593Smuzhiyun {
4132*4882a593Smuzhiyun 	int ret = BCME_OK;
4133*4882a593Smuzhiyun 	int tlvs_len;
4134*4882a593Smuzhiyun 	uint16 version;
4135*4882a593Smuzhiyun 	wl_proxd_event_t *p_event;
4136*4882a593Smuzhiyun 	wl_proxd_event_type_t event_type;
4137*4882a593Smuzhiyun 	wl_proxd_ftm_session_status_t session_status;
4138*4882a593Smuzhiyun 	const ftm_strmap_entry_t *p_loginfo;
4139*4882a593Smuzhiyun 	rtt_result_t *rtt_result;
4140*4882a593Smuzhiyun #ifdef WL_CFG80211
4141*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
4142*4882a593Smuzhiyun 	rtt_results_header_t *rtt_results_header = NULL;
4143*4882a593Smuzhiyun 	bool is_new = TRUE;
4144*4882a593Smuzhiyun 	rtt_target_info_t *target = NULL;
4145*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4146*4882a593Smuzhiyun 
4147*4882a593Smuzhiyun 	DHD_RTT(("Enter %s \n", __FUNCTION__));
4148*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", ret);
4149*4882a593Smuzhiyun 
4150*4882a593Smuzhiyun 	if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) {
4151*4882a593Smuzhiyun 		DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__,
4152*4882a593Smuzhiyun 			ntoh32_ua((void *)&event->datalen)));
4153*4882a593Smuzhiyun 		return -EINVAL;
4154*4882a593Smuzhiyun 	}
4155*4882a593Smuzhiyun 	event_type = ntoh32_ua((void *)&event->event_type);
4156*4882a593Smuzhiyun 	if (event_type != WLC_E_PROXD) {
4157*4882a593Smuzhiyun 		DHD_RTT_ERR((" failed event \n"));
4158*4882a593Smuzhiyun 		return -EINVAL;
4159*4882a593Smuzhiyun 	}
4160*4882a593Smuzhiyun 
4161*4882a593Smuzhiyun 	if (!event_data) {
4162*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s: event_data:NULL\n", __FUNCTION__));
4163*4882a593Smuzhiyun 		return -EINVAL;
4164*4882a593Smuzhiyun 	}
4165*4882a593Smuzhiyun 	p_event = (wl_proxd_event_t *) event_data;
4166*4882a593Smuzhiyun 	version = ltoh16(p_event->version);
4167*4882a593Smuzhiyun 	if (version < WL_PROXD_API_VERSION) {
4168*4882a593Smuzhiyun 		DHD_RTT_ERR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n",
4169*4882a593Smuzhiyun 			version, WL_PROXD_API_VERSION));
4170*4882a593Smuzhiyun 		return ret;
4171*4882a593Smuzhiyun 	}
4172*4882a593Smuzhiyun 
4173*4882a593Smuzhiyun 	event_type = (wl_proxd_event_type_t) ltoh16(p_event->type);
4174*4882a593Smuzhiyun 
4175*4882a593Smuzhiyun 	DHD_RTT(("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x\n",
4176*4882a593Smuzhiyun 		p_event->type, ntoh16(p_event->type), ltoh16(p_event->type)));
4177*4882a593Smuzhiyun 	p_loginfo = ftm_get_event_type_loginfo(event_type);
4178*4882a593Smuzhiyun 	if (p_loginfo == NULL) {
4179*4882a593Smuzhiyun 		DHD_RTT_ERR(("receive an invalid FTM event %d\n", event_type));
4180*4882a593Smuzhiyun 		ret = -EINVAL;
4181*4882a593Smuzhiyun 		return ret;	/* ignore this event */
4182*4882a593Smuzhiyun 	}
4183*4882a593Smuzhiyun 	/* get TLVs len, skip over event header */
4184*4882a593Smuzhiyun 	if (ltoh16(p_event->len) < OFFSETOF(wl_proxd_event_t, tlvs)) {
4185*4882a593Smuzhiyun 		DHD_RTT_ERR(("invalid FTM event length:%d\n", ltoh16(p_event->len)));
4186*4882a593Smuzhiyun 		ret = -EINVAL;
4187*4882a593Smuzhiyun 		return ret;
4188*4882a593Smuzhiyun 	}
4189*4882a593Smuzhiyun 	tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs);
4190*4882a593Smuzhiyun 	DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n",
4191*4882a593Smuzhiyun 		p_loginfo->text,
4192*4882a593Smuzhiyun 		version,
4193*4882a593Smuzhiyun 		ltoh16(p_event->len),
4194*4882a593Smuzhiyun 		ltoh16(p_event->method),
4195*4882a593Smuzhiyun 		ltoh16(p_event->sid),
4196*4882a593Smuzhiyun 		tlvs_len));
4197*4882a593Smuzhiyun #ifdef WL_CFG80211
4198*4882a593Smuzhiyun #ifdef WL_NAN
4199*4882a593Smuzhiyun 	if ((event_type == WL_PROXD_EVENT_BURST_END) &&
4200*4882a593Smuzhiyun 			dhd_rtt_is_nan_peer(dhd, &event->addr)) {
4201*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_BURST_END for NAN RTT\n"));
4202*4882a593Smuzhiyun 		ret = dhd_rtt_handle_nan_burst_end(dhd, &event->addr, p_event, tlvs_len);
4203*4882a593Smuzhiyun 		return ret;
4204*4882a593Smuzhiyun 	}
4205*4882a593Smuzhiyun #endif /* WL_NAN */
4206*4882a593Smuzhiyun 
4207*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
4208*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", ret);
4209*4882a593Smuzhiyun 	mutex_lock(&rtt_status->rtt_mutex);
4210*4882a593Smuzhiyun 
4211*4882a593Smuzhiyun 	if (RTT_IS_STOPPED(rtt_status)) {
4212*4882a593Smuzhiyun 		/* Ignore the Proxd event */
4213*4882a593Smuzhiyun 		DHD_RTT((" event handler rtt is stopped \n"));
4214*4882a593Smuzhiyun 		if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) {
4215*4882a593Smuzhiyun 			DHD_RTT(("Device is target/Responder. Recv the event. \n"));
4216*4882a593Smuzhiyun 		} else {
4217*4882a593Smuzhiyun 			ret = BCME_NOTREADY;
4218*4882a593Smuzhiyun 			goto exit;
4219*4882a593Smuzhiyun 		}
4220*4882a593Smuzhiyun 	}
4221*4882a593Smuzhiyun 
4222*4882a593Smuzhiyun 	/* check current target_mac and event_mac are matching */
4223*4882a593Smuzhiyun 	target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
4224*4882a593Smuzhiyun 	if (memcmp(&target->addr, &event->addr, ETHER_ADDR_LEN)) {
4225*4882a593Smuzhiyun 		DHD_RTT(("Ignore Proxd event for the unexpected peer "MACDBG
4226*4882a593Smuzhiyun 			" expected peer "MACDBG"\n", MAC2STRDBG(&event->addr),
4227*4882a593Smuzhiyun 			MAC2STRDBG(&target->addr)));
4228*4882a593Smuzhiyun 		goto exit;
4229*4882a593Smuzhiyun 	}
4230*4882a593Smuzhiyun 
4231*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4232*4882a593Smuzhiyun 
4233*4882a593Smuzhiyun #ifdef WL_CFG80211
4234*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4235*4882a593Smuzhiyun 	is_new = !dhd_rtt_get_report_header(rtt_status,
4236*4882a593Smuzhiyun 		&rtt_results_header, &event->addr);
4237*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_POP();
4238*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4239*4882a593Smuzhiyun 	switch (event_type) {
4240*4882a593Smuzhiyun 	case WL_PROXD_EVENT_SESSION_CREATE:
4241*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_SESSION_CREATE\n"));
4242*4882a593Smuzhiyun 		break;
4243*4882a593Smuzhiyun 	case WL_PROXD_EVENT_SESSION_START:
4244*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_SESSION_START\n"));
4245*4882a593Smuzhiyun 		break;
4246*4882a593Smuzhiyun 	case WL_PROXD_EVENT_BURST_START:
4247*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_BURST_START\n"));
4248*4882a593Smuzhiyun 		break;
4249*4882a593Smuzhiyun 	case WL_PROXD_EVENT_BURST_END:
4250*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_BURST_END for Legacy RTT\n"));
4251*4882a593Smuzhiyun 		/* allocate rtt_results for new legacy rtt results */
4252*4882a593Smuzhiyun 		rtt_result = (rtt_result_t *)MALLOCZ(dhd->osh, sizeof(rtt_result_t));
4253*4882a593Smuzhiyun 		if (!rtt_result) {
4254*4882a593Smuzhiyun 			ret = -ENOMEM;
4255*4882a593Smuzhiyun 			goto exit;
4256*4882a593Smuzhiyun 		}
4257*4882a593Smuzhiyun 		ret = dhd_rtt_handle_directed_rtt_burst_end(dhd, &event->addr,
4258*4882a593Smuzhiyun 			p_event, tlvs_len, rtt_result, FALSE);
4259*4882a593Smuzhiyun 		if (rtt_result &&
4260*4882a593Smuzhiyun #ifdef WL_CFG80211
4261*4882a593Smuzhiyun 		(ret != BCME_OK) &&
4262*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4263*4882a593Smuzhiyun 		TRUE) {
4264*4882a593Smuzhiyun 			/*
4265*4882a593Smuzhiyun 			 * Free rtt_result irrespectively, for non-cfg,
4266*4882a593Smuzhiyun 			 * as it would not be needed any further
4267*4882a593Smuzhiyun 			 */
4268*4882a593Smuzhiyun 			MFREE(dhd->osh, rtt_result,
4269*4882a593Smuzhiyun 				sizeof(rtt_result_t));
4270*4882a593Smuzhiyun 			goto exit;
4271*4882a593Smuzhiyun 		}
4272*4882a593Smuzhiyun 		break;
4273*4882a593Smuzhiyun 	case WL_PROXD_EVENT_SESSION_END:
4274*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n"));
4275*4882a593Smuzhiyun #ifdef WL_CFG80211
4276*4882a593Smuzhiyun 		if (!RTT_IS_ENABLED(rtt_status)) {
4277*4882a593Smuzhiyun 			DHD_RTT(("Ignore the session end evt\n"));
4278*4882a593Smuzhiyun 			goto exit;
4279*4882a593Smuzhiyun 		}
4280*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4281*4882a593Smuzhiyun 		if (tlvs_len > 0) {
4282*4882a593Smuzhiyun 			/* unpack TLVs and invokes the cbfn to print the event content TLVs */
4283*4882a593Smuzhiyun 			ret = bcm_unpack_xtlv_buf((void *) &session_status,
4284*4882a593Smuzhiyun 				(uint8 *)&p_event->tlvs[0], tlvs_len,
4285*4882a593Smuzhiyun 				BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn);
4286*4882a593Smuzhiyun 			if (ret != BCME_OK) {
4287*4882a593Smuzhiyun 				DHD_RTT_ERR(("%s : Failed to unpack xtlv for an event\n",
4288*4882a593Smuzhiyun 					__FUNCTION__));
4289*4882a593Smuzhiyun 				goto exit;
4290*4882a593Smuzhiyun 			}
4291*4882a593Smuzhiyun 		}
4292*4882a593Smuzhiyun #ifdef WL_CFG80211
4293*4882a593Smuzhiyun 		/* In case of no result for the peer device, make fake result for error case */
4294*4882a593Smuzhiyun 		if (is_new) {
4295*4882a593Smuzhiyun 			dhd_rtt_create_failure_result(rtt_status, &event->addr);
4296*4882a593Smuzhiyun 		}
4297*4882a593Smuzhiyun 		DHD_RTT_MEM(("RTT Session End for Legacy peer "MACDBG"\n",
4298*4882a593Smuzhiyun 			MAC2STRDBG(&event->addr)));
4299*4882a593Smuzhiyun 		dhd_rtt_handle_rtt_session_end(dhd);
4300*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4301*4882a593Smuzhiyun 		break;
4302*4882a593Smuzhiyun 	case WL_PROXD_EVENT_SESSION_RESTART:
4303*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_SESSION_RESTART\n"));
4304*4882a593Smuzhiyun 		break;
4305*4882a593Smuzhiyun 	case WL_PROXD_EVENT_BURST_RESCHED:
4306*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_BURST_RESCHED\n"));
4307*4882a593Smuzhiyun 		break;
4308*4882a593Smuzhiyun 	case WL_PROXD_EVENT_SESSION_DESTROY:
4309*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_SESSION_DESTROY\n"));
4310*4882a593Smuzhiyun 		break;
4311*4882a593Smuzhiyun 	case WL_PROXD_EVENT_FTM_FRAME:
4312*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_FTM_FRAME\n"));
4313*4882a593Smuzhiyun 		break;
4314*4882a593Smuzhiyun 	case WL_PROXD_EVENT_DELAY:
4315*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_DELAY\n"));
4316*4882a593Smuzhiyun 		break;
4317*4882a593Smuzhiyun 	case WL_PROXD_EVENT_VS_INITIATOR_RPT:
4318*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_VS_INITIATOR_RPT\n "));
4319*4882a593Smuzhiyun 		break;
4320*4882a593Smuzhiyun 	case WL_PROXD_EVENT_RANGING:
4321*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_RANGING\n"));
4322*4882a593Smuzhiyun 		break;
4323*4882a593Smuzhiyun 	case WL_PROXD_EVENT_COLLECT:
4324*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_COLLECT\n"));
4325*4882a593Smuzhiyun 		if (tlvs_len > 0) {
4326*4882a593Smuzhiyun 			void *buffer = NULL;
4327*4882a593Smuzhiyun 			if (!(buffer = (void *)MALLOCZ(dhd->osh, tlvs_len))) {
4328*4882a593Smuzhiyun 				ret = -ENOMEM;
4329*4882a593Smuzhiyun 				goto exit;
4330*4882a593Smuzhiyun 			}
4331*4882a593Smuzhiyun 			/* unpack TLVs and invokes the cbfn to print the event content TLVs */
4332*4882a593Smuzhiyun 			ret = bcm_unpack_xtlv_buf(buffer,
4333*4882a593Smuzhiyun 				(uint8 *)&p_event->tlvs[0], tlvs_len,
4334*4882a593Smuzhiyun 				BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn);
4335*4882a593Smuzhiyun 			MFREE(dhd->osh, buffer, tlvs_len);
4336*4882a593Smuzhiyun 			if (ret != BCME_OK) {
4337*4882a593Smuzhiyun 				DHD_RTT_ERR(("%s : Failed to unpack xtlv for event %d\n",
4338*4882a593Smuzhiyun 					__FUNCTION__, event_type));
4339*4882a593Smuzhiyun 				goto exit;
4340*4882a593Smuzhiyun 			}
4341*4882a593Smuzhiyun 		}
4342*4882a593Smuzhiyun 		break;
4343*4882a593Smuzhiyun 	case WL_PROXD_EVENT_MF_STATS:
4344*4882a593Smuzhiyun 		DHD_RTT(("WL_PROXD_EVENT_MF_STATS\n"));
4345*4882a593Smuzhiyun 		if (tlvs_len > 0) {
4346*4882a593Smuzhiyun 			void *buffer = NULL;
4347*4882a593Smuzhiyun 			if (!(buffer = (void *)MALLOCZ(dhd->osh, tlvs_len))) {
4348*4882a593Smuzhiyun 				ret = -ENOMEM;
4349*4882a593Smuzhiyun 				goto exit;
4350*4882a593Smuzhiyun 			}
4351*4882a593Smuzhiyun 			/* unpack TLVs and invokes the cbfn to print the event content TLVs */
4352*4882a593Smuzhiyun 			ret = bcm_unpack_xtlv_buf(buffer,
4353*4882a593Smuzhiyun 				(uint8 *)&p_event->tlvs[0], tlvs_len,
4354*4882a593Smuzhiyun 				BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn);
4355*4882a593Smuzhiyun 			MFREE(dhd->osh, buffer, tlvs_len);
4356*4882a593Smuzhiyun 			if (ret != BCME_OK) {
4357*4882a593Smuzhiyun 				DHD_RTT_ERR(("%s : Failed to unpack xtlv for event %d\n",
4358*4882a593Smuzhiyun 					__FUNCTION__, event_type));
4359*4882a593Smuzhiyun 				goto exit;
4360*4882a593Smuzhiyun 			}
4361*4882a593Smuzhiyun 		}
4362*4882a593Smuzhiyun 		break;
4363*4882a593Smuzhiyun 
4364*4882a593Smuzhiyun 	default:
4365*4882a593Smuzhiyun 		DHD_RTT_ERR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type));
4366*4882a593Smuzhiyun 		break;
4367*4882a593Smuzhiyun 	}
4368*4882a593Smuzhiyun exit:
4369*4882a593Smuzhiyun #ifdef WL_CFG80211
4370*4882a593Smuzhiyun 	mutex_unlock(&rtt_status->rtt_mutex);
4371*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4372*4882a593Smuzhiyun 
4373*4882a593Smuzhiyun 	return ret;
4374*4882a593Smuzhiyun }
4375*4882a593Smuzhiyun 
4376*4882a593Smuzhiyun #ifdef WL_CFG80211
4377*4882a593Smuzhiyun static void
dhd_rtt_work(struct work_struct * work)4378*4882a593Smuzhiyun dhd_rtt_work(struct work_struct *work)
4379*4882a593Smuzhiyun {
4380*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
4381*4882a593Smuzhiyun 	dhd_pub_t *dhd;
4382*4882a593Smuzhiyun 
4383*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4384*4882a593Smuzhiyun 	rtt_status = container_of(work, rtt_status_info_t, work);
4385*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_POP();
4386*4882a593Smuzhiyun 
4387*4882a593Smuzhiyun 	dhd = rtt_status->dhd;
4388*4882a593Smuzhiyun 	if (dhd == NULL) {
4389*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s : dhd is NULL\n", __FUNCTION__));
4390*4882a593Smuzhiyun 		return;
4391*4882a593Smuzhiyun 	}
4392*4882a593Smuzhiyun 	(void) dhd_rtt_start(dhd);
4393*4882a593Smuzhiyun }
4394*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4395*4882a593Smuzhiyun 
4396*4882a593Smuzhiyun int
dhd_rtt_capability(dhd_pub_t * dhd,rtt_capabilities_t * capa)4397*4882a593Smuzhiyun dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa)
4398*4882a593Smuzhiyun {
4399*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
4400*4882a593Smuzhiyun 	int err = BCME_OK;
4401*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
4402*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
4403*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
4404*4882a593Smuzhiyun 	NULL_CHECK(capa, "capa is NULL", err);
4405*4882a593Smuzhiyun 	bzero(capa, sizeof(rtt_capabilities_t));
4406*4882a593Smuzhiyun 
4407*4882a593Smuzhiyun 	/* set rtt capabilities */
4408*4882a593Smuzhiyun 	if (rtt_status->rtt_capa.proto & RTT_CAP_ONE_WAY)
4409*4882a593Smuzhiyun 		capa->rtt_one_sided_supported = 1;
4410*4882a593Smuzhiyun 	if (rtt_status->rtt_capa.proto & RTT_CAP_FTM_WAY)
4411*4882a593Smuzhiyun 		capa->rtt_ftm_supported = 1;
4412*4882a593Smuzhiyun 
4413*4882a593Smuzhiyun 	if (rtt_status->rtt_capa.feature & RTT_FEATURE_LCI)
4414*4882a593Smuzhiyun 		capa->lci_support = 1;
4415*4882a593Smuzhiyun 	if (rtt_status->rtt_capa.feature & RTT_FEATURE_LCR)
4416*4882a593Smuzhiyun 		capa->lcr_support = 1;
4417*4882a593Smuzhiyun 	if (rtt_status->rtt_capa.feature & RTT_FEATURE_PREAMBLE)
4418*4882a593Smuzhiyun 		capa->preamble_support = 1;
4419*4882a593Smuzhiyun 	if (rtt_status->rtt_capa.feature & RTT_FEATURE_BW)
4420*4882a593Smuzhiyun 		capa->bw_support = 1;
4421*4882a593Smuzhiyun 
4422*4882a593Smuzhiyun 	/* bit mask */
4423*4882a593Smuzhiyun 	capa->preamble_support = rtt_status->rtt_capa.preamble;
4424*4882a593Smuzhiyun 	capa->bw_support = rtt_status->rtt_capa.bw;
4425*4882a593Smuzhiyun 
4426*4882a593Smuzhiyun 	return err;
4427*4882a593Smuzhiyun }
4428*4882a593Smuzhiyun 
4429*4882a593Smuzhiyun #ifdef WL_CFG80211
4430*4882a593Smuzhiyun int
dhd_rtt_avail_channel(dhd_pub_t * dhd,wifi_channel_info * channel_info)4431*4882a593Smuzhiyun dhd_rtt_avail_channel(dhd_pub_t *dhd, wifi_channel_info *channel_info)
4432*4882a593Smuzhiyun {
4433*4882a593Smuzhiyun 	u32 chanspec = 0;
4434*4882a593Smuzhiyun 	int err = BCME_OK;
4435*4882a593Smuzhiyun 	chanspec_t c = 0;
4436*4882a593Smuzhiyun 	u32 channel;
4437*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
4438*4882a593Smuzhiyun 
4439*4882a593Smuzhiyun 	if ((err = wldev_iovar_getint(dev, "chanspec",
4440*4882a593Smuzhiyun 		(s32 *)&chanspec)) == BCME_OK) {
4441*4882a593Smuzhiyun 		c = (chanspec_t)dtoh32(chanspec);
4442*4882a593Smuzhiyun 		c = wl_chspec_driver_to_host(c);
4443*4882a593Smuzhiyun 		channel  = wf_chspec_ctlchan(c);
4444*4882a593Smuzhiyun 		DHD_RTT((" control channel is %d \n", channel));
4445*4882a593Smuzhiyun 		if (CHSPEC_IS20(c)) {
4446*4882a593Smuzhiyun 			channel_info->width = WIFI_CHAN_WIDTH_20;
4447*4882a593Smuzhiyun 			DHD_RTT((" band is 20 \n"));
4448*4882a593Smuzhiyun 		} else if (CHSPEC_IS40(c)) {
4449*4882a593Smuzhiyun 			channel_info->width = WIFI_CHAN_WIDTH_40;
4450*4882a593Smuzhiyun 			DHD_RTT(("band is 40 \n"));
4451*4882a593Smuzhiyun 		} else {
4452*4882a593Smuzhiyun 			channel_info->width = WIFI_CHAN_WIDTH_80;
4453*4882a593Smuzhiyun 			DHD_RTT(("band is 80 \n"));
4454*4882a593Smuzhiyun 		}
4455*4882a593Smuzhiyun 		if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
4456*4882a593Smuzhiyun 			(channel <= CH_MAX_2G_CHANNEL)) {
4457*4882a593Smuzhiyun 			channel_info->center_freq =
4458*4882a593Smuzhiyun 				ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
4459*4882a593Smuzhiyun 		} else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
4460*4882a593Smuzhiyun 			channel_info->center_freq =
4461*4882a593Smuzhiyun 				ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
4462*4882a593Smuzhiyun 		}
4463*4882a593Smuzhiyun 		if ((channel_info->width == WIFI_CHAN_WIDTH_80) ||
4464*4882a593Smuzhiyun 			(channel_info->width == WIFI_CHAN_WIDTH_40)) {
4465*4882a593Smuzhiyun 			channel = CHSPEC_CHANNEL(c);
4466*4882a593Smuzhiyun 			channel_info->center_freq0 =
4467*4882a593Smuzhiyun 				ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
4468*4882a593Smuzhiyun 		}
4469*4882a593Smuzhiyun 	} else {
4470*4882a593Smuzhiyun 		DHD_RTT_ERR(("Failed to get the chanspec \n"));
4471*4882a593Smuzhiyun 	}
4472*4882a593Smuzhiyun 	return err;
4473*4882a593Smuzhiyun }
4474*4882a593Smuzhiyun 
4475*4882a593Smuzhiyun int
dhd_rtt_enable_responder(dhd_pub_t * dhd,wifi_channel_info * channel_info)4476*4882a593Smuzhiyun dhd_rtt_enable_responder(dhd_pub_t *dhd, wifi_channel_info *channel_info)
4477*4882a593Smuzhiyun {
4478*4882a593Smuzhiyun 	int err = BCME_OK;
4479*4882a593Smuzhiyun 	char chanbuf[CHANSPEC_STR_LEN];
4480*4882a593Smuzhiyun 	int pm = PM_OFF;
4481*4882a593Smuzhiyun 	int ftm_cfg_cnt = 0;
4482*4882a593Smuzhiyun 	chanspec_t chanspec;
4483*4882a593Smuzhiyun 	wifi_channel_info channel;
4484*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
4485*4882a593Smuzhiyun 	ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS];
4486*4882a593Smuzhiyun 	ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS];
4487*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
4488*4882a593Smuzhiyun 
4489*4882a593Smuzhiyun 	memset(&channel, 0, sizeof(channel));
4490*4882a593Smuzhiyun 	BCM_REFERENCE(chanbuf);
4491*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
4492*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
4493*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
4494*4882a593Smuzhiyun 	if (RTT_IS_STOPPED(rtt_status)) {
4495*4882a593Smuzhiyun 		DHD_RTT(("STA responder/Target. \n"));
4496*4882a593Smuzhiyun 	}
4497*4882a593Smuzhiyun 	DHD_RTT(("Enter %s \n", __FUNCTION__));
4498*4882a593Smuzhiyun 	if (!dhd_is_associated(dhd, 0, NULL)) {
4499*4882a593Smuzhiyun 		if (channel_info) {
4500*4882a593Smuzhiyun 			channel.width = channel_info->width;
4501*4882a593Smuzhiyun 			channel.center_freq = channel_info->center_freq;
4502*4882a593Smuzhiyun 			channel.center_freq0 = channel_info->center_freq;
4503*4882a593Smuzhiyun 		}
4504*4882a593Smuzhiyun 		else {
4505*4882a593Smuzhiyun 			channel.width = WIFI_CHAN_WIDTH_80;
4506*4882a593Smuzhiyun 			channel.center_freq = DEFAULT_FTM_FREQ;
4507*4882a593Smuzhiyun 			channel.center_freq0 = DEFAULT_FTM_CNTR_FREQ0;
4508*4882a593Smuzhiyun 		}
4509*4882a593Smuzhiyun 		chanspec =  dhd_rtt_convert_to_chspec(channel);
4510*4882a593Smuzhiyun 		DHD_RTT(("chanspec/channel set as %s for rtt.\n",
4511*4882a593Smuzhiyun 			wf_chspec_ntoa(chanspec, chanbuf)));
4512*4882a593Smuzhiyun 		err = wldev_iovar_setint(dev, "chanspec", chanspec);
4513*4882a593Smuzhiyun 		if (err) {
4514*4882a593Smuzhiyun 			DHD_RTT_ERR(("Failed to set the chanspec \n"));
4515*4882a593Smuzhiyun 		}
4516*4882a593Smuzhiyun 	}
4517*4882a593Smuzhiyun 	rtt_status->pm = PM_OFF;
4518*4882a593Smuzhiyun 	err = wldev_ioctl_get(dev, WLC_GET_PM, &rtt_status->pm, sizeof(rtt_status->pm));
4519*4882a593Smuzhiyun 	DHD_RTT(("Current PM value read %d\n", rtt_status->pm));
4520*4882a593Smuzhiyun 	if (err) {
4521*4882a593Smuzhiyun 		DHD_RTT_ERR(("Failed to get the PM value \n"));
4522*4882a593Smuzhiyun 	} else {
4523*4882a593Smuzhiyun 		err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
4524*4882a593Smuzhiyun 		if (err) {
4525*4882a593Smuzhiyun 			DHD_RTT_ERR(("Failed to set the PM \n"));
4526*4882a593Smuzhiyun 			rtt_status->pm_restore = FALSE;
4527*4882a593Smuzhiyun 		} else {
4528*4882a593Smuzhiyun 			rtt_status->pm_restore = TRUE;
4529*4882a593Smuzhiyun 		}
4530*4882a593Smuzhiyun 	}
4531*4882a593Smuzhiyun 	if (!RTT_IS_ENABLED(rtt_status)) {
4532*4882a593Smuzhiyun 		err = dhd_rtt_ftm_enable(dhd, TRUE);
4533*4882a593Smuzhiyun 		if (err) {
4534*4882a593Smuzhiyun 			DHD_RTT_ERR(("Failed to enable FTM (%d)\n", err));
4535*4882a593Smuzhiyun 			goto exit;
4536*4882a593Smuzhiyun 		}
4537*4882a593Smuzhiyun 		DHD_RTT(("FTM enabled \n"));
4538*4882a593Smuzhiyun 	}
4539*4882a593Smuzhiyun 	rtt_status->status = RTT_ENABLED;
4540*4882a593Smuzhiyun 	DHD_RTT(("Responder enabled \n"));
4541*4882a593Smuzhiyun 	memset(ftm_configs, 0, sizeof(ftm_configs));
4542*4882a593Smuzhiyun 	memset(ftm_params, 0, sizeof(ftm_params));
4543*4882a593Smuzhiyun 	ftm_configs[ftm_cfg_cnt].enable = TRUE;
4544*4882a593Smuzhiyun 	ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_TARGET;
4545*4882a593Smuzhiyun 	rtt_status->flags = WL_PROXD_SESSION_FLAG_TARGET;
4546*4882a593Smuzhiyun 	DHD_RTT(("Set the device as responder \n"));
4547*4882a593Smuzhiyun 	err = dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS,
4548*4882a593Smuzhiyun 		ftm_configs, ftm_cfg_cnt);
4549*4882a593Smuzhiyun exit:
4550*4882a593Smuzhiyun 	if (err) {
4551*4882a593Smuzhiyun 		rtt_status->status = RTT_STOPPED;
4552*4882a593Smuzhiyun 		DHD_RTT_ERR(("rtt is stopped  %s \n", __FUNCTION__));
4553*4882a593Smuzhiyun 		dhd_rtt_ftm_enable(dhd, FALSE);
4554*4882a593Smuzhiyun 		DHD_RTT(("restoring the PM value \n"));
4555*4882a593Smuzhiyun 		if (rtt_status->pm_restore) {
4556*4882a593Smuzhiyun 			pm = PM_FAST;
4557*4882a593Smuzhiyun 			err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
4558*4882a593Smuzhiyun 			if (err) {
4559*4882a593Smuzhiyun 				DHD_RTT_ERR(("Failed to restore PM \n"));
4560*4882a593Smuzhiyun 			} else {
4561*4882a593Smuzhiyun 				rtt_status->pm_restore = FALSE;
4562*4882a593Smuzhiyun 			}
4563*4882a593Smuzhiyun 		}
4564*4882a593Smuzhiyun 	}
4565*4882a593Smuzhiyun 	return err;
4566*4882a593Smuzhiyun }
4567*4882a593Smuzhiyun 
4568*4882a593Smuzhiyun int
dhd_rtt_cancel_responder(dhd_pub_t * dhd)4569*4882a593Smuzhiyun dhd_rtt_cancel_responder(dhd_pub_t *dhd)
4570*4882a593Smuzhiyun {
4571*4882a593Smuzhiyun 	int err = BCME_OK;
4572*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
4573*4882a593Smuzhiyun 	int pm = 0;
4574*4882a593Smuzhiyun 	struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
4575*4882a593Smuzhiyun 
4576*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
4577*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
4578*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
4579*4882a593Smuzhiyun 	DHD_RTT(("Enter %s \n", __FUNCTION__));
4580*4882a593Smuzhiyun 	err = dhd_rtt_ftm_enable(dhd, FALSE);
4581*4882a593Smuzhiyun 	if (err) {
4582*4882a593Smuzhiyun 		DHD_RTT_ERR(("failed to disable FTM (%d)\n", err));
4583*4882a593Smuzhiyun 	}
4584*4882a593Smuzhiyun 	rtt_status->status = RTT_STOPPED;
4585*4882a593Smuzhiyun 	if (rtt_status->pm_restore) {
4586*4882a593Smuzhiyun 		pm = PM_FAST;
4587*4882a593Smuzhiyun 		DHD_RTT(("pm_restore =%d \n", rtt_status->pm_restore));
4588*4882a593Smuzhiyun 		err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
4589*4882a593Smuzhiyun 		if (err) {
4590*4882a593Smuzhiyun 			DHD_RTT_ERR(("Failed to restore PM \n"));
4591*4882a593Smuzhiyun 		} else {
4592*4882a593Smuzhiyun 			rtt_status->pm_restore = FALSE;
4593*4882a593Smuzhiyun 		}
4594*4882a593Smuzhiyun 	}
4595*4882a593Smuzhiyun 	return err;
4596*4882a593Smuzhiyun }
4597*4882a593Smuzhiyun 
4598*4882a593Smuzhiyun #ifdef WL_NAN
4599*4882a593Smuzhiyun static bool
dhd_rtt_parallel_nan_rtt_sessions_supported(dhd_pub_t * dhd)4600*4882a593Smuzhiyun dhd_rtt_parallel_nan_rtt_sessions_supported(dhd_pub_t *dhd)
4601*4882a593Smuzhiyun {
4602*4882a593Smuzhiyun 	bool supported = FALSE;
4603*4882a593Smuzhiyun 
4604*4882a593Smuzhiyun 	if ((dhd->wlc_ver_major > RTT_PARALLEL_SSNS_SUPPORTED_MAJ_VER) ||
4605*4882a593Smuzhiyun 		((dhd->wlc_ver_major == RTT_PARALLEL_SSNS_SUPPORTED_MAJ_VER) &&
4606*4882a593Smuzhiyun 		(dhd->wlc_ver_minor >= RTT_PARALLEL_SSNS_SUPPORTED_MIN_VER))) {
4607*4882a593Smuzhiyun 		supported = TRUE;
4608*4882a593Smuzhiyun 	}
4609*4882a593Smuzhiyun 
4610*4882a593Smuzhiyun 	return supported;
4611*4882a593Smuzhiyun }
4612*4882a593Smuzhiyun 
4613*4882a593Smuzhiyun int
dhd_rtt_get_max_nan_rtt_sessions_supported(dhd_pub_t * dhd)4614*4882a593Smuzhiyun dhd_rtt_get_max_nan_rtt_sessions_supported(dhd_pub_t *dhd)
4615*4882a593Smuzhiyun {
4616*4882a593Smuzhiyun 	int max_sessions = 0;
4617*4882a593Smuzhiyun 
4618*4882a593Smuzhiyun 	/* Older fw branches does not support parallel rtt sessions */
4619*4882a593Smuzhiyun 	if (dhd_rtt_parallel_nan_rtt_sessions_supported(dhd)) {
4620*4882a593Smuzhiyun 		max_sessions = DHD_NAN_RTT_MAX_SESSIONS;
4621*4882a593Smuzhiyun 	} else {
4622*4882a593Smuzhiyun 		max_sessions = DHD_NAN_RTT_MAX_SESSIONS_LEGACY;
4623*4882a593Smuzhiyun 	}
4624*4882a593Smuzhiyun 
4625*4882a593Smuzhiyun 	return max_sessions;
4626*4882a593Smuzhiyun }
4627*4882a593Smuzhiyun #endif /* WL_NAN */
4628*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4629*4882a593Smuzhiyun 
4630*4882a593Smuzhiyun /*
4631*4882a593Smuzhiyun  * DHD Attach Context
4632*4882a593Smuzhiyun  */
4633*4882a593Smuzhiyun int
dhd_rtt_attach(dhd_pub_t * dhd)4634*4882a593Smuzhiyun dhd_rtt_attach(dhd_pub_t *dhd)
4635*4882a593Smuzhiyun {
4636*4882a593Smuzhiyun 	int err = BCME_OK;
4637*4882a593Smuzhiyun #ifdef WL_CFG80211
4638*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status = NULL;
4639*4882a593Smuzhiyun 
4640*4882a593Smuzhiyun 	dhd->rtt_supported = FALSE;
4641*4882a593Smuzhiyun 	if (dhd->rtt_state) {
4642*4882a593Smuzhiyun 		return err;
4643*4882a593Smuzhiyun 	}
4644*4882a593Smuzhiyun 
4645*4882a593Smuzhiyun 	dhd->rtt_state = (rtt_status_info_t *)MALLOCZ(dhd->osh,
4646*4882a593Smuzhiyun 		sizeof(rtt_status_info_t));
4647*4882a593Smuzhiyun 	if (dhd->rtt_state == NULL) {
4648*4882a593Smuzhiyun 		err = BCME_NOMEM;
4649*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s : failed to create rtt_state\n", __FUNCTION__));
4650*4882a593Smuzhiyun 		return err;
4651*4882a593Smuzhiyun 	}
4652*4882a593Smuzhiyun 	bzero(dhd->rtt_state, sizeof(rtt_status_info_t));
4653*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
4654*4882a593Smuzhiyun 	rtt_status->rtt_config.target_info =
4655*4882a593Smuzhiyun 		(rtt_target_info_t *)MALLOCZ(dhd->osh,
4656*4882a593Smuzhiyun 		TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
4657*4882a593Smuzhiyun 	if (rtt_status->rtt_config.target_info == NULL) {
4658*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s failed to allocate the target info for %d\n",
4659*4882a593Smuzhiyun 			__FUNCTION__, RTT_MAX_TARGET_CNT));
4660*4882a593Smuzhiyun 		err = BCME_NOMEM;
4661*4882a593Smuzhiyun 		goto exit;
4662*4882a593Smuzhiyun 	}
4663*4882a593Smuzhiyun 	rtt_status->dhd = dhd;
4664*4882a593Smuzhiyun 	mutex_init(&rtt_status->rtt_mutex);
4665*4882a593Smuzhiyun 	mutex_init(&rtt_status->geofence_mutex);
4666*4882a593Smuzhiyun 	INIT_LIST_HEAD(&rtt_status->noti_fn_list);
4667*4882a593Smuzhiyun 	INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
4668*4882a593Smuzhiyun 	INIT_WORK(&rtt_status->work, dhd_rtt_work);
4669*4882a593Smuzhiyun 	/* initialize proxd timer */
4670*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&rtt_status->proxd_timeout, dhd_rtt_timeout_work);
4671*4882a593Smuzhiyun #ifdef WL_NAN
4672*4882a593Smuzhiyun 	/* initialize proxd retry timer */
4673*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&rtt_status->rtt_retry_timer, dhd_rtt_retry_work);
4674*4882a593Smuzhiyun #endif /* WL_NAN */
4675*4882a593Smuzhiyun exit:
4676*4882a593Smuzhiyun 	if (err < 0) {
4677*4882a593Smuzhiyun 		MFREE(dhd->osh, rtt_status->rtt_config.target_info,
4678*4882a593Smuzhiyun 			TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
4679*4882a593Smuzhiyun 		MFREE(dhd->osh, dhd->rtt_state, sizeof(rtt_status_info_t));
4680*4882a593Smuzhiyun 	}
4681*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4682*4882a593Smuzhiyun 	return err;
4683*4882a593Smuzhiyun 
4684*4882a593Smuzhiyun }
4685*4882a593Smuzhiyun 
4686*4882a593Smuzhiyun /*
4687*4882a593Smuzhiyun  * DHD Detach Context
4688*4882a593Smuzhiyun  */
4689*4882a593Smuzhiyun int
dhd_rtt_detach(dhd_pub_t * dhd)4690*4882a593Smuzhiyun dhd_rtt_detach(dhd_pub_t *dhd)
4691*4882a593Smuzhiyun {
4692*4882a593Smuzhiyun 	int err = BCME_OK;
4693*4882a593Smuzhiyun 
4694*4882a593Smuzhiyun #ifdef WL_CFG80211
4695*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
4696*4882a593Smuzhiyun 
4697*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
4698*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
4699*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
4700*4882a593Smuzhiyun 
4701*4882a593Smuzhiyun 	err = dhd_rtt_deinit(dhd);
4702*4882a593Smuzhiyun 	if (err != BCME_OK) {
4703*4882a593Smuzhiyun 		DHD_RTT_ERR(("dhd_rtt_deinit failed while detaching"
4704*4882a593Smuzhiyun 			" err = %d\n", err));
4705*4882a593Smuzhiyun 		goto exit;
4706*4882a593Smuzhiyun 	}
4707*4882a593Smuzhiyun 
4708*4882a593Smuzhiyun exit:
4709*4882a593Smuzhiyun 	MFREE(dhd->osh, rtt_status->rtt_config.target_info,
4710*4882a593Smuzhiyun 		TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
4711*4882a593Smuzhiyun 	MFREE(dhd->osh, dhd->rtt_state, sizeof(rtt_status_info_t));
4712*4882a593Smuzhiyun 
4713*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4714*4882a593Smuzhiyun 
4715*4882a593Smuzhiyun 	return err;
4716*4882a593Smuzhiyun }
4717*4882a593Smuzhiyun 
4718*4882a593Smuzhiyun /*
4719*4882a593Smuzhiyun  * If Up context
4720*4882a593Smuzhiyun  */
4721*4882a593Smuzhiyun int
dhd_rtt_init(dhd_pub_t * dhd)4722*4882a593Smuzhiyun dhd_rtt_init(dhd_pub_t *dhd)
4723*4882a593Smuzhiyun {
4724*4882a593Smuzhiyun 	int err = BCME_OK;
4725*4882a593Smuzhiyun #ifdef WL_CFG80211
4726*4882a593Smuzhiyun 	int ret;
4727*4882a593Smuzhiyun 	int32 version;
4728*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
4729*4882a593Smuzhiyun 
4730*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
4731*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
4732*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
4733*4882a593Smuzhiyun 
4734*4882a593Smuzhiyun 	DHD_RTT_MEM(("dhd_rtt_init ENTRY\n"));
4735*4882a593Smuzhiyun 
4736*4882a593Smuzhiyun 	ret = dhd_rtt_get_version(dhd, &version);
4737*4882a593Smuzhiyun 	if (ret == BCME_OK && (version == WL_PROXD_API_VERSION)) {
4738*4882a593Smuzhiyun 		DHD_RTT_ERR(("%s : FTM is supported\n", __FUNCTION__));
4739*4882a593Smuzhiyun 		dhd->rtt_supported = TRUE;
4740*4882a593Smuzhiyun 		/* TODO :  need to find a way to check rtt capability */
4741*4882a593Smuzhiyun 		/* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */
4742*4882a593Smuzhiyun 		rtt_status->rtt_capa.proto |= RTT_CAP_FTM_WAY;
4743*4882a593Smuzhiyun 
4744*4882a593Smuzhiyun 		/* indicate to set tx rate */
4745*4882a593Smuzhiyun 		rtt_status->rtt_capa.feature |= RTT_FEATURE_LCI;
4746*4882a593Smuzhiyun 		rtt_status->rtt_capa.feature |= RTT_FEATURE_LCR;
4747*4882a593Smuzhiyun 		rtt_status->rtt_capa.feature |= RTT_FEATURE_PREAMBLE;
4748*4882a593Smuzhiyun 		rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_VHT;
4749*4882a593Smuzhiyun 		rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_HT;
4750*4882a593Smuzhiyun 
4751*4882a593Smuzhiyun 		/* indicate to set bandwith */
4752*4882a593Smuzhiyun 		rtt_status->rtt_capa.feature |= RTT_FEATURE_BW;
4753*4882a593Smuzhiyun 		rtt_status->rtt_capa.bw |= RTT_BW_20;
4754*4882a593Smuzhiyun 		rtt_status->rtt_capa.bw |= RTT_BW_40;
4755*4882a593Smuzhiyun 		rtt_status->rtt_capa.bw |= RTT_BW_80;
4756*4882a593Smuzhiyun 	} else {
4757*4882a593Smuzhiyun 		if ((ret != BCME_OK) || (version == 0)) {
4758*4882a593Smuzhiyun 			DHD_RTT_ERR(("%s : FTM is not supported\n", __FUNCTION__));
4759*4882a593Smuzhiyun 		} else {
4760*4882a593Smuzhiyun 			DHD_RTT_ERR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n",
4761*4882a593Smuzhiyun 				__FUNCTION__, WL_PROXD_API_VERSION, version));
4762*4882a593Smuzhiyun 		}
4763*4882a593Smuzhiyun 		goto exit;
4764*4882a593Smuzhiyun 	}
4765*4882a593Smuzhiyun 
4766*4882a593Smuzhiyun #ifdef WL_NAN
4767*4882a593Smuzhiyun 	rtt_status->max_nan_rtt_sessions = dhd_rtt_get_max_nan_rtt_sessions_supported(dhd);
4768*4882a593Smuzhiyun #endif /* WL_NAN */
4769*4882a593Smuzhiyun 	/* cancel all of RTT request once we got the cancel request */
4770*4882a593Smuzhiyun 	rtt_status->all_cancel = TRUE;
4771*4882a593Smuzhiyun 
4772*4882a593Smuzhiyun exit:
4773*4882a593Smuzhiyun 	DHD_ERROR(("dhd_rtt_init EXIT, err = %d\n", err));
4774*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4775*4882a593Smuzhiyun 
4776*4882a593Smuzhiyun 	return err;
4777*4882a593Smuzhiyun }
4778*4882a593Smuzhiyun 
4779*4882a593Smuzhiyun /*
4780*4882a593Smuzhiyun  * If Down context
4781*4882a593Smuzhiyun  */
4782*4882a593Smuzhiyun int
dhd_rtt_deinit(dhd_pub_t * dhd)4783*4882a593Smuzhiyun dhd_rtt_deinit(dhd_pub_t *dhd)
4784*4882a593Smuzhiyun {
4785*4882a593Smuzhiyun 	int err = BCME_OK;
4786*4882a593Smuzhiyun #ifdef WL_CFG80211
4787*4882a593Smuzhiyun 	rtt_status_info_t *rtt_status;
4788*4882a593Smuzhiyun 	rtt_results_header_t *rtt_header, *next;
4789*4882a593Smuzhiyun 	rtt_result_t *rtt_result, *next2;
4790*4882a593Smuzhiyun 	struct rtt_noti_callback *iter, *iter2;
4791*4882a593Smuzhiyun 	rtt_target_info_t *rtt_target = NULL;
4792*4882a593Smuzhiyun 
4793*4882a593Smuzhiyun 	NULL_CHECK(dhd, "dhd is NULL", err);
4794*4882a593Smuzhiyun 	rtt_status = GET_RTTSTATE(dhd);
4795*4882a593Smuzhiyun 	NULL_CHECK(rtt_status, "rtt_status is NULL", err);
4796*4882a593Smuzhiyun 
4797*4882a593Smuzhiyun 	DHD_RTT_MEM(("dhd_rtt_deinit: ENTER\n"));
4798*4882a593Smuzhiyun 
4799*4882a593Smuzhiyun #ifdef WL_NAN
4800*4882a593Smuzhiyun 	if (delayed_work_pending(&rtt_status->rtt_retry_timer)) {
4801*4882a593Smuzhiyun 		cancel_delayed_work_sync(&rtt_status->rtt_retry_timer);
4802*4882a593Smuzhiyun 	}
4803*4882a593Smuzhiyun #endif /* WL_NAN */
4804*4882a593Smuzhiyun 
4805*4882a593Smuzhiyun 	if (work_pending(&rtt_status->work)) {
4806*4882a593Smuzhiyun 		cancel_work_sync(&rtt_status->work);
4807*4882a593Smuzhiyun 		rtt_status->rtt_sched = FALSE;
4808*4882a593Smuzhiyun 	}
4809*4882a593Smuzhiyun 
4810*4882a593Smuzhiyun 	if (delayed_work_pending(&rtt_status->proxd_timeout)) {
4811*4882a593Smuzhiyun 		cancel_delayed_work_sync(&rtt_status->proxd_timeout);
4812*4882a593Smuzhiyun 	}
4813*4882a593Smuzhiyun 
4814*4882a593Smuzhiyun 	/*
4815*4882a593Smuzhiyun 	 * Cleanup attempt is required,
4816*4882a593Smuzhiyun 	 * if legacy RTT session is in progress
4817*4882a593Smuzhiyun 	 */
4818*4882a593Smuzhiyun 	if ((!RTT_IS_STOPPED(rtt_status)) &&
4819*4882a593Smuzhiyun 			rtt_status->rtt_config.rtt_target_cnt &&
4820*4882a593Smuzhiyun 			(rtt_status->cur_idx < rtt_status->rtt_config.rtt_target_cnt)) {
4821*4882a593Smuzhiyun 		/* if dhd is started and there is a target cnt */
4822*4882a593Smuzhiyun 		rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
4823*4882a593Smuzhiyun 		if (rtt_target->peer == RTT_PEER_AP) {
4824*4882a593Smuzhiyun 			DHD_RTT_MEM(("dhd_rtt_deinit: Deleting Default FTM Session\n"));
4825*4882a593Smuzhiyun 			dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION);
4826*4882a593Smuzhiyun 		}
4827*4882a593Smuzhiyun 	}
4828*4882a593Smuzhiyun 
4829*4882a593Smuzhiyun 	rtt_status->status = RTT_STOPPED;
4830*4882a593Smuzhiyun 	DHD_RTT(("rtt is stopped %s \n", __FUNCTION__));
4831*4882a593Smuzhiyun 	/* clear evt callback list */
4832*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4833*4882a593Smuzhiyun 	if (!list_empty(&rtt_status->noti_fn_list)) {
4834*4882a593Smuzhiyun 		list_for_each_entry_safe(iter, iter2, &rtt_status->noti_fn_list, list) {
4835*4882a593Smuzhiyun 			list_del(&iter->list);
4836*4882a593Smuzhiyun 			MFREE(dhd->osh, iter, sizeof(struct rtt_noti_callback));
4837*4882a593Smuzhiyun 		}
4838*4882a593Smuzhiyun 	}
4839*4882a593Smuzhiyun 	/* remove the rtt results */
4840*4882a593Smuzhiyun 	if (!list_empty(&rtt_status->rtt_results_cache)) {
4841*4882a593Smuzhiyun 		list_for_each_entry_safe(rtt_header, next, &rtt_status->rtt_results_cache, list) {
4842*4882a593Smuzhiyun 			list_del(&rtt_header->list);
4843*4882a593Smuzhiyun 			list_for_each_entry_safe(rtt_result, next2,
4844*4882a593Smuzhiyun 					&rtt_header->result_list, list) {
4845*4882a593Smuzhiyun 				list_del(&rtt_result->list);
4846*4882a593Smuzhiyun 				MFREE(dhd->osh, rtt_result, sizeof(rtt_result_t));
4847*4882a593Smuzhiyun 			}
4848*4882a593Smuzhiyun 			MFREE(dhd->osh, rtt_header, sizeof(rtt_results_header_t));
4849*4882a593Smuzhiyun 		}
4850*4882a593Smuzhiyun 	}
4851*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_POP();
4852*4882a593Smuzhiyun 	DHD_RTT_MEM(("dhd_rtt_deinit: EXIT, err = %d\n", err));
4853*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4854*4882a593Smuzhiyun 	return err;
4855*4882a593Smuzhiyun }
4856