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