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