• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&noti_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(&noti_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(&noti_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(&noti_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