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