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