• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Broadcom Dongle Host Driver (DHD), RTT
3  *
4  * Copyright (C) 1999-2017, Broadcom Corporation
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *      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 
44 #include <bcmevent.h>
45 #include <dhd.h>
46 #include <dhd_rtt.h>
47 #include <dhd_dbg.h>
48 #include <wldev_common.h>
49 #ifdef WL_CFG80211
50 #include <wl_cfg80211.h>
51 #endif /* WL_CFG80211 */
52 static DEFINE_SPINLOCK(noti_list_lock);
53 #define NULL_CHECK(p, s, err)  \
54             do { \
55                 if (!(p)) { \
56                     printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \
57                     err = BCME_ERROR; \
58                     return err; \
59                 } \
60             } while (0)
61 
62 #define RTT_IS_ENABLED(rtt_status) (rtt_status->status == RTT_ENABLED)
63 #define RTT_IS_STOPPED(rtt_status) (rtt_status->status == RTT_STOPPED)
64 #define TIMESPEC_TO_US(ts)  (((uint64)(ts).tv_sec * USEC_PER_SEC) + \
65                             (ts).tv_nsec / NSEC_PER_USEC)
66 
67 #define FTM_IOC_BUFSZ  2048    /* ioc buffsize for our module (> BCM_XTLV_HDR_SIZE) */
68 #define FTM_AVAIL_MAX_SLOTS        32
69 #define FTM_MAX_CONFIGS 10
70 #define FTM_MAX_PARAMS 10
71 #define FTM_DEFAULT_SESSION 1
72 #define FTM_BURST_TIMEOUT_UNIT 250 /* 250 ns */
73 #define FTM_INVALID -1
74 #define    FTM_DEFAULT_CNT_20M        12
75 #define FTM_DEFAULT_CNT_40M        10
76 #define FTM_DEFAULT_CNT_80M        5
77 
78 /* convenience macros */
79 #define FTM_TU2MICRO(_tu) ((uint64)(_tu) << 10)
80 #define FTM_MICRO2TU(_tu) ((uint64)(_tu) >> 10)
81 #define FTM_TU2MILLI(_tu) ((uint32)FTM_TU2MICRO(_tu) / 1000)
82 #define FTM_MICRO2MILLI(_x) ((uint32)(_x) / 1000)
83 #define FTM_MICRO2SEC(_x) ((uint32)(_x) / 1000000)
84 #define FTM_INTVL2NSEC(_intvl) ((uint32)ftm_intvl2nsec(_intvl))
85 #define FTM_INTVL2USEC(_intvl) ((uint32)ftm_intvl2usec(_intvl))
86 #define FTM_INTVL2MSEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000)
87 #define FTM_INTVL2SEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000000)
88 #define FTM_USECIN100MILLI(_usec) ((_usec) / 100000)
89 
90 /* broadcom specific set to have more accurate data */
91 #define ENABLE_VHT_ACK
92 #define CH_MIN_5G_CHANNEL 34
93 #define CH_MIN_2G_CHANNEL 1
94 
95 struct rtt_noti_callback {
96     struct list_head list;
97     void *ctx;
98     dhd_rtt_compl_noti_fn noti_fn;
99 };
100 
101 
102 /* bitmask indicating which command groups; */
103 typedef enum {
104     FTM_SUBCMD_FLAG_METHOD    = 0x01,    /* FTM method command */
105     FTM_SUBCMD_FLAG_SESSION = 0x02,    /* FTM session command */
106     FTM_SUBCMD_FLAG_ALL = FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION
107 } ftm_subcmd_flag_t;
108 
109 /* proxd ftm config-category definition */
110 typedef enum {
111     FTM_CONFIG_CAT_GENERAL = 1,    /* generial configuration */
112     FTM_CONFIG_CAT_OPTIONS = 2,    /* 'config options' */
113     FTM_CONFIG_CAT_AVAIL = 3,    /* 'config avail' */
114 } ftm_config_category_t;
115 
116 
117 typedef struct ftm_subcmd_info {
118     int16                version;    /* FTM version (optional) */
119     char                *name;        /* cmd-name string as cmdline input */
120     wl_proxd_cmd_t        cmdid;        /* cmd-id */
121     bcm_xtlv_unpack_cbfn_t *handler;  /* cmd response handler (optional) */
122     ftm_subcmd_flag_t    cmdflag; /* CMD flag (optional)  */
123 } ftm_subcmd_info_t;
124 
125 
126 typedef struct ftm_config_options_info {
127     uint32 flags;                /* wl_proxd_flags_t/wl_proxd_session_flags_t */
128     bool enable;
129 } ftm_config_options_info_t;
130 
131 typedef struct ftm_config_param_info {
132     uint16        tlvid;    /* mapping TLV id for the item */
133     union {
134         uint32  chanspec;
135         struct ether_addr mac_addr;
136         wl_proxd_intvl_t data_intvl;
137         uint32 data32;
138         uint16 data16;
139         uint8 data8;
140     };
141 } ftm_config_param_info_t;
142 
143 /*
144 * definition for id-string mapping.
145 *   This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string
146 *   for debug-display or cmd-log-display
147 */
148 typedef struct ftm_strmap_entry {
149     int32        id;
150     char        *text;
151 } ftm_strmap_entry_t;
152 
153 
154 typedef struct ftm_status_map_host_entry {
155     wl_proxd_status_t proxd_status;
156     rtt_reason_t rtt_reason;
157 } ftm_status_map_host_entry_t;
158 
159 static int
160 dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len);
161 
162 static wifi_rate_t
163 dhd_rtt_convert_rate_to_host(uint32 ratespec);
164 
165 #ifdef WL_CFG80211
166 static int
167 dhd_rtt_start(dhd_pub_t *dhd);
168 #endif /* WL_CFG80211 */
169 static const int burst_duration_idx[]  = {0, 0, 1, 2, 4, 8, 16, 32, 64, 128, 0, 0};
170 
171 /* ftm status mapping to host status */
172 static const ftm_status_map_host_entry_t ftm_status_map_info[] = {
173     {WL_PROXD_E_INCOMPLETE, RTT_REASON_FAILURE},
174     {WL_PROXD_E_OVERRIDDEN, RTT_REASON_FAILURE},
175     {WL_PROXD_E_ASAP_FAILED, RTT_REASON_FAILURE},
176     {WL_PROXD_E_NOTSTARTED, RTT_REASON_FAIL_NOT_SCHEDULED_YET},
177     {WL_PROXD_E_INVALIDMEAS, RTT_REASON_FAIL_INVALID_TS},
178     {WL_PROXD_E_INCAPABLE, RTT_REASON_FAIL_NO_CAPABILITY},
179     {WL_PROXD_E_MISMATCH, RTT_REASON_FAILURE},
180     {WL_PROXD_E_DUP_SESSION, RTT_REASON_FAILURE},
181     {WL_PROXD_E_REMOTE_FAIL, RTT_REASON_FAILURE},
182     {WL_PROXD_E_REMOTE_INCAPABLE, RTT_REASON_FAILURE},
183     {WL_PROXD_E_SCHED_FAIL, RTT_REASON_FAIL_SCHEDULE},
184     {WL_PROXD_E_PROTO, RTT_REASON_FAIL_PROTOCOL},
185     {WL_PROXD_E_EXPIRED, RTT_REASON_FAILURE},
186     {WL_PROXD_E_TIMEOUT, RTT_REASON_FAIL_TM_TIMEOUT},
187     {WL_PROXD_E_NOACK, RTT_REASON_FAIL_NO_RSP},
188     {WL_PROXD_E_DEFERRED, RTT_REASON_FAILURE},
189     {WL_PROXD_E_INVALID_SID, RTT_REASON_FAILURE},
190     {WL_PROXD_E_REMOTE_CANCEL, RTT_REASON_FAILURE},
191     {WL_PROXD_E_CANCELED, RTT_REASON_ABORTED},
192     {WL_PROXD_E_INVALID_SESSION, RTT_REASON_FAILURE},
193     {WL_PROXD_E_BAD_STATE, RTT_REASON_FAILURE},
194     {WL_PROXD_E_ERROR, RTT_REASON_FAILURE},
195     {WL_PROXD_E_OK, RTT_REASON_SUCCESS}
196 };
197 
198 /* ftm tlv-id mapping */
199 #if 0
200 static const ftm_strmap_entry_t ftm_tlvid_loginfo[] = {
201     /* { WL_PROXD_TLV_ID_xxx,                "text for WL_PROXD_TLV_ID_xxx" }, */
202     { WL_PROXD_TLV_ID_NONE,                "none" },
203     { WL_PROXD_TLV_ID_METHOD,            "method" },
204     { WL_PROXD_TLV_ID_FLAGS,            "flags" },
205     { WL_PROXD_TLV_ID_CHANSPEC,            "chanspec" },
206     { WL_PROXD_TLV_ID_TX_POWER,            "tx power" },
207     { WL_PROXD_TLV_ID_RATESPEC,            "ratespec" },
208     { WL_PROXD_TLV_ID_BURST_DURATION,        "burst duration" },
209     { WL_PROXD_TLV_ID_BURST_PERIOD,            "burst period" },
210     { WL_PROXD_TLV_ID_BURST_FTM_SEP,        "burst ftm sep" },
211     { WL_PROXD_TLV_ID_BURST_NUM_FTM,        "burst num ftm" },
212     { WL_PROXD_TLV_ID_NUM_BURST,            "num burst" },
213     { WL_PROXD_TLV_ID_FTM_RETRIES,            "ftm retries" },
214     { WL_PROXD_TLV_ID_BSS_INDEX,            "BSS index" },
215     { WL_PROXD_TLV_ID_BSSID,            "bssid" },
216     { WL_PROXD_TLV_ID_INIT_DELAY,            "burst init delay" },
217     { WL_PROXD_TLV_ID_BURST_TIMEOUT,        "burst timeout" },
218     { WL_PROXD_TLV_ID_EVENT_MASK,            "event mask" },
219     { WL_PROXD_TLV_ID_FLAGS_MASK,            "flags mask" },
220     { WL_PROXD_TLV_ID_PEER_MAC,            "peer addr" },
221     { WL_PROXD_TLV_ID_FTM_REQ,            "ftm req" },
222     { WL_PROXD_TLV_ID_LCI_REQ,            "lci req" },
223     { WL_PROXD_TLV_ID_LCI,                "lci" },
224     { WL_PROXD_TLV_ID_CIVIC_REQ,            "civic req" },
225     { WL_PROXD_TLV_ID_CIVIC,            "civic" },
226     { WL_PROXD_TLV_ID_AVAIL,            "availability" },
227     { WL_PROXD_TLV_ID_SESSION_FLAGS,        "session flags" },
228     { WL_PROXD_TLV_ID_SESSION_FLAGS_MASK,        "session flags mask" },
229     { WL_PROXD_TLV_ID_RX_MAX_BURST,            "rx max bursts" },
230     { WL_PROXD_TLV_ID_RANGING_INFO,            "ranging info" },
231     { WL_PROXD_TLV_ID_RANGING_FLAGS,        "ranging flags" },
232     { WL_PROXD_TLV_ID_RANGING_FLAGS_MASK,        "ranging flags mask" },
233     /* output - 512 + x */
234     { WL_PROXD_TLV_ID_STATUS,            "status" },
235     { WL_PROXD_TLV_ID_COUNTERS,            "counters" },
236     { WL_PROXD_TLV_ID_INFO,                "info" },
237     { WL_PROXD_TLV_ID_RTT_RESULT,            "rtt result" },
238     { WL_PROXD_TLV_ID_AOA_RESULT,            "aoa result" },
239     { WL_PROXD_TLV_ID_SESSION_INFO,            "session info" },
240     { WL_PROXD_TLV_ID_SESSION_STATUS,        "session status" },
241     { WL_PROXD_TLV_ID_SESSION_ID_LIST,        "session ids" },
242     /* debug tlvs can be added starting 1024 */
243     { WL_PROXD_TLV_ID_DEBUG_MASK,            "debug mask" },
244     { WL_PROXD_TLV_ID_COLLECT,            "collect" },
245     { WL_PROXD_TLV_ID_STRBUF,            "result" },
246     { WL_PROXD_TLV_ID_COLLECT_DATA,            "collect-data" },
247     { WL_PROXD_TLV_ID_RI_RR,            "ri_rr" },
248     { WL_PROXD_TLV_ID_COLLECT_CHAN_DATA,        "chan est"}
249 };
250 #endif
251 
252 static const ftm_strmap_entry_t ftm_event_type_loginfo[] = {
253     /* wl_proxd_event_type_t,            text-string */
254     { WL_PROXD_EVENT_NONE,                "none" },
255     { WL_PROXD_EVENT_SESSION_CREATE,        "session create" },
256     { WL_PROXD_EVENT_SESSION_START,            "session start" },
257     { WL_PROXD_EVENT_FTM_REQ,            "FTM req" },
258     { WL_PROXD_EVENT_BURST_START,            "burst start" },
259     { WL_PROXD_EVENT_BURST_END,            "burst end" },
260     { WL_PROXD_EVENT_SESSION_END,            "session end" },
261     { WL_PROXD_EVENT_SESSION_RESTART,        "session restart" },
262     { WL_PROXD_EVENT_BURST_RESCHED,            "burst rescheduled" },
263     { WL_PROXD_EVENT_SESSION_DESTROY,        "session destroy" },
264     { WL_PROXD_EVENT_RANGE_REQ,            "range request" },
265     { WL_PROXD_EVENT_FTM_FRAME,            "FTM frame" },
266     { WL_PROXD_EVENT_DELAY,                "delay" },
267     { WL_PROXD_EVENT_VS_INITIATOR_RPT,        "initiator-report " }, /* rx */
268     { WL_PROXD_EVENT_RANGING,            "ranging " },
269     { WL_PROXD_EVENT_COLLECT,            "collect" },
270 };
271 
272 /*
273 * session-state --> text string mapping
274 */
275 static const ftm_strmap_entry_t ftm_session_state_value_loginfo[] = {
276     /* wl_proxd_session_state_t,            text string */
277     { WL_PROXD_SESSION_STATE_CREATED,        "created" },
278     { WL_PROXD_SESSION_STATE_CONFIGURED,        "configured" },
279     { WL_PROXD_SESSION_STATE_STARTED,        "started" },
280     { WL_PROXD_SESSION_STATE_DELAY,            "delay" },
281     { WL_PROXD_SESSION_STATE_USER_WAIT,        "user-wait" },
282     { WL_PROXD_SESSION_STATE_SCHED_WAIT,        "sched-wait" },
283     { WL_PROXD_SESSION_STATE_BURST,            "burst" },
284     { WL_PROXD_SESSION_STATE_STOPPING,        "stopping" },
285     { WL_PROXD_SESSION_STATE_ENDED,            "ended" },
286     { WL_PROXD_SESSION_STATE_DESTROYING,        "destroying" },
287     { WL_PROXD_SESSION_STATE_NONE,            "none" }
288 };
289 
290 /*
291 * ranging-state --> text string mapping
292 */
293 #if 0
294 static const ftm_strmap_entry_t ftm_ranging_state_value_loginfo [] = {
295     /* wl_proxd_ranging_state_t,            text string */
296     { WL_PROXD_RANGING_STATE_NONE,            "none" },
297     { WL_PROXD_RANGING_STATE_NOTSTARTED,        "nonstarted" },
298     { WL_PROXD_RANGING_STATE_INPROGRESS,        "inprogress" },
299     { WL_PROXD_RANGING_STATE_DONE,            "done" },
300 };
301 #endif
302 
303 /*
304 * status --> text string mapping
305 */
306 static const ftm_strmap_entry_t ftm_status_value_loginfo[] = {
307     /* wl_proxd_status_t,            text-string */
308     { WL_PROXD_E_OVERRIDDEN,        "overridden" },
309     { WL_PROXD_E_ASAP_FAILED,        "ASAP failed" },
310     { WL_PROXD_E_NOTSTARTED,        "not started" },
311     { WL_PROXD_E_INVALIDMEAS,        "invalid measurement" },
312     { WL_PROXD_E_INCAPABLE,            "incapable" },
313     { WL_PROXD_E_MISMATCH,            "mismatch"},
314     { WL_PROXD_E_DUP_SESSION,        "dup session" },
315     { WL_PROXD_E_REMOTE_FAIL,        "remote fail" },
316     { WL_PROXD_E_REMOTE_INCAPABLE,        "remote incapable" },
317     { WL_PROXD_E_SCHED_FAIL,        "sched failure" },
318     { WL_PROXD_E_PROTO,            "protocol error" },
319     { WL_PROXD_E_EXPIRED,            "expired" },
320     { WL_PROXD_E_TIMEOUT,            "timeout" },
321     { WL_PROXD_E_NOACK,            "no ack" },
322     { WL_PROXD_E_DEFERRED,            "deferred" },
323     { WL_PROXD_E_INVALID_SID,        "invalid session id" },
324     { WL_PROXD_E_REMOTE_CANCEL,        "remote cancel" },
325     { WL_PROXD_E_CANCELED,            "canceled" },
326     { WL_PROXD_E_INVALID_SESSION,        "invalid session" },
327     { WL_PROXD_E_BAD_STATE,            "bad state" },
328     { WL_PROXD_E_ERROR,            "error" },
329     { WL_PROXD_E_OK,            "OK" }
330 };
331 
332 /*
333 * time interval unit --> text string mapping
334 */
335 static const ftm_strmap_entry_t ftm_tmu_value_loginfo[] = {
336     /* wl_proxd_tmu_t,            text-string */
337     { WL_PROXD_TMU_TU,            "TU" },
338     { WL_PROXD_TMU_SEC,            "sec" },
339     { WL_PROXD_TMU_MILLI_SEC,        "ms" },
340     { WL_PROXD_TMU_MICRO_SEC,        "us" },
341     { WL_PROXD_TMU_NANO_SEC,        "ns" },
342     { WL_PROXD_TMU_PICO_SEC,        "ps" }
343 };
344 
345 #define RSPEC_BW(rspec)         ((rspec) & WL_RSPEC_BW_MASK)
346 #define RSPEC_IS20MHZ(rspec)    (RSPEC_BW(rspec) == WL_RSPEC_BW_20MHZ)
347 #define RSPEC_IS40MHZ(rspec)    (RSPEC_BW(rspec) == WL_RSPEC_BW_40MHZ)
348 #define RSPEC_IS80MHZ(rspec)    (RSPEC_BW(rspec) == WL_RSPEC_BW_80MHZ)
349 #define RSPEC_IS160MHZ(rspec)   (RSPEC_BW(rspec) == WL_RSPEC_BW_160MHZ)
350 
351 #define IS_MCS(rspec)         (((rspec) & WL_RSPEC_ENCODING_MASK) != WL_RSPEC_ENCODE_RATE)
352 #define IS_STBC(rspec)         (((((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) ||    \
353     (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)) &&    \
354     (((rspec) & WL_RSPEC_STBC) == WL_RSPEC_STBC))
355 #define RSPEC_ISSGI(rspec)      (((rspec) & WL_RSPEC_SGI) != 0)
356 #define RSPEC_ISLDPC(rspec)     (((rspec) & WL_RSPEC_LDPC) != 0)
357 #define RSPEC_ISSTBC(rspec)     (((rspec) & WL_RSPEC_STBC) != 0)
358 #define RSPEC_ISTXBF(rspec)     (((rspec) & WL_RSPEC_TXBF) != 0)
359 #define RSPEC_ISVHT(rspec)        (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)
360 #define RSPEC_ISHT(rspec)    (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT)
361 #define RSPEC_ISLEGACY(rspec)   (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE)
362 #define RSPEC2RATE(rspec)    (RSPEC_ISLEGACY(rspec) ? \
363                  ((rspec) & RSPEC_RATE_MASK) : rate_rspec2rate(rspec))
364 /* return rate in unit of 500Kbps -- for internal use in wlc_rate_sel.c */
365 #define RSPEC2KBPS(rspec)    rate_rspec2rate(rspec)
366 
367 struct ieee_80211_mcs_rate_info {
368     uint8 constellation_bits;
369     uint8 coding_q;
370     uint8 coding_d;
371 };
372 
373 static const struct ieee_80211_mcs_rate_info wl_mcs_info[] = {
374     { 1, 1, 2 }, /* MCS  0: MOD: BPSK,   CR 1/2 */
375     { 2, 1, 2 }, /* MCS  1: MOD: QPSK,   CR 1/2 */
376     { 2, 3, 4 }, /* MCS  2: MOD: QPSK,   CR 3/4 */
377     { 4, 1, 2 }, /* MCS  3: MOD: 16QAM,  CR 1/2 */
378     { 4, 3, 4 }, /* MCS  4: MOD: 16QAM,  CR 3/4 */
379     { 6, 2, 3 }, /* MCS  5: MOD: 64QAM,  CR 2/3 */
380     { 6, 3, 4 }, /* MCS  6: MOD: 64QAM,  CR 3/4 */
381     { 6, 5, 6 }, /* MCS  7: MOD: 64QAM,  CR 5/6 */
382     { 8, 3, 4 }, /* MCS  8: MOD: 256QAM, CR 3/4 */
383     { 8, 5, 6 }  /* MCS  9: MOD: 256QAM, CR 5/6 */
384 };
385 
386 /**
387  * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination.
388  *     'mcs' : a *single* spatial stream MCS (11n or 11ac)
389  */
390 uint
rate_mcs2rate(uint mcs,uint nss,uint bw,int sgi)391 rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi)
392 {
393     const int ksps = 250; /* kilo symbols per sec, 4 us sym */
394     const int Nsd_20MHz = 52;
395     const int Nsd_40MHz = 108;
396     const int Nsd_80MHz = 234;
397     const int Nsd_160MHz = 468;
398     uint rate;
399 
400     if (mcs == 32) {
401         /* just return fixed values for mcs32 instead of trying to parametrize */
402         rate = (sgi == 0) ? 6000 : 6778;
403     } else if (mcs <= 9) {
404         /* This calculation works for 11n HT and 11ac VHT if the HT mcs values
405          * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8.
406          * That is, HT MCS 23 is a base MCS = 7, Nss = 3
407          */
408 
409         /* find the number of complex numbers per symbol */
410         if (RSPEC_IS20MHZ(bw)) {
411             rate = Nsd_20MHz;
412         } else if (RSPEC_IS40MHZ(bw)) {
413             rate = Nsd_40MHz;
414         } else if (bw == WL_RSPEC_BW_80MHZ) {
415             rate = Nsd_80MHz;
416         } else if (bw == WL_RSPEC_BW_160MHZ) {
417             rate = Nsd_160MHz;
418         } else {
419             rate = 0;
420         }
421 
422         /* multiply by bits per number from the constellation in use */
423         rate = rate * wl_mcs_info[mcs].constellation_bits;
424 
425         /* adjust for the number of spatial streams */
426         rate = rate * nss;
427 
428         /* adjust for the coding rate given as a quotient and divisor */
429         rate = (rate * wl_mcs_info[mcs].coding_q) / wl_mcs_info[mcs].coding_d;
430 
431         /* multiply by Kilo symbols per sec to get Kbps */
432         rate = rate * ksps;
433 
434         /* adjust the symbols per sec for SGI
435          * symbol duration is 4 us without SGI, and 3.6 us with SGI,
436          * so ratio is 10 / 9
437          */
438         if (sgi) {
439             /* add 4 for rounding of division by 9 */
440             rate = ((rate * 10) + 4) / 9;
441         }
442     } else {
443         rate = 0;
444     }
445 
446     return rate;
447 } /* wlc_rate_mcs2rate */
448 
449 /** take a well formed ratespec_t arg and return phy rate in [Kbps] units */
450 int
rate_rspec2rate(uint32 rspec)451 rate_rspec2rate(uint32 rspec)
452 {
453     int rate = -1;
454 
455     if (RSPEC_ISLEGACY(rspec)) {
456         rate = 500 * (rspec & WL_RSPEC_RATE_MASK);
457     } else if (RSPEC_ISHT(rspec)) {
458         uint mcs = (rspec & WL_RSPEC_RATE_MASK);
459 
460         if (mcs == 32) {
461             rate = rate_mcs2rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec));
462         } else {
463             uint nss = 1 + (mcs / 8);
464             mcs = mcs % 8;
465             rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec));
466         }
467     } else if (RSPEC_ISVHT(rspec)) {
468         uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK);
469         uint nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
470 
471         ASSERT(mcs <= 9);
472         ASSERT(nss <= 8);
473 
474         rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec));
475     } else {
476         ASSERT(0);
477     }
478 
479     return (rate == 0) ? -1 : rate;
480 }
481 
482 char resp_buf[WLC_IOCTL_SMLEN];
483 
484 static uint64
ftm_intvl2nsec(const wl_proxd_intvl_t * intvl)485 ftm_intvl2nsec(const wl_proxd_intvl_t *intvl)
486 {
487     uint64 ret;
488     ret = intvl->intvl;
489     switch (intvl->tmu) {
490     case WL_PROXD_TMU_TU:            ret = FTM_TU2MICRO(ret) * 1000; break;
491     case WL_PROXD_TMU_SEC:            ret *= 1000000000; break;
492     case WL_PROXD_TMU_MILLI_SEC:    ret *= 1000000; break;
493     case WL_PROXD_TMU_MICRO_SEC:    ret *= 1000; break;
494     case WL_PROXD_TMU_PICO_SEC:        ret = intvl->intvl / 1000; break;
495     case WL_PROXD_TMU_NANO_SEC:        /* fall through */
496     default:                        break;
497     }
498     return ret;
499 }
500 uint64
ftm_intvl2usec(const wl_proxd_intvl_t * intvl)501 ftm_intvl2usec(const wl_proxd_intvl_t *intvl)
502 {
503     uint64 ret;
504     ret = intvl->intvl;
505     switch (intvl->tmu) {
506     case WL_PROXD_TMU_TU:            ret = FTM_TU2MICRO(ret); break;
507     case WL_PROXD_TMU_SEC:            ret *= 1000000; break;
508     case WL_PROXD_TMU_NANO_SEC:        ret = intvl->intvl / 1000; break;
509     case WL_PROXD_TMU_PICO_SEC:        ret = intvl->intvl / 1000000; break;
510     case WL_PROXD_TMU_MILLI_SEC:    ret *= 1000; break;
511     case WL_PROXD_TMU_MICRO_SEC:    /* fall through */
512     default:                        break;
513     }
514     return ret;
515 }
516 
517 /*
518 * lookup 'id' (as a key) from a fw status to host map table
519 * if found, return the corresponding reason code
520 */
521 
522 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)523 ftm_get_statusmap_info(wl_proxd_status_t id, const ftm_status_map_host_entry_t *p_table,
524     uint32 num_entries)
525 {
526     int i;
527     const ftm_status_map_host_entry_t *p_entry;
528     /* scan thru the table till end */
529     p_entry = p_table;
530     for (i = 0; i < (int) num_entries; i++)
531     {
532         if (p_entry->proxd_status == id) {
533             return p_entry->rtt_reason;
534         }
535         p_entry++;        /* next entry */
536     }
537     return RTT_REASON_FAILURE; /* not found */
538 }
539 /*
540 * lookup 'id' (as a key) from a table
541 * if found, return the entry pointer, otherwise return NULL
542 */
543 static const ftm_strmap_entry_t*
ftm_get_strmap_info(int32 id,const ftm_strmap_entry_t * p_table,uint32 num_entries)544 ftm_get_strmap_info(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries)
545 {
546     int i;
547     const ftm_strmap_entry_t *p_entry;
548 
549     /* scan thru the table till end */
550     p_entry = p_table;
551     for (i = 0; i < (int) num_entries; i++)
552     {
553         if (p_entry->id == id)
554             return p_entry;
555         p_entry++;        /* next entry */
556     }
557     return NULL;            /* not found */
558 }
559 
560 /*
561 * map enum to a text-string for display, this function is called by the following:
562 * For debug/trace:
563 *     ftm_[cmdid|tlvid]_to_str()
564 * For TLV-output log for 'get' commands
565 *     ftm_[method|tmu|caps|status|state]_value_to_logstr()
566 * Input:
567 *     pTable -- point to a 'enum to string' table.
568 */
569 static const char *
ftm_map_id_to_str(int32 id,const ftm_strmap_entry_t * p_table,uint32 num_entries)570 ftm_map_id_to_str(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries)
571 {
572     const ftm_strmap_entry_t*p_entry = ftm_get_strmap_info(id, p_table, num_entries);
573     if (p_entry)
574         return (p_entry->text);
575 
576     return "invalid";
577 }
578 
579 
580 #ifdef RTT_DEBUG
581 
582 /* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */
583 #define DEF_STRMAP_ENTRY(id) { (id), #id }
584 
585 /* ftm cmd-id mapping */
586 static const ftm_strmap_entry_t ftm_cmdid_map[] = {
587     DEF_STRMAP_ENTRY(WL_PROXD_CMD_NONE),
588     DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_VERSION),
589     DEF_STRMAP_ENTRY(WL_PROXD_CMD_ENABLE),
590     DEF_STRMAP_ENTRY(WL_PROXD_CMD_DISABLE),
591     DEF_STRMAP_ENTRY(WL_PROXD_CMD_CONFIG),
592     DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_SESSION),
593     DEF_STRMAP_ENTRY(WL_PROXD_CMD_BURST_REQUEST),
594     DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_SESSION),
595     DEF_STRMAP_ENTRY(WL_PROXD_CMD_DELETE_SESSION),
596     DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RESULT),
597     DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_INFO),
598     DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_STATUS),
599     DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_SESSIONS),
600     DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_COUNTERS),
601     DEF_STRMAP_ENTRY(WL_PROXD_CMD_CLEAR_COUNTERS),
602     DEF_STRMAP_ENTRY(WL_PROXD_CMD_COLLECT),
603     DEF_STRMAP_ENTRY(WL_PROXD_CMD_TUNE),
604     DEF_STRMAP_ENTRY(WL_PROXD_CMD_DUMP),
605     DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_RANGING),
606     DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_RANGING),
607     DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RANGING_INFO),
608 };
609 
610 /*
611 * map a ftm cmd-id to a text-string for display
612 */
613 static const char *
ftm_cmdid_to_str(uint16 cmdid)614 ftm_cmdid_to_str(uint16 cmdid)
615 {
616     return ftm_map_id_to_str((int32) cmdid, &ftm_cmdid_map[0], ARRAYSIZE(ftm_cmdid_map));
617 }
618 #endif /* RTT_DEBUG */
619 
620 
621 /*
622 * convert BCME_xxx error codes into related error strings
623 * note, bcmerrorstr() defined in bcmutils is for BCMDRIVER only,
624 *       this duplicate copy is for WL access and may need to clean up later
625 */
626 static const char *ftm_bcmerrorstrtable[] = BCMERRSTRINGTABLE;
627 static const char *
ftm_status_value_to_logstr(wl_proxd_status_t status)628 ftm_status_value_to_logstr(wl_proxd_status_t status)
629 {
630     static char ftm_msgbuf_status_undef[32];
631     const ftm_strmap_entry_t *p_loginfo;
632     int bcmerror;
633 
634     /* check if within BCME_xxx error range */
635     bcmerror = (int) status;
636     if (VALID_BCMERROR(bcmerror))
637         return ftm_bcmerrorstrtable[-bcmerror];
638 
639     /* otherwise, look for 'proxd ftm status' range */
640     p_loginfo = ftm_get_strmap_info((int32) status,
641         &ftm_status_value_loginfo[0], ARRAYSIZE(ftm_status_value_loginfo));
642     if (p_loginfo)
643         return p_loginfo->text;
644 
645     /* report for 'out of range' FTM-status error code */
646     memset(ftm_msgbuf_status_undef, 0, sizeof(ftm_msgbuf_status_undef));
647     snprintf(ftm_msgbuf_status_undef, sizeof(ftm_msgbuf_status_undef),
648         "Undefined status %d", status);
649     return &ftm_msgbuf_status_undef[0];
650 }
651 
652 static const char *
ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu)653 ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu)
654 {
655     return ftm_map_id_to_str((int32)tmu,
656         &ftm_tmu_value_loginfo[0], ARRAYSIZE(ftm_tmu_value_loginfo));
657 }
658 
659 static const ftm_strmap_entry_t*
ftm_get_event_type_loginfo(wl_proxd_event_type_t event_type)660 ftm_get_event_type_loginfo(wl_proxd_event_type_t    event_type)
661 {
662     /* look up 'event-type' from a predefined table  */
663     return ftm_get_strmap_info((int32) event_type,
664         ftm_event_type_loginfo, ARRAYSIZE(ftm_event_type_loginfo));
665 }
666 
667 static const char *
ftm_session_state_value_to_logstr(wl_proxd_session_state_t state)668 ftm_session_state_value_to_logstr(wl_proxd_session_state_t state)
669 {
670     return ftm_map_id_to_str((int32)state, &ftm_session_state_value_loginfo[0],
671         ARRAYSIZE(ftm_session_state_value_loginfo));
672 }
673 
674 
675 #ifdef WL_CFG80211
676 /*
677  * send 'proxd' iovar for all ftm get-related commands
678  */
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)679 static int rtt_do_get_ioctl(dhd_pub_t *dhd, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize,
680     ftm_subcmd_info_t *p_subcmd_info)
681 {
682     wl_proxd_iov_t *p_iovresp = (wl_proxd_iov_t *)resp_buf;
683     int status;
684     int tlvs_len;
685     /*  send getbuf proxd iovar */
686     status = dhd_getiovar(dhd, 0, "proxd", (char *)p_proxd_iov,
687             proxd_iovsize, (char **)&p_iovresp, WLC_IOCTL_SMLEN);
688     if (status != BCME_OK) {
689         DHD_ERROR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n",
690             __FUNCTION__, p_subcmd_info->cmdid, status));
691         return status;
692     }
693     if (p_subcmd_info->cmdid == WL_PROXD_CMD_GET_VERSION) {
694         p_subcmd_info->version = ltoh16(p_iovresp->version);
695         DHD_RTT(("ftm version: 0x%x\n", ltoh16(p_iovresp->version)));
696         goto exit;
697     }
698 
699     tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE;
700     if (tlvs_len < 0) {
701         DHD_ERROR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n",
702             __FUNCTION__, ltoh16(p_iovresp->len), (int) WL_PROXD_IOV_HDR_SIZE));
703         tlvs_len = 0;
704     }
705 
706     if (tlvs_len > 0 && p_subcmd_info->handler) {
707         /* unpack TLVs and invokes the cbfn for processing */
708         status = bcm_unpack_xtlv_buf(p_proxd_iov, (uint8 *)p_iovresp->tlvs,
709                 tlvs_len, BCM_XTLV_OPTION_ALIGN32, p_subcmd_info->handler);
710     }
711 exit:
712     return status;
713 }
714 
715 
716 static wl_proxd_iov_t *
rtt_alloc_getset_buf(wl_proxd_method_t method,wl_proxd_session_id_t session_id,wl_proxd_cmd_t cmdid,uint16 tlvs_bufsize,uint16 * p_out_bufsize)717 rtt_alloc_getset_buf(wl_proxd_method_t method, wl_proxd_session_id_t session_id,
718     wl_proxd_cmd_t cmdid, uint16 tlvs_bufsize, uint16 *p_out_bufsize)
719 {
720     uint16 proxd_iovsize;
721     uint16 kflags;
722     wl_proxd_tlv_t *p_tlv;
723     wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) NULL;
724 
725     *p_out_bufsize = 0;    /* init */
726     kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
727     /* calculate the whole buffer size, including one reserve-tlv entry in the header */
728     proxd_iovsize = sizeof(wl_proxd_iov_t) + tlvs_bufsize;
729 
730     p_proxd_iov = kzalloc(proxd_iovsize, kflags);
731     if (p_proxd_iov == NULL) {
732         DHD_ERROR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize));
733         return NULL;
734     }
735 
736     /* setup proxd-FTM-method iovar header */
737     p_proxd_iov->version = htol16(WL_PROXD_API_VERSION);
738     p_proxd_iov->len = htol16(proxd_iovsize); /* caller may adjust it based on #of TLVs */
739     p_proxd_iov->cmd = htol16(cmdid);
740     p_proxd_iov->method = htol16(method);
741     p_proxd_iov->sid = htol16(session_id);
742 
743     /* initialize the reserved/dummy-TLV in iovar header */
744     p_tlv = p_proxd_iov->tlvs;
745     p_tlv->id = htol16(WL_PROXD_TLV_ID_NONE);
746     p_tlv->len = htol16(0);
747 
748     *p_out_bufsize = proxd_iovsize;    /* for caller's reference */
749 
750     return p_proxd_iov;
751 }
752 
753 
754 static int
dhd_rtt_common_get_handler(dhd_pub_t * dhd,ftm_subcmd_info_t * p_subcmd_info,wl_proxd_method_t method,wl_proxd_session_id_t session_id)755 dhd_rtt_common_get_handler(dhd_pub_t *dhd, ftm_subcmd_info_t *p_subcmd_info,
756         wl_proxd_method_t method,
757         wl_proxd_session_id_t session_id)
758 {
759     int status = BCME_OK;
760     uint16 proxd_iovsize = 0;
761     wl_proxd_iov_t *p_proxd_iov;
762 #ifdef RTT_DEBUG
763     DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
764         __FUNCTION__, method, session_id, p_subcmd_info->cmdid,
765         ftm_cmdid_to_str(p_subcmd_info->cmdid)));
766 #endif
767     /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */
768     p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid,
769         0, &proxd_iovsize);
770 
771     if (p_proxd_iov == NULL)
772         return BCME_NOMEM;
773 
774     status = rtt_do_get_ioctl(dhd, p_proxd_iov, proxd_iovsize, p_subcmd_info);
775 
776     if (status != BCME_OK) {
777         DHD_RTT(("%s failed: status=%d\n", __FUNCTION__, status));
778     }
779     kfree(p_proxd_iov);
780     return status;
781 }
782 
783 /*
784 * common handler for set-related proxd method commands which require no TLV as input
785 *   wl proxd ftm [session-id] <set-subcmd>
786 * e.g.
787 *   wl proxd ftm enable -- to enable ftm
788 *   wl proxd ftm disable -- to disable ftm
789 *   wl proxd ftm <session-id> start -- to start a specified session
790 *   wl proxd ftm <session-id> stop  -- to cancel a specified session;
791 *                                    state is maintained till session is delete.
792 *   wl proxd ftm <session-id> delete -- to delete a specified session
793 *   wl proxd ftm [<session-id>] clear-counters -- to clear counters
794 *   wl proxd ftm <session-id> burst-request -- on initiator: to send burst request;
795 *                                              on target: send FTM frame
796 *   wl proxd ftm <session-id> collect
797 *   wl proxd ftm tune     (TBD)
798 */
799 static int
dhd_rtt_common_set_handler(dhd_pub_t * dhd,const ftm_subcmd_info_t * p_subcmd_info,wl_proxd_method_t method,wl_proxd_session_id_t session_id)800 dhd_rtt_common_set_handler(dhd_pub_t *dhd, const ftm_subcmd_info_t *p_subcmd_info,
801     wl_proxd_method_t method, wl_proxd_session_id_t session_id)
802 {
803     uint16 proxd_iovsize;
804     wl_proxd_iov_t *p_proxd_iov;
805     int ret;
806 
807 #ifdef RTT_DEBUG
808     DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
809         __FUNCTION__, method, session_id, p_subcmd_info->cmdid,
810         ftm_cmdid_to_str(p_subcmd_info->cmdid)));
811 #endif
812 
813     /* allocate and initialize a temp buffer for 'set proxd' iovar */
814     proxd_iovsize = 0;
815     p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid,
816                             0, &proxd_iovsize);        /* no TLV */
817     if (p_proxd_iov == NULL)
818         return BCME_NOMEM;
819 
820     /* no TLV to pack, simply issue a set-proxd iovar */
821     ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, proxd_iovsize, NULL, 0, TRUE);
822 #ifdef RTT_DEBUG
823     if (ret != BCME_OK) {
824         DHD_RTT(("error: IOVAR failed, status=%d\n", ret));
825     }
826 #endif
827     /* clean up */
828     kfree(p_proxd_iov);
829 
830     return ret;
831 }
832 #endif /* WL_CFG80211 */
833 
834 static int
rtt_unpack_xtlv_cbfn(void * ctx,uint8 * p_data,uint16 tlvid,uint16 len)835 rtt_unpack_xtlv_cbfn(void *ctx, uint8 *p_data, uint16 tlvid, uint16 len)
836 {
837     int ret = BCME_OK;
838     int i;
839     wl_proxd_ftm_session_status_t *p_data_info = NULL;
840     wl_proxd_collect_event_data_t *p_collect_data = NULL;
841     uint32 chan_data_entry = 0;
842 
843     switch (tlvid) {
844     case WL_PROXD_TLV_ID_RTT_RESULT:
845         ret = dhd_rtt_convert_results_to_host((rtt_report_t *)ctx,
846                 p_data, tlvid, len);
847         break;
848     case WL_PROXD_TLV_ID_SESSION_STATUS:
849         DHD_RTT(("WL_PROXD_TLV_ID_SESSION_STATUS\n"));
850         memcpy(ctx, p_data, sizeof(wl_proxd_ftm_session_status_t));
851         p_data_info = (wl_proxd_ftm_session_status_t *)ctx;
852         p_data_info->sid = ltoh16_ua(&p_data_info->sid);
853         p_data_info->state = ltoh16_ua(&p_data_info->state);
854         p_data_info->status = ltoh32_ua(&p_data_info->status);
855         p_data_info->burst_num = ltoh16_ua(&p_data_info->burst_num);
856         DHD_RTT(("\tsid=%u, state=%d, status=%d, burst_num=%u\n",
857             p_data_info->sid, p_data_info->state,
858             p_data_info->status, p_data_info->burst_num));
859 
860         break;
861     case WL_PROXD_TLV_ID_COLLECT_DATA:
862         DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_DATA\n"));
863         memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_t));
864         p_collect_data = (wl_proxd_collect_event_data_t *)ctx;
865         DHD_RTT(("\tH_RX\n"));
866         for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
867             p_collect_data->H_RX[i] = ltoh32_ua(&p_collect_data->H_RX[i]);
868             DHD_RTT(("\t%u\n", p_collect_data->H_RX[i]));
869         }
870         DHD_RTT(("\n"));
871         DHD_RTT(("\tH_LB\n"));
872         for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) {
873             p_collect_data->H_LB[i] = ltoh32_ua(&p_collect_data->H_LB[i]);
874             DHD_RTT(("\t%u\n", p_collect_data->H_LB[i]));
875         }
876         DHD_RTT(("\n"));
877         DHD_RTT(("\tri_rr\n"));
878         for (i = 0; i < FTM_TPK_RI_RR_LEN; i++) {
879             DHD_RTT(("\t%u\n", p_collect_data->ri_rr[i]));
880         }
881         p_collect_data->phy_err_mask = ltoh32_ua(&p_collect_data->phy_err_mask);
882         DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data->phy_err_mask));
883         break;
884     case WL_PROXD_TLV_ID_COLLECT_CHAN_DATA:
885         DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_CHAN_DATA\n"));
886         DHD_RTT(("\tchan est %u\n", (uint32) (len / sizeof(uint32))));
887         for (i = 0; i < (len/sizeof(chan_data_entry)); i++) {
888             uint32 *p = (uint32*)p_data;
889             chan_data_entry = ltoh32_ua(p + i);
890             DHD_RTT(("\t%u\n", chan_data_entry));
891         }
892         break;
893     default:
894         DHD_ERROR(("> Unsupported TLV ID %d\n", tlvid));
895         ret = BCME_ERROR;
896         break;
897     }
898 
899     return ret;
900 }
901 
902 #ifdef WL_CFG80211
903 static int
rtt_handle_config_options(wl_proxd_session_id_t session_id,wl_proxd_tlv_t ** p_tlv,uint16 * p_buf_space_left,ftm_config_options_info_t * ftm_configs,int ftm_cfg_cnt)904 rtt_handle_config_options(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv,
905     uint16 *p_buf_space_left, ftm_config_options_info_t *ftm_configs, int ftm_cfg_cnt)
906 {
907     int ret = BCME_OK;
908     int cfg_idx = 0;
909     uint32 flags = WL_PROXD_FLAG_NONE;
910     uint32 flags_mask = WL_PROXD_FLAG_NONE;
911     uint32 new_mask;        /* cmdline input */
912     ftm_config_options_info_t *p_option_info;
913     uint16 type = (session_id == WL_PROXD_SESSION_ID_GLOBAL) ?
914             WL_PROXD_TLV_ID_FLAGS_MASK : WL_PROXD_TLV_ID_SESSION_FLAGS_MASK;
915     for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) {
916         p_option_info = (ftm_configs + cfg_idx);
917         if (p_option_info != NULL) {
918             new_mask = p_option_info->flags;
919             /* update flags mask */
920             flags_mask |= new_mask;
921             if (p_option_info->enable) {
922                 flags |= new_mask;    /* set the bit on */
923             } else {
924                 flags &= ~new_mask;    /* set the bit off */
925             }
926         }
927     }
928     flags = htol32(flags);
929     flags_mask = htol32(flags_mask);
930     /* setup flags_mask TLV */
931     ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left,
932         type, sizeof(uint32), &flags_mask, BCM_XTLV_OPTION_ALIGN32);
933     if (ret != BCME_OK) {
934         DHD_ERROR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n",
935             __FUNCTION__, ret));
936         goto exit;
937     }
938 
939     type = (session_id == WL_PROXD_SESSION_ID_GLOBAL)?
940         WL_PROXD_TLV_ID_FLAGS : WL_PROXD_TLV_ID_SESSION_FLAGS;
941     /* setup flags TLV */
942     ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left,
943             type, sizeof(uint32), &flags, BCM_XTLV_OPTION_ALIGN32);
944         if (ret != BCME_OK) {
945 #ifdef RTT_DEBUG
946             DHD_RTT(("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n",
947                 __FUNCTION__, ret));
948 #endif
949         }
950 exit:
951     return ret;
952 }
953 
954 static int
rtt_handle_config_general(wl_proxd_session_id_t session_id,wl_proxd_tlv_t ** p_tlv,uint16 * p_buf_space_left,ftm_config_param_info_t * ftm_configs,int ftm_cfg_cnt)955 rtt_handle_config_general(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv,
956     uint16 *p_buf_space_left, ftm_config_param_info_t *ftm_configs, int ftm_cfg_cnt)
957 {
958     int ret = BCME_OK;
959     int cfg_idx = 0;
960     uint32 chanspec;
961     ftm_config_param_info_t *p_config_param_info;
962     void        *p_src_data;
963     uint16    src_data_size;    /* size of data pointed by p_src_data as 'source' */
964     for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) {
965         p_config_param_info = (ftm_configs + cfg_idx);
966         if (p_config_param_info != NULL) {
967             switch (p_config_param_info->tlvid)    {
968             case WL_PROXD_TLV_ID_BSS_INDEX:
969             case WL_PROXD_TLV_ID_FTM_RETRIES:
970             case WL_PROXD_TLV_ID_FTM_REQ_RETRIES:
971                 p_src_data = &p_config_param_info->data8;
972                 src_data_size = sizeof(uint8);
973                 break;
974             case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* uint16 */
975             case WL_PROXD_TLV_ID_NUM_BURST:
976             case WL_PROXD_TLV_ID_RX_MAX_BURST:
977                 p_src_data = &p_config_param_info->data16;
978                 src_data_size = sizeof(uint16);
979                 break;
980             case WL_PROXD_TLV_ID_TX_POWER:        /* uint32 */
981             case WL_PROXD_TLV_ID_RATESPEC:
982             case WL_PROXD_TLV_ID_EVENT_MASK: /* wl_proxd_event_mask_t/uint32 */
983             case WL_PROXD_TLV_ID_DEBUG_MASK:
984                 p_src_data = &p_config_param_info->data32;
985                 src_data_size = sizeof(uint32);
986                 break;
987             case WL_PROXD_TLV_ID_CHANSPEC:        /* chanspec_t --> 32bit */
988                 chanspec = p_config_param_info->chanspec;
989                 p_src_data = (void *) &chanspec;
990                 src_data_size = sizeof(uint32);
991                 break;
992             case WL_PROXD_TLV_ID_BSSID: /* mac address */
993             case WL_PROXD_TLV_ID_PEER_MAC:
994                 p_src_data = &p_config_param_info->mac_addr;
995                 src_data_size = sizeof(struct ether_addr);
996                 break;
997             case WL_PROXD_TLV_ID_BURST_DURATION:    /* wl_proxd_intvl_t */
998             case WL_PROXD_TLV_ID_BURST_PERIOD:
999             case WL_PROXD_TLV_ID_BURST_FTM_SEP:
1000             case WL_PROXD_TLV_ID_BURST_TIMEOUT:
1001             case WL_PROXD_TLV_ID_INIT_DELAY:
1002                 p_src_data = &p_config_param_info->data_intvl;
1003                 src_data_size = sizeof(wl_proxd_intvl_t);
1004                 break;
1005             default:
1006                 ret = BCME_BADARG;
1007                 break;
1008             }
1009             if (ret != BCME_OK) {
1010                 DHD_ERROR(("%s bad TLV ID : %d\n",
1011                     __FUNCTION__, p_config_param_info->tlvid));
1012                 break;
1013             }
1014 
1015             ret = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left,
1016                 p_config_param_info->tlvid, src_data_size, p_src_data,
1017                 BCM_XTLV_OPTION_ALIGN32);
1018             if (ret != BCME_OK) {
1019                 DHD_ERROR(("%s: bcm_pack_xltv_entry() failed,"
1020                     " status=%d\n", __FUNCTION__, ret));
1021                 break;
1022             }
1023         }
1024     }
1025     return ret;
1026 }
1027 
1028 static int
dhd_rtt_ftm_enable(dhd_pub_t * dhd,bool enable)1029 dhd_rtt_ftm_enable(dhd_pub_t *dhd, bool enable)
1030 {
1031     ftm_subcmd_info_t subcmd_info;
1032     subcmd_info.name = (enable)? "enable" : "disable";
1033     subcmd_info.cmdid = (enable)? WL_PROXD_CMD_ENABLE: WL_PROXD_CMD_DISABLE;
1034     subcmd_info.handler = NULL;
1035     return dhd_rtt_common_set_handler(dhd, &subcmd_info,
1036             WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL);
1037 }
1038 
1039 static int
dhd_rtt_start_session(dhd_pub_t * dhd,wl_proxd_session_id_t session_id,bool start)1040 dhd_rtt_start_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, bool start)
1041 {
1042     ftm_subcmd_info_t subcmd_info;
1043     subcmd_info.name = (start)? "start session" : "stop session";
1044     subcmd_info.cmdid = (start)? WL_PROXD_CMD_START_SESSION: WL_PROXD_CMD_STOP_SESSION;
1045     subcmd_info.handler = NULL;
1046     return dhd_rtt_common_set_handler(dhd, &subcmd_info,
1047             WL_PROXD_METHOD_FTM, session_id);
1048 }
1049 
1050 static int
dhd_rtt_delete_session(dhd_pub_t * dhd,wl_proxd_session_id_t session_id)1051 dhd_rtt_delete_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id)
1052 {
1053     ftm_subcmd_info_t subcmd_info;
1054     subcmd_info.name = "delete session";
1055     subcmd_info.cmdid = WL_PROXD_CMD_DELETE_SESSION;
1056     subcmd_info.handler = NULL;
1057     return dhd_rtt_common_set_handler(dhd, &subcmd_info,
1058             WL_PROXD_METHOD_FTM, session_id);
1059 }
1060 
1061 static int
dhd_rtt_ftm_config(dhd_pub_t * dhd,wl_proxd_session_id_t session_id,ftm_config_category_t catagory,void * ftm_configs,int ftm_cfg_cnt)1062 dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id,
1063     ftm_config_category_t catagory, void *ftm_configs, int ftm_cfg_cnt)
1064 {
1065     ftm_subcmd_info_t subcmd_info;
1066     wl_proxd_tlv_t *p_tlv;
1067     /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */
1068     wl_proxd_iov_t *p_proxd_iov;
1069     uint16 proxd_iovsize = 0;
1070     uint16 bufsize;
1071     uint16 buf_space_left;
1072     uint16 all_tlvsize;
1073     int ret = BCME_OK;
1074 
1075     subcmd_info.name = "config";
1076     subcmd_info.cmdid = WL_PROXD_CMD_CONFIG;
1077 
1078     p_proxd_iov = rtt_alloc_getset_buf(WL_PROXD_METHOD_FTM, session_id, subcmd_info.cmdid,
1079         FTM_IOC_BUFSZ, &proxd_iovsize);
1080 
1081     if (p_proxd_iov == NULL) {
1082         DHD_ERROR(("%s : failed to allocate the iovar (size :%d)\n",
1083             __FUNCTION__, FTM_IOC_BUFSZ));
1084         return BCME_NOMEM;
1085     }
1086     /* setup TLVs */
1087     bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */
1088     p_tlv = &p_proxd_iov->tlvs[0];
1089     /* TLV buffer starts with a full size, will decrement for each packed TLV */
1090     buf_space_left = bufsize;
1091     if (catagory == FTM_CONFIG_CAT_OPTIONS) {
1092         ret = rtt_handle_config_options(session_id, &p_tlv, &buf_space_left,
1093                 (ftm_config_options_info_t *)ftm_configs, ftm_cfg_cnt);
1094     } else if (catagory == FTM_CONFIG_CAT_GENERAL) {
1095         ret = rtt_handle_config_general(session_id, &p_tlv, &buf_space_left,
1096                 (ftm_config_param_info_t *)ftm_configs, ftm_cfg_cnt);
1097     }
1098     if (ret == BCME_OK) {
1099         /* update the iov header, set len to include all TLVs + header */
1100         all_tlvsize = (bufsize - buf_space_left);
1101         p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE);
1102         ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov,
1103                 all_tlvsize + WL_PROXD_IOV_HDR_SIZE, NULL, 0, TRUE);
1104         if (ret != BCME_OK) {
1105             DHD_ERROR(("%s : failed to set config\n", __FUNCTION__));
1106         }
1107     }
1108     /* clean up */
1109     kfree(p_proxd_iov);
1110     return ret;
1111 }
1112 
1113 static int
dhd_rtt_get_version(dhd_pub_t * dhd,int * out_version)1114 dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version)
1115 {
1116     int ret;
1117     ftm_subcmd_info_t subcmd_info;
1118     subcmd_info.name = "ver";
1119     subcmd_info.cmdid = WL_PROXD_CMD_GET_VERSION;
1120     subcmd_info.handler = NULL;
1121     ret = dhd_rtt_common_get_handler(dhd, &subcmd_info,
1122             WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL);
1123     *out_version = (ret == BCME_OK) ? subcmd_info.version : 0;
1124     return ret;
1125 }
1126 #endif /* WL_CFG80211 */
1127 
1128 chanspec_t
dhd_rtt_convert_to_chspec(wifi_channel_info_t channel)1129 dhd_rtt_convert_to_chspec(wifi_channel_info_t channel)
1130 {
1131     int bw;
1132     chanspec_t chanspec = 0;
1133     uint8 center_chan;
1134     uint8 primary_chan;
1135     /* set witdh to 20MHZ for 2.4G HZ */
1136     if (channel.center_freq >= 2400 && channel.center_freq <= 2500) {
1137         channel.width = WIFI_CHAN_WIDTH_20;
1138     }
1139     switch (channel.width) {
1140     case WIFI_CHAN_WIDTH_20:
1141         bw = WL_CHANSPEC_BW_20;
1142         primary_chan = wf_mhz2channel(channel.center_freq, 0);
1143         chanspec = wf_channel2chspec(primary_chan, bw);
1144         break;
1145     case WIFI_CHAN_WIDTH_40:
1146         bw = WL_CHANSPEC_BW_40;
1147         primary_chan = wf_mhz2channel(channel.center_freq, 0);
1148         chanspec = wf_channel2chspec(primary_chan, bw);
1149         break;
1150     case WIFI_CHAN_WIDTH_80:
1151         bw = WL_CHANSPEC_BW_80;
1152         primary_chan = wf_mhz2channel(channel.center_freq, 0);
1153         center_chan = wf_mhz2channel(channel.center_freq0, 0);
1154         chanspec = wf_chspec_80(center_chan, primary_chan);
1155         break;
1156     default:
1157         DHD_ERROR(("doesn't support this bandwith : %d", channel.width));
1158         bw = -1;
1159         break;
1160     }
1161     return chanspec;
1162 }
1163 
1164 int
dhd_rtt_idx_to_burst_duration(uint idx)1165 dhd_rtt_idx_to_burst_duration(uint idx)
1166 {
1167     if (idx >= ARRAY_SIZE(burst_duration_idx)) {
1168         return -1;
1169     }
1170     return burst_duration_idx[idx];
1171 }
1172 
1173 int
dhd_rtt_set_cfg(dhd_pub_t * dhd,rtt_config_params_t * params)1174 dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params)
1175 {
1176     int err = BCME_OK;
1177     int idx;
1178     rtt_status_info_t *rtt_status;
1179     NULL_CHECK(params, "params is NULL", err);
1180 
1181     NULL_CHECK(dhd, "dhd is NULL", err);
1182     rtt_status = GET_RTTSTATE(dhd);
1183     NULL_CHECK(rtt_status, "rtt_status is NULL", err);
1184     if (!HAS_11MC_CAP(rtt_status->rtt_capa.proto)) {
1185         DHD_ERROR(("doesn't support RTT \n"));
1186         return BCME_ERROR;
1187     }
1188     if (rtt_status->status != RTT_STOPPED) {
1189         DHD_ERROR(("rtt is already started\n"));
1190         return BCME_BUSY;
1191     }
1192     DHD_RTT(("%s enter\n", __FUNCTION__));
1193 
1194     memset(rtt_status->rtt_config.target_info, 0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
1195     rtt_status->rtt_config.rtt_target_cnt = params->rtt_target_cnt;
1196     memcpy(rtt_status->rtt_config.target_info,
1197         params->target_info, TARGET_INFO_SIZE(params->rtt_target_cnt));
1198     rtt_status->status = RTT_STARTED;
1199     /* start to measure RTT from first device */
1200     /* find next target to trigger RTT */
1201     for (idx = rtt_status->cur_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
1202         /* skip the disabled device */
1203         if (rtt_status->rtt_config.target_info[idx].disable) {
1204             continue;
1205         } else {
1206             /* set the idx to cur_idx */
1207             rtt_status->cur_idx = idx;
1208             break;
1209         }
1210     }
1211     if (idx < rtt_status->rtt_config.rtt_target_cnt) {
1212         DHD_RTT(("rtt_status->cur_idx : %d\n", rtt_status->cur_idx));
1213         schedule_work(&rtt_status->work);
1214     }
1215     return err;
1216 }
1217 
1218 int
dhd_rtt_stop(dhd_pub_t * dhd,struct ether_addr * mac_list,int mac_cnt)1219 dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt)
1220 {
1221     int err = BCME_OK;
1222 #ifdef WL_CFG8011
1223     int i = 0, j = 0;
1224     rtt_status_info_t *rtt_status;
1225     rtt_results_header_t *entry, *next;
1226     rtt_result_t *rtt_result, *next2;
1227     struct rtt_noti_callback *iter;
1228 
1229     NULL_CHECK(dhd, "dhd is NULL", err);
1230     rtt_status = GET_RTTSTATE(dhd);
1231     NULL_CHECK(rtt_status, "rtt_status is NULL", err);
1232     if (rtt_status->status == RTT_STOPPED) {
1233         DHD_ERROR(("rtt is not started\n"));
1234         return BCME_OK;
1235     }
1236     DHD_RTT(("%s enter\n", __FUNCTION__));
1237     mutex_lock(&rtt_status->rtt_mutex);
1238     for (i = 0; i < mac_cnt; i++) {
1239         for (j = 0; j < rtt_status->rtt_config.rtt_target_cnt; j++) {
1240             if (!bcmp(&mac_list[i], &rtt_status->rtt_config.target_info[j].addr,
1241                 ETHER_ADDR_LEN)) {
1242                 rtt_status->rtt_config.target_info[j].disable = TRUE;
1243             }
1244         }
1245     }
1246     if (rtt_status->all_cancel) {
1247         /* cancel all of request */
1248         rtt_status->status = RTT_STOPPED;
1249         DHD_RTT(("current RTT process is cancelled\n"));
1250         /* remove the rtt results in cache */
1251         if (!list_empty(&rtt_status->rtt_results_cache)) {
1252             /* Iterate rtt_results_header list */
1253 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1254 #pragma GCC diagnostic push
1255 #pragma GCC diagnostic ignored "-Wcast-qual"
1256 #endif
1257             list_for_each_entry_safe(entry, next,
1258                 &rtt_status->rtt_results_cache, list) {
1259                 list_del(&entry->list);
1260                 /* Iterate rtt_result list */
1261                 list_for_each_entry_safe(rtt_result, next2,
1262                     &entry->result_list, list) {
1263                     list_del(&rtt_result->list);
1264                     kfree(rtt_result);
1265                 }
1266                 kfree(entry);
1267             }
1268 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1269 #pragma GCC diagnostic pop
1270 #endif
1271         }
1272         /* send the rtt complete event to wake up the user process */
1273 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1274 #pragma GCC diagnostic push
1275 #pragma GCC diagnostic ignored "-Wcast-qual"
1276 #endif
1277         list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
1278             iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache);
1279         }
1280 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1281 #pragma GCC diagnostic pop
1282 #endif
1283         /* reinitialize the HEAD */
1284         INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
1285         /* clear information for rtt_config */
1286         rtt_status->rtt_config.rtt_target_cnt = 0;
1287         memset(rtt_status->rtt_config.target_info, 0,
1288             TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
1289         rtt_status->cur_idx = 0;
1290         dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION);
1291         dhd_rtt_ftm_enable(dhd, FALSE);
1292     }
1293     mutex_unlock(&rtt_status->rtt_mutex);
1294 #endif /* WL_CFG80211 */
1295     return err;
1296 }
1297 
1298 
1299 #ifdef WL_CFG80211
1300 static int
dhd_rtt_start(dhd_pub_t * dhd)1301 dhd_rtt_start(dhd_pub_t *dhd)
1302 {
1303     int err = BCME_OK;
1304     char eabuf[ETHER_ADDR_STR_LEN];
1305     char chanbuf[CHANSPEC_STR_LEN];
1306     int ftm_cfg_cnt = 0;
1307     int ftm_param_cnt = 0;
1308     uint32 rspec = 0;
1309     ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS];
1310     ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS];
1311     rtt_target_info_t *rtt_target;
1312     rtt_status_info_t *rtt_status;
1313     int pm = PM_OFF;
1314     struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
1315     NULL_CHECK(dhd, "dhd is NULL", err);
1316 
1317     rtt_status = GET_RTTSTATE(dhd);
1318     NULL_CHECK(rtt_status, "rtt_status is NULL", err);
1319 
1320     DHD_RTT(("Enter %s\n", __FUNCTION__));
1321     if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) {
1322         err = BCME_RANGE;
1323         DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx));
1324         if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) {
1325             DHD_ERROR(("STA is set as Target/Responder \n"));
1326             return BCME_ERROR;
1327         }
1328         goto exit;
1329     }
1330     if (RTT_IS_STOPPED(rtt_status)) {
1331         DHD_RTT(("RTT is stopped\n"));
1332         goto exit;
1333     }
1334     err = wldev_ioctl_get(dev, WLC_GET_PM, &rtt_status->pm, sizeof(rtt_status->pm));
1335     if (err) {
1336         DHD_ERROR(("Failed to get the PM value\n"));
1337     } else {
1338         err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
1339         if (err) {
1340             DHD_ERROR(("Failed to set the PM\n"));
1341             rtt_status->pm_restore = FALSE;
1342         } else {
1343             rtt_status->pm_restore = TRUE;
1344         }
1345     }
1346 
1347     mutex_lock(&rtt_status->rtt_mutex);
1348     /* Get a target information */
1349     rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
1350     mutex_unlock(&rtt_status->rtt_mutex);
1351     DHD_RTT(("%s enter\n", __FUNCTION__));
1352     if (!RTT_IS_ENABLED(rtt_status)) {
1353         /* enable ftm */
1354         err = dhd_rtt_ftm_enable(dhd, TRUE);
1355         if (err) {
1356             DHD_ERROR(("failed to enable FTM (%d)\n", err));
1357             goto exit;
1358         }
1359     }
1360 
1361     /* delete session of index default sesession  */
1362     err = dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION);
1363     if (err < 0 && err != BCME_NOTFOUND) {
1364         DHD_ERROR(("failed to delete session of FTM (%d)\n", err));
1365         goto exit;
1366     }
1367     rtt_status->status = RTT_ENABLED;
1368     memset(ftm_configs, 0, sizeof(ftm_configs));
1369     memset(ftm_params, 0, sizeof(ftm_params));
1370 
1371     /* configure the session 1 as initiator */
1372     ftm_configs[ftm_cfg_cnt].enable = TRUE;
1373     ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_INITIATOR;
1374     dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS,
1375         ftm_configs, ftm_cfg_cnt);
1376     /* target's mac address */
1377     if (!ETHER_ISNULLADDR(rtt_target->addr.octet)) {
1378         ftm_params[ftm_param_cnt].mac_addr = rtt_target->addr;
1379         ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_PEER_MAC;
1380         bcm_ether_ntoa(&rtt_target->addr, eabuf);
1381         DHD_RTT((">\t target %s\n", eabuf));
1382     }
1383     /* target's chanspec */
1384     if (rtt_target->chanspec) {
1385         ftm_params[ftm_param_cnt].chanspec = htol32((uint32)rtt_target->chanspec);
1386         ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_CHANSPEC;
1387         wf_chspec_ntoa(rtt_target->chanspec, chanbuf);
1388         DHD_RTT((">\t chanspec : %s\n", chanbuf));
1389     }
1390     /* num-burst */
1391     if (rtt_target->num_burst) {
1392         ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_burst);
1393         ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_NUM_BURST;
1394         DHD_RTT((">\t num of burst : %d\n", rtt_target->num_burst));
1395     }
1396     /* number of frame per burst */
1397     if (rtt_target->num_frames_per_burst == 0) {
1398         rtt_target->num_frames_per_burst =
1399             CHSPEC_IS20(rtt_target->chanspec) ? FTM_DEFAULT_CNT_20M :
1400             CHSPEC_IS40(rtt_target->chanspec) ? FTM_DEFAULT_CNT_40M :
1401             FTM_DEFAULT_CNT_80M;
1402     }
1403     ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_frames_per_burst);
1404     ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_NUM_FTM;
1405     DHD_RTT((">\t number of frame per burst : %d\n", rtt_target->num_frames_per_burst));
1406     /* FTM retry count */
1407     if (rtt_target->num_retries_per_ftm) {
1408         ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftm;
1409         ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_RETRIES;
1410         DHD_RTT((">\t retry count of FTM  : %d\n", rtt_target->num_retries_per_ftm));
1411     }
1412     /* FTM Request retry count */
1413     if (rtt_target->num_retries_per_ftmr) {
1414         ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftmr;
1415         ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_REQ_RETRIES;
1416         DHD_RTT((">\t retry count of FTM Req : %d\n", rtt_target->num_retries_per_ftmr));
1417     }
1418     /* burst-period */
1419     if (rtt_target->burst_period) {
1420         ftm_params[ftm_param_cnt].data_intvl.intvl =
1421             htol32(rtt_target->burst_period); /* ms */
1422         ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC;
1423         ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_PERIOD;
1424         DHD_RTT((">\t burst period : %d ms\n", rtt_target->burst_period));
1425     }
1426     /* burst-duration */
1427     if (rtt_target->burst_duration) {
1428         ftm_params[ftm_param_cnt].data_intvl.intvl =
1429             htol32(rtt_target->burst_duration); /* ms */
1430         ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC;
1431         ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_DURATION;
1432         DHD_RTT((">\t burst duration : %d ms\n",
1433             rtt_target->burst_duration));
1434     }
1435     if (rtt_target->bw && rtt_target->preamble) {
1436         bool use_default = FALSE;
1437         int nss;
1438         int mcs;
1439         switch (rtt_target->preamble) {
1440         case RTT_PREAMBLE_LEGACY:
1441             rspec |= WL_RSPEC_ENCODE_RATE; /* 11abg */
1442             rspec |= WL_RATE_6M;
1443             break;
1444         case RTT_PREAMBLE_HT:
1445             rspec |= WL_RSPEC_ENCODE_HT; /* 11n HT */
1446             mcs = 0; /* default MCS 0 */
1447             rspec |= mcs;
1448             break;
1449         case RTT_PREAMBLE_VHT:
1450             rspec |= WL_RSPEC_ENCODE_VHT; /* 11ac VHT */
1451             mcs = 0; /* default MCS 0 */
1452             nss = 1; /* default Nss = 1  */
1453             rspec |= (nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs;
1454             break;
1455         default:
1456             DHD_RTT(("doesn't support this preamble : %d\n", rtt_target->preamble));
1457             use_default = TRUE;
1458             break;
1459         }
1460         switch (rtt_target->bw) {
1461         case RTT_BW_20:
1462             rspec |= WL_RSPEC_BW_20MHZ;
1463             break;
1464         case RTT_BW_40:
1465             rspec |= WL_RSPEC_BW_40MHZ;
1466             break;
1467         case RTT_BW_80:
1468             rspec |= WL_RSPEC_BW_80MHZ;
1469             break;
1470         default:
1471             DHD_RTT(("doesn't support this BW : %d\n", rtt_target->bw));
1472             use_default = TRUE;
1473             break;
1474         }
1475         if (!use_default) {
1476             ftm_params[ftm_param_cnt].data32 = htol32(rspec);
1477             ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_RATESPEC;
1478             DHD_RTT((">\t ratespec : %d\n", rspec));
1479         }
1480     }
1481     dhd_set_rand_mac_oui(dhd);
1482     dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_GENERAL,
1483         ftm_params, ftm_param_cnt);
1484 
1485     err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE);
1486     if (err) {
1487         DHD_ERROR(("failed to start session of FTM : error %d\n", err));
1488     }
1489 exit:
1490     if (err) {
1491         DHD_ERROR(("rtt is stopped %s \n", __FUNCTION__));
1492         rtt_status->status = RTT_STOPPED;
1493         /* disable FTM */
1494         dhd_rtt_ftm_enable(dhd, FALSE);
1495         if (rtt_status->pm_restore) {
1496             DHD_ERROR(("pm_restore =%d func =%s \n",
1497                 rtt_status->pm_restore, __FUNCTION__));
1498             pm = PM_FAST;
1499             err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
1500             if (err) {
1501                 DHD_ERROR(("Failed to set PM \n"));
1502             } else {
1503                 rtt_status->pm_restore = FALSE;
1504             }
1505         }
1506     }
1507     return err;
1508 }
1509 #endif /* WL_CFG80211 */
1510 
1511 int
dhd_rtt_register_noti_callback(dhd_pub_t * dhd,void * ctx,dhd_rtt_compl_noti_fn noti_fn)1512 dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn)
1513 {
1514     int err = BCME_OK;
1515     struct rtt_noti_callback *cb = NULL, *iter;
1516     rtt_status_info_t *rtt_status;
1517     NULL_CHECK(dhd, "dhd is NULL", err);
1518     NULL_CHECK(noti_fn, "noti_fn is NULL", err);
1519 
1520     rtt_status = GET_RTTSTATE(dhd);
1521     NULL_CHECK(rtt_status, "rtt_status is NULL", err);
1522     spin_lock_bh(&noti_list_lock);
1523 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1524 #pragma GCC diagnostic push
1525 #pragma GCC diagnostic ignored "-Wcast-qual"
1526 #endif
1527     list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
1528         if (iter->noti_fn == noti_fn) {
1529             goto exit;
1530         }
1531     }
1532 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1533 #pragma GCC diagnostic pop
1534 #endif
1535     cb = kmalloc(sizeof(struct rtt_noti_callback), GFP_ATOMIC);
1536     if (!cb) {
1537         err = -ENOMEM;
1538         goto exit;
1539     }
1540     cb->noti_fn = noti_fn;
1541     cb->ctx = ctx;
1542     list_add(&cb->list, &rtt_status->noti_fn_list);
1543 exit:
1544     spin_unlock_bh(&noti_list_lock);
1545     return err;
1546 }
1547 
1548 int
dhd_rtt_unregister_noti_callback(dhd_pub_t * dhd,dhd_rtt_compl_noti_fn noti_fn)1549 dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn)
1550 {
1551     int err = BCME_OK;
1552     struct rtt_noti_callback *cb = NULL, *iter;
1553     rtt_status_info_t *rtt_status;
1554     NULL_CHECK(dhd, "dhd is NULL", err);
1555     NULL_CHECK(noti_fn, "noti_fn is NULL", err);
1556     rtt_status = GET_RTTSTATE(dhd);
1557     NULL_CHECK(rtt_status, "rtt_status is NULL", err);
1558     spin_lock_bh(&noti_list_lock);
1559 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1560 #pragma GCC diagnostic push
1561 #pragma GCC diagnostic ignored "-Wcast-qual"
1562 #endif
1563     list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
1564         if (iter->noti_fn == noti_fn) {
1565             cb = iter;
1566             list_del(&cb->list);
1567             break;
1568         }
1569     }
1570 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1571 #pragma GCC diagnostic pop
1572 #endif
1573 
1574     spin_unlock_bh(&noti_list_lock);
1575     if (cb) {
1576         kfree(cb);
1577     }
1578     return err;
1579 }
1580 
1581 static wifi_rate_t
dhd_rtt_convert_rate_to_host(uint32 rspec)1582 dhd_rtt_convert_rate_to_host(uint32 rspec)
1583 {
1584     wifi_rate_t host_rate;
1585     memset(&host_rate, 0, sizeof(wifi_rate_t));
1586     if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) {
1587         host_rate.preamble = 0;
1588     } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) {
1589         host_rate.preamble = 2;
1590         host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK;
1591     } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) {
1592         host_rate.preamble = 3;
1593         host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK;
1594         host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
1595     }
1596     host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1;
1597     host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */
1598     DHD_RTT(("bit rate : %d\n", host_rate.bitrate));
1599     return host_rate;
1600 }
1601 
1602 
1603 static int
dhd_rtt_convert_results_to_host(rtt_report_t * rtt_report,uint8 * p_data,uint16 tlvid,uint16 len)1604 dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len)
1605 {
1606     int err = BCME_OK;
1607     char eabuf[ETHER_ADDR_STR_LEN];
1608     wl_proxd_rtt_result_t *p_data_info;
1609     wl_proxd_result_flags_t flags;
1610     wl_proxd_session_state_t session_state;
1611     wl_proxd_status_t proxd_status;
1612 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
1613     struct timespec64 ts;
1614 #endif /* LINUX_VER >= 2.6.39 */
1615     uint32 ratespec;
1616     uint32 avg_dist;
1617     wl_proxd_rtt_sample_t *p_sample;
1618     wl_proxd_intvl_t rtt;
1619     wl_proxd_intvl_t p_time;
1620 
1621     NULL_CHECK(rtt_report, "rtt_report is NULL", err);
1622     NULL_CHECK(p_data, "p_data is NULL", err);
1623     DHD_RTT(("%s enter\n", __FUNCTION__));
1624     p_data_info = (wl_proxd_rtt_result_t *) p_data;
1625     /* unpack and format 'flags' for display */
1626     flags = ltoh16_ua(&p_data_info->flags);
1627 
1628     /* session state and status */
1629     session_state = ltoh16_ua(&p_data_info->state);
1630     proxd_status = ltoh32_ua(&p_data_info->status);
1631     bcm_ether_ntoa((&(p_data_info->peer)), eabuf);
1632     ftm_session_state_value_to_logstr(session_state);
1633     ftm_status_value_to_logstr(proxd_status);
1634     DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n",
1635         eabuf,
1636         session_state,
1637         ftm_session_state_value_to_logstr(session_state),
1638         proxd_status,
1639         ftm_status_value_to_logstr(proxd_status)));
1640 
1641     /* show avg_dist (1/256m units), burst_num */
1642     avg_dist = ltoh32_ua(&p_data_info->avg_dist);
1643     if (avg_dist == 0xffffffff) {    /* report 'failure' case */
1644         DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n",
1645         ltoh16_ua(&p_data_info->burst_num),
1646         p_data_info->num_valid_rtt)); /* in a session */
1647         avg_dist = FTM_INVALID;
1648     }
1649     else {
1650         DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n",
1651             avg_dist >> 8, /* 1/256m units */
1652             ((avg_dist & 0xff) * 625) >> 4,
1653             ltoh16_ua(&p_data_info->burst_num),
1654             p_data_info->num_valid_rtt,
1655             p_data_info->num_ftm)); /* in a session */
1656     }
1657     /* show 'avg_rtt' sample */
1658     p_sample = &p_data_info->avg_rtt;
1659     ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu));
1660     DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d ratespec=0x%08x\n",
1661         (int16) ltoh16_ua(&p_sample->rssi),
1662         ltoh32_ua(&p_sample->rtt.intvl),
1663         ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)),
1664         ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10,
1665         ltoh32_ua(&p_sample->ratespec)));
1666 
1667     /* set peer address */
1668     rtt_report->addr = p_data_info->peer;
1669     /* burst num */
1670     rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num);
1671     /* success num */
1672     rtt_report->success_num = p_data_info->num_valid_rtt;
1673     /* actual number of FTM supported by peer */
1674     rtt_report->num_per_burst_peer = p_data_info->num_ftm;
1675     rtt_report->negotiated_burst_num = p_data_info->num_ftm;
1676     /* status */
1677     rtt_report->status = ftm_get_statusmap_info(proxd_status,
1678             &ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info));
1679 
1680     /* rssi (0.5db) */
1681     rtt_report->rssi = ABS((wl_proxd_rssi_t)ltoh16_ua(&p_data_info->avg_rtt.rssi)) * 2;
1682 
1683     /* rx rate */
1684     ratespec = ltoh32_ua(&p_data_info->avg_rtt.ratespec);
1685     rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec);
1686     /* tx rate */
1687     if (flags & WL_PROXD_RESULT_FLAG_VHTACK) {
1688         rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0x2010010);
1689     } else {
1690         rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0xc);
1691     }
1692     /* rtt_sd */
1693     rtt.tmu = ltoh16_ua(&p_data_info->avg_rtt.rtt.tmu);
1694     rtt.intvl = ltoh32_ua(&p_data_info->avg_rtt.rtt.intvl);
1695     rtt_report->rtt = (wifi_timespan)FTM_INTVL2NSEC(&rtt) * 1000; /* nano -> pico seconds */
1696     rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */
1697     DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt));
1698     DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi));
1699 
1700     /* average distance */
1701     if (avg_dist != FTM_INVALID) {
1702         rtt_report->distance = (avg_dist >> 8) * 1000; /* meter -> mm */
1703         rtt_report->distance += (avg_dist & 0xff) * 1000 / 256;
1704     } else {
1705         rtt_report->distance = FTM_INVALID;
1706     }
1707     /* time stamp */
1708     /* get the time elapsed from boot time */
1709 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
1710     ts = ktime_to_timespec64(ktime_get_boottime());
1711     rtt_report->ts = (uint64)TIMESPEC_TO_US(ts);
1712 #endif /* LINUX_VER >= 2.6.39 */
1713 
1714     if (proxd_status == WL_PROXD_E_REMOTE_FAIL) {
1715         /* retry time  after failure */
1716         p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl);
1717         p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu);
1718         rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */
1719         DHD_RTT((">\tretry_after: %d%s\n",
1720             ltoh32_ua(&p_data_info->u.retry_after.intvl),
1721             ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu))));
1722     } else {
1723         /* burst duration */
1724         p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl);
1725         p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu);
1726         rtt_report->burst_duration =  FTM_INTVL2MSEC(&p_time); /* s -> ms */
1727         DHD_RTT((">\tburst_duration: %d%s\n",
1728             ltoh32_ua(&p_data_info->u.burst_duration.intvl),
1729             ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu))));
1730         DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report->burst_duration));
1731     }
1732     return err;
1733 }
1734 
1735 int
dhd_rtt_event_handler(dhd_pub_t * dhd,wl_event_msg_t * event,void * event_data)1736 dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
1737 {
1738     int ret = BCME_OK;
1739     int tlvs_len;
1740     uint16 version;
1741     wl_proxd_event_t *p_event;
1742     wl_proxd_event_type_t event_type;
1743     wl_proxd_ftm_session_status_t session_status;
1744     wl_proxd_collect_event_data_t *collect_event_data;
1745     const ftm_strmap_entry_t *p_loginfo;
1746     rtt_result_t *rtt_result;
1747     gfp_t kflags;
1748 #ifdef WL_CFG80211
1749     int idx;
1750     struct rtt_noti_callback *iter;
1751     bool is_new = TRUE;
1752     rtt_status_info_t *rtt_status;
1753     rtt_result_t *next2;
1754     rtt_results_header_t *next = NULL;
1755     rtt_target_info_t *rtt_target_info;
1756     rtt_results_header_t *entry, *rtt_results_header = NULL;
1757 #endif /* WL_CFG80211 */
1758 
1759     DHD_RTT(("Enter %s \n", __FUNCTION__));
1760     NULL_CHECK(dhd, "dhd is NULL", ret);
1761 
1762 #ifdef WL_CFG80211
1763     rtt_status = GET_RTTSTATE(dhd);
1764     NULL_CHECK(rtt_status, "rtt_status is NULL", ret);
1765 
1766     if (RTT_IS_STOPPED(rtt_status)) {
1767         /* Ignore the Proxd event */
1768         DHD_RTT((" event handler rtt is stopped \n"));
1769         if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) {
1770             DHD_RTT(("Device is target/Responder. Recv the event. \n"));
1771         } else {
1772             return ret;
1773         }
1774     }
1775 #endif /* WL_CFG80211 */
1776     if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) {
1777         DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__,
1778             ntoh32_ua((void *)&event->datalen)));
1779         return -EINVAL;
1780     }
1781     event_type = ntoh32_ua((void *)&event->event_type);
1782     if (event_type != WLC_E_PROXD) {
1783         DHD_ERROR((" failed event \n"));
1784         return -EINVAL;
1785     }
1786 
1787     if (!event_data) {
1788         DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__));
1789         return -EINVAL;
1790     }
1791     p_event = (wl_proxd_event_t *) event_data;
1792     version = ltoh16(p_event->version);
1793     if (version < WL_PROXD_API_VERSION) {
1794         DHD_ERROR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n",
1795             version, WL_PROXD_API_VERSION));
1796         return ret;
1797     }
1798 #ifdef WL_CFG80211
1799     if (!in_atomic()) {
1800         mutex_lock(&rtt_status->rtt_mutex);
1801     }
1802 #endif /* WL_CFG80211 */
1803     event_type = (wl_proxd_event_type_t) ltoh16(p_event->type);
1804 
1805     kflags = in_softirq()? GFP_ATOMIC : GFP_KERNEL;
1806 
1807     DHD_RTT(("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x\n",
1808         p_event->type, ntoh16(p_event->type), ltoh16(p_event->type)));
1809     p_loginfo = ftm_get_event_type_loginfo(event_type);
1810     if (p_loginfo == NULL) {
1811         DHD_ERROR(("receive an invalid FTM event %d\n", event_type));
1812         ret = -EINVAL;
1813         goto exit;    /* ignore this event */
1814     }
1815     /* get TLVs len, skip over event header */
1816     if (ltoh16(p_event->len) < OFFSETOF(wl_proxd_event_t, tlvs)) {
1817         DHD_ERROR(("invalid FTM event length:%d\n", ltoh16(p_event->len)));
1818         ret = -EINVAL;
1819         goto exit;
1820     }
1821     tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs);
1822     DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n",
1823         p_loginfo->text,
1824         version,
1825         ltoh16(p_event->len),
1826         ltoh16(p_event->method),
1827         ltoh16(p_event->sid),
1828         tlvs_len));
1829 #ifdef WL_CFG80211
1830     rtt_target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
1831 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1832 #pragma GCC diagnostic push
1833 #pragma GCC diagnostic ignored "-Wcast-qual"
1834 #endif
1835     /* find a rtt_report_header for this mac address */
1836     list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) {
1837         if (!memcmp(&entry->peer_mac, &event->addr, ETHER_ADDR_LEN))  {
1838             /* found a rtt_report_header for peer_mac in the list */
1839             is_new = FALSE;
1840             rtt_results_header = entry;
1841             break;
1842         }
1843     }
1844 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1845 #pragma GCC diagnostic pop
1846 #endif
1847 #endif /* WL_CFG80211 */
1848     switch (event_type) {
1849     case WL_PROXD_EVENT_SESSION_CREATE:
1850         DHD_RTT(("WL_PROXD_EVENT_SESSION_CREATE\n"));
1851         break;
1852     case WL_PROXD_EVENT_SESSION_START:
1853         DHD_RTT(("WL_PROXD_EVENT_SESSION_START\n"));
1854         break;
1855     case WL_PROXD_EVENT_BURST_START:
1856         DHD_RTT(("WL_PROXD_EVENT_BURST_START\n"));
1857         break;
1858     case WL_PROXD_EVENT_BURST_END:
1859         DHD_RTT(("WL_PROXD_EVENT_BURST_END\n"));
1860 #ifdef WL_CFG80211
1861         if (is_new) {
1862             /* allocate new header for rtt_results */
1863             rtt_results_header = kzalloc(sizeof(rtt_results_header_t), kflags);
1864             if (!rtt_results_header) {
1865                 ret = -ENOMEM;
1866                 goto exit;
1867             }
1868             /* Initialize the head of list for rtt result */
1869             INIT_LIST_HEAD(&rtt_results_header->result_list);
1870             rtt_results_header->peer_mac = event->addr;
1871             list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache);
1872         }
1873 #endif /* WL_CFG80211 */
1874         if (tlvs_len > 0) {
1875             /* allocate rtt_results for new results */
1876             rtt_result = kzalloc(sizeof(rtt_result_t), kflags);
1877             if (!rtt_result) {
1878                 ret = -ENOMEM;
1879                 goto exit;
1880             }
1881             /* unpack TLVs and invokes the cbfn to print the event content TLVs */
1882             ret = bcm_unpack_xtlv_buf((void *) &(rtt_result->report),
1883                 (uint8 *)&p_event->tlvs[0], tlvs_len,
1884                 BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn);
1885             if (ret != BCME_OK) {
1886                 DHD_ERROR(("%s : Failed to unpack xtlv for an event\n",
1887                     __FUNCTION__));
1888                 goto exit;
1889             }
1890 #ifdef WL_CFG80211
1891             /* fill out the results from the configuration param */
1892             rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst;
1893             rtt_result->report.type = RTT_TWO_WAY;
1894             DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num));
1895             rtt_result->report_len = RTT_REPORT_SIZE;
1896 
1897             list_add_tail(&rtt_result->list, &rtt_results_header->result_list);
1898             rtt_results_header->result_cnt++;
1899             rtt_results_header->result_tot_len += rtt_result->report_len;
1900 #endif /* WL_CFG80211 */
1901         }
1902         break;
1903     case WL_PROXD_EVENT_SESSION_END:
1904             DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n"));
1905 #ifdef WL_CFG80211
1906         if (!RTT_IS_ENABLED(rtt_status)) {
1907             DHD_RTT(("Ignore the session end evt\n"));
1908             goto exit;
1909         }
1910 #endif /* WL_CFG80211 */
1911         if (tlvs_len > 0) {
1912             /* unpack TLVs and invokes the cbfn to print the event content TLVs */
1913             ret = bcm_unpack_xtlv_buf((void *) &session_status,
1914                 (uint8 *)&p_event->tlvs[0], tlvs_len,
1915                 BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn);
1916             if (ret != BCME_OK) {
1917                 DHD_ERROR(("%s : Failed to unpack xtlv for an event\n",
1918                     __FUNCTION__));
1919                 goto exit;
1920             }
1921         }
1922 #ifdef WL_CFG80211
1923         /* In case of no result for the peer device, make fake result for error case */
1924         if (is_new) {
1925             /* allocate new header for rtt_results */
1926             rtt_results_header = kzalloc(sizeof(rtt_results_header_t), GFP_KERNEL);
1927             if (!rtt_results_header) {
1928                 ret = -ENOMEM;
1929                 goto exit;
1930             }
1931             /* Initialize the head of list for rtt result */
1932             INIT_LIST_HEAD(&rtt_results_header->result_list);
1933             rtt_results_header->peer_mac = event->addr;
1934             list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache);
1935 
1936             /* allocate rtt_results for new results */
1937             rtt_result = kzalloc(sizeof(rtt_result_t), kflags);
1938             if (!rtt_result) {
1939                 ret = -ENOMEM;
1940                 kfree(rtt_results_header);
1941                 goto exit;
1942             }
1943             /* fill out the results from the configuration param */
1944             rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst;
1945             rtt_result->report.type = RTT_TWO_WAY;
1946             DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num));
1947             rtt_result->report_len = RTT_REPORT_SIZE;
1948             rtt_result->report.status = RTT_REASON_FAIL_NO_RSP;
1949             rtt_result->report.addr = rtt_target_info->addr;
1950             rtt_result->report.distance = FTM_INVALID;
1951             list_add_tail(&rtt_result->list, &rtt_results_header->result_list);
1952             rtt_results_header->result_cnt++;
1953             rtt_results_header->result_tot_len += rtt_result->report_len;
1954         }
1955         /* find next target to trigger RTT */
1956         for (idx = (rtt_status->cur_idx + 1);
1957             idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
1958             /* skip the disabled device */
1959             if (rtt_status->rtt_config.target_info[idx].disable) {
1960                 continue;
1961             } else {
1962                 /* set the idx to cur_idx */
1963                 rtt_status->cur_idx = idx;
1964                 break;
1965             }
1966         }
1967         if (idx < rtt_status->rtt_config.rtt_target_cnt) {
1968             /* restart to measure RTT from next device */
1969             DHD_ERROR(("restart to measure rtt\n"));
1970             schedule_work(&rtt_status->work);
1971         } else {
1972             DHD_RTT(("RTT_STOPPED\n"));
1973             rtt_status->status = RTT_STOPPED;
1974             /* to turn on mpc mode */
1975             schedule_work(&rtt_status->work);
1976             /* notify the completed information to others */
1977 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1978 #pragma GCC diagnostic push
1979 #pragma GCC diagnostic ignored "-Wcast-qual"
1980 #endif
1981             list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
1982                 iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache);
1983             }
1984             /* remove the rtt results in cache */
1985             if (!list_empty(&rtt_status->rtt_results_cache)) {
1986                 /* Iterate rtt_results_header list */
1987                 list_for_each_entry_safe(entry, next,
1988                     &rtt_status->rtt_results_cache, list) {
1989                     list_del(&entry->list);
1990                     /* Iterate rtt_result list */
1991                     list_for_each_entry_safe(rtt_result, next2,
1992                         &entry->result_list, list) {
1993                         list_del(&rtt_result->list);
1994                         kfree(rtt_result);
1995                     }
1996                     kfree(entry);
1997                 }
1998             }
1999 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2000 #pragma GCC diagnostic pop
2001 #endif
2002             /* reinitialize the HEAD */
2003             INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
2004             /* clear information for rtt_config */
2005             rtt_status->rtt_config.rtt_target_cnt = 0;
2006             memset(rtt_status->rtt_config.target_info, 0,
2007                 TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT));
2008             rtt_status->cur_idx = 0;
2009         }
2010 #endif /* WL_CFG80211 */
2011         break;
2012     case WL_PROXD_EVENT_SESSION_RESTART:
2013         DHD_RTT(("WL_PROXD_EVENT_SESSION_RESTART\n"));
2014         break;
2015     case WL_PROXD_EVENT_BURST_RESCHED:
2016         DHD_RTT(("WL_PROXD_EVENT_BURST_RESCHED\n"));
2017         break;
2018     case WL_PROXD_EVENT_SESSION_DESTROY:
2019         DHD_RTT(("WL_PROXD_EVENT_SESSION_DESTROY\n"));
2020         break;
2021     case WL_PROXD_EVENT_FTM_FRAME:
2022         DHD_RTT(("WL_PROXD_EVENT_FTM_FRAME\n"));
2023         break;
2024     case WL_PROXD_EVENT_DELAY:
2025         DHD_RTT(("WL_PROXD_EVENT_DELAY\n"));
2026         break;
2027     case WL_PROXD_EVENT_VS_INITIATOR_RPT:
2028         DHD_RTT(("WL_PROXD_EVENT_VS_INITIATOR_RPT\n "));
2029         break;
2030     case WL_PROXD_EVENT_RANGING:
2031         DHD_RTT(("WL_PROXD_EVENT_RANGING\n"));
2032         break;
2033     case WL_PROXD_EVENT_COLLECT:
2034         DHD_RTT(("WL_PROXD_EVENT_COLLECT\n"));
2035         if (tlvs_len > 0) {
2036             collect_event_data = kzalloc(sizeof(wl_proxd_collect_event_data_t), kflags);
2037             if (!collect_event_data) {
2038                 ret = -ENOMEM;
2039                 goto exit;
2040             }
2041             /* unpack TLVs and invokes the cbfn to print the event content TLVs */
2042             ret = bcm_unpack_xtlv_buf((void *) collect_event_data,
2043                 (uint8 *)&p_event->tlvs[0], tlvs_len,
2044                 BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn);
2045             kfree(collect_event_data);
2046             if (ret != BCME_OK) {
2047                 DHD_ERROR(("%s : Failed to unpack xtlv for an event\n",
2048                     __FUNCTION__));
2049                 goto exit;
2050             }
2051         }
2052         break;
2053 
2054 
2055     default:
2056         DHD_ERROR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type));
2057         break;
2058     }
2059 exit:
2060 #ifdef WL_CFG80211
2061     if (!in_atomic()) {
2062         mutex_unlock(&rtt_status->rtt_mutex);
2063     }
2064 #endif /* WL_CFG80211 */
2065 
2066     return ret;
2067 }
2068 
2069 #ifdef WL_CFG80211
2070 static void
dhd_rtt_work(struct work_struct * work)2071 dhd_rtt_work(struct work_struct *work)
2072 {
2073     rtt_status_info_t *rtt_status;
2074     dhd_pub_t *dhd;
2075 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2076 #pragma GCC diagnostic push
2077 #pragma GCC diagnostic ignored "-Wcast-qual"
2078 #endif
2079     rtt_status = container_of(work, rtt_status_info_t, work);
2080 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2081 #pragma GCC diagnostic pop
2082 #endif
2083     if (rtt_status == NULL) {
2084         DHD_ERROR(("%s : rtt_status is NULL\n", __FUNCTION__));
2085         return;
2086     }
2087     dhd = rtt_status->dhd;
2088     if (dhd == NULL) {
2089         DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__));
2090         return;
2091     }
2092     (void) dhd_rtt_start(dhd);
2093 }
2094 #endif /* WL_CFG80211 */
2095 
2096 int
dhd_rtt_capability(dhd_pub_t * dhd,rtt_capabilities_t * capa)2097 dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa)
2098 {
2099     rtt_status_info_t *rtt_status;
2100     int err = BCME_OK;
2101     NULL_CHECK(dhd, "dhd is NULL", err);
2102     rtt_status = GET_RTTSTATE(dhd);
2103     NULL_CHECK(rtt_status, "rtt_status is NULL", err);
2104     NULL_CHECK(capa, "capa is NULL", err);
2105     bzero(capa, sizeof(rtt_capabilities_t));
2106 
2107     /* set rtt capabilities */
2108     if (rtt_status->rtt_capa.proto & RTT_CAP_ONE_WAY)
2109         capa->rtt_one_sided_supported = 1;
2110     if (rtt_status->rtt_capa.proto & RTT_CAP_FTM_WAY)
2111         capa->rtt_ftm_supported = 1;
2112 
2113     if (rtt_status->rtt_capa.feature & RTT_FEATURE_LCI)
2114         capa->lci_support = 1;
2115     if (rtt_status->rtt_capa.feature & RTT_FEATURE_LCR)
2116         capa->lcr_support = 1;
2117     if (rtt_status->rtt_capa.feature & RTT_FEATURE_PREAMBLE)
2118         capa->preamble_support = 1;
2119     if (rtt_status->rtt_capa.feature & RTT_FEATURE_BW)
2120         capa->bw_support = 1;
2121 
2122     /* bit mask */
2123     capa->preamble_support = rtt_status->rtt_capa.preamble;
2124     capa->bw_support = rtt_status->rtt_capa.bw;
2125 
2126     return err;
2127 }
2128 
2129 #ifdef WL_CFG80211
2130 int
dhd_rtt_avail_channel(dhd_pub_t * dhd,wifi_channel_info * channel_info)2131 dhd_rtt_avail_channel(dhd_pub_t *dhd, wifi_channel_info *channel_info)
2132 {
2133     u32 chanspec = 0;
2134     int err = BCME_OK;
2135     chanspec_t c = 0;
2136     u32 channel;
2137     struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
2138 
2139     if ((err = wldev_iovar_getint(dev, "chanspec",
2140         (s32 *)&chanspec)) == BCME_OK) {
2141         c = (chanspec_t)dtoh32(chanspec);
2142         c = wl_chspec_driver_to_host(c);
2143         channel  = wf_chspec_ctlchan(c);
2144         DHD_RTT((" control channel is %d \n", channel));
2145         if (CHSPEC_IS20(c)) {
2146             channel_info->width = WIFI_CHAN_WIDTH_20;
2147             DHD_RTT((" band is 20 \n"));
2148         } else if (CHSPEC_IS40(c)) {
2149             channel_info->width = WIFI_CHAN_WIDTH_40;
2150             DHD_RTT(("band is 40 \n"));
2151         } else {
2152             channel_info->width = WIFI_CHAN_WIDTH_80;
2153             DHD_RTT(("band is 80 \n"));
2154         }
2155         if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
2156             (channel <= CH_MAX_2G_CHANNEL)) {
2157             channel_info->center_freq =
2158                 ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
2159         } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
2160             channel_info->center_freq =
2161                 ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
2162         }
2163         if ((channel_info->width == WIFI_CHAN_WIDTH_80) ||
2164             (channel_info->width == WIFI_CHAN_WIDTH_40)) {
2165             channel = CHSPEC_CHANNEL(c);
2166             channel_info->center_freq0 =
2167                 ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
2168         }
2169     } else {
2170         DHD_ERROR(("Failed to get the chanspec \n"));
2171     }
2172     return err;
2173 }
2174 
2175 int
dhd_rtt_enable_responder(dhd_pub_t * dhd,wifi_channel_info * channel_info)2176 dhd_rtt_enable_responder(dhd_pub_t *dhd, wifi_channel_info *channel_info)
2177 {
2178     int err = BCME_OK;
2179     char chanbuf[CHANSPEC_STR_LEN];
2180     int pm = PM_OFF;
2181     int ftm_cfg_cnt = 0;
2182     chanspec_t chanspec;
2183     wifi_channel_info_t channel;
2184     struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
2185     ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS];
2186     ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS];
2187     rtt_status_info_t *rtt_status;
2188 
2189     memset(&channel, 0, sizeof(channel));
2190     BCM_REFERENCE(chanbuf);
2191     NULL_CHECK(dhd, "dhd is NULL", err);
2192     rtt_status = GET_RTTSTATE(dhd);
2193     NULL_CHECK(rtt_status, "rtt_status is NULL", err);
2194     if (RTT_IS_STOPPED(rtt_status)) {
2195         DHD_RTT(("STA responder/Target. \n"));
2196     }
2197     DHD_RTT(("Enter %s \n", __FUNCTION__));
2198     if (!dhd_is_associated(dhd, 0, NULL)) {
2199         if (channel_info) {
2200             channel.width = channel_info->width;
2201             channel.center_freq = channel_info->center_freq;
2202             channel.center_freq0 = channel_info->center_freq;
2203         }
2204         else {
2205             channel.width = WIFI_CHAN_WIDTH_80;
2206             channel.center_freq = DEFAULT_FTM_FREQ;
2207             channel.center_freq0 = DEFAULT_FTM_CNTR_FREQ0;
2208         }
2209         chanspec =  dhd_rtt_convert_to_chspec(channel);
2210         DHD_RTT(("chanspec/channel set as %s for rtt.\n",
2211             wf_chspec_ntoa(chanspec, chanbuf)));
2212         err = wldev_iovar_setint(dev, "chanspec", chanspec);
2213         if (err) {
2214             DHD_ERROR(("Failed to set the chanspec \n"));
2215         }
2216     }
2217     err = wldev_ioctl_get(dev, WLC_GET_PM, &rtt_status->pm, sizeof(rtt_status->pm));
2218     DHD_RTT(("Current PM value read %d\n", rtt_status->pm));
2219     if (err) {
2220         DHD_ERROR(("Failed to get the PM value \n"));
2221     } else {
2222         err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
2223         if (err) {
2224             DHD_ERROR(("Failed to set the PM \n"));
2225             rtt_status->pm_restore = FALSE;
2226         } else {
2227             rtt_status->pm_restore = TRUE;
2228         }
2229     }
2230     if (!RTT_IS_ENABLED(rtt_status)) {
2231         err = dhd_rtt_ftm_enable(dhd, TRUE);
2232         if (err) {
2233             DHD_ERROR(("Failed to enable FTM (%d)\n", err));
2234             goto exit;
2235         }
2236         DHD_RTT(("FTM enabled \n"));
2237     }
2238     rtt_status->status = RTT_ENABLED;
2239     DHD_RTT(("Responder enabled \n"));
2240     memset(ftm_configs, 0, sizeof(ftm_configs));
2241     memset(ftm_params, 0, sizeof(ftm_params));
2242     ftm_configs[ftm_cfg_cnt].enable = TRUE;
2243     ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_TARGET;
2244     rtt_status->flags = WL_PROXD_SESSION_FLAG_TARGET;
2245     DHD_RTT(("Set the device as responder \n"));
2246     err = dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS,
2247         ftm_configs, ftm_cfg_cnt);
2248 exit:
2249     if (err) {
2250         rtt_status->status = RTT_STOPPED;
2251         DHD_ERROR(("rtt is stopped  %s \n", __FUNCTION__));
2252         dhd_rtt_ftm_enable(dhd, FALSE);
2253         DHD_RTT(("restoring the PM value \n"));
2254         if (rtt_status->pm_restore) {
2255             pm = PM_FAST;
2256             err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
2257             if (err) {
2258                 DHD_ERROR(("Failed to restore PM \n"));
2259             } else {
2260                 rtt_status->pm_restore = FALSE;
2261             }
2262         }
2263     }
2264     return err;
2265 }
2266 
2267 int
dhd_rtt_cancel_responder(dhd_pub_t * dhd)2268 dhd_rtt_cancel_responder(dhd_pub_t *dhd)
2269 {
2270     int err = BCME_OK;
2271     rtt_status_info_t *rtt_status;
2272     int pm = 0;
2273     struct net_device *dev = dhd_linux_get_primary_netdev(dhd);
2274     NULL_CHECK(dhd, "dhd is NULL", err);
2275     rtt_status = GET_RTTSTATE(dhd);
2276     NULL_CHECK(rtt_status, "rtt_status is NULL", err);
2277     DHD_RTT(("Enter %s \n", __FUNCTION__));
2278     err = dhd_rtt_ftm_enable(dhd, FALSE);
2279     if (err) {
2280         DHD_ERROR(("failed to disable FTM (%d)\n", err));
2281     }
2282     rtt_status->status = RTT_STOPPED;
2283     if (rtt_status->pm_restore) {
2284         pm = PM_FAST;
2285         DHD_RTT(("pm_restore =%d \n", rtt_status->pm_restore));
2286         err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
2287         if (err) {
2288             DHD_ERROR(("Failed to restore PM \n"));
2289         } else {
2290             rtt_status->pm_restore = FALSE;
2291         }
2292     }
2293     return err;
2294 }
2295 #endif /* WL_CFG80211 */
2296 
2297 int
dhd_rtt_init(dhd_pub_t * dhd)2298 dhd_rtt_init(dhd_pub_t *dhd)
2299 {
2300     int err = BCME_OK;
2301 #ifdef WL_CFG80211
2302     int ret;
2303     int32 drv_up = 1;
2304     int32 version;
2305     rtt_status_info_t *rtt_status;
2306     NULL_CHECK(dhd, "dhd is NULL", err);
2307     dhd->rtt_supported = FALSE;
2308     if (dhd->rtt_state) {
2309         return err;
2310     }
2311     dhd->rtt_state = kzalloc(sizeof(rtt_status_info_t), GFP_KERNEL);
2312     if (dhd->rtt_state == NULL) {
2313         err = BCME_NOMEM;
2314         DHD_ERROR(("%s : failed to create rtt_state\n", __FUNCTION__));
2315         return err;
2316     }
2317     bzero(dhd->rtt_state, sizeof(rtt_status_info_t));
2318     rtt_status = GET_RTTSTATE(dhd);
2319     rtt_status->rtt_config.target_info =
2320             kzalloc(TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT), GFP_KERNEL);
2321     if (rtt_status->rtt_config.target_info == NULL) {
2322         DHD_ERROR(("%s failed to allocate the target info for %d\n",
2323             __FUNCTION__, RTT_MAX_TARGET_CNT));
2324         err = BCME_NOMEM;
2325         goto exit;
2326     }
2327     rtt_status->dhd = dhd;
2328     /* need to do WLC_UP  */
2329     dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&drv_up, sizeof(int32), TRUE, 0);
2330 
2331     ret = dhd_rtt_get_version(dhd, &version);
2332     if (ret == BCME_OK && (version == WL_PROXD_API_VERSION)) {
2333         DHD_ERROR(("%s : FTM is supported\n", __FUNCTION__));
2334         dhd->rtt_supported = TRUE;
2335         /* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */
2336         rtt_status->rtt_capa.proto |= RTT_CAP_FTM_WAY;
2337 
2338         /* indicate to set tx rate */
2339         rtt_status->rtt_capa.feature |= RTT_FEATURE_LCI;
2340         rtt_status->rtt_capa.feature |= RTT_FEATURE_LCR;
2341         rtt_status->rtt_capa.feature |= RTT_FEATURE_PREAMBLE;
2342         rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_VHT;
2343         rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_HT;
2344 
2345         /* indicate to set bandwith */
2346         rtt_status->rtt_capa.feature |= RTT_FEATURE_BW;
2347         rtt_status->rtt_capa.bw |= RTT_BW_20;
2348         rtt_status->rtt_capa.bw |= RTT_BW_40;
2349         rtt_status->rtt_capa.bw |= RTT_BW_80;
2350     } else {
2351         if ((ret != BCME_OK) || (version == 0)) {
2352             DHD_ERROR(("%s : FTM is not supported\n", __FUNCTION__));
2353         } else {
2354             DHD_ERROR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n",
2355                 __FUNCTION__, WL_PROXD_API_VERSION, version));
2356         }
2357     }
2358     /* cancel all of RTT request once we got the cancel request */
2359     rtt_status->all_cancel = TRUE;
2360     mutex_init(&rtt_status->rtt_mutex);
2361     INIT_LIST_HEAD(&rtt_status->noti_fn_list);
2362     INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
2363     INIT_WORK(&rtt_status->work, dhd_rtt_work);
2364 exit:
2365     if (err < 0) {
2366         kfree(rtt_status->rtt_config.target_info);
2367         kfree(dhd->rtt_state);
2368     }
2369 #endif /* WL_CFG80211 */
2370     return err;
2371 }
2372 
2373 int
dhd_rtt_deinit(dhd_pub_t * dhd)2374 dhd_rtt_deinit(dhd_pub_t *dhd)
2375 {
2376     int err = BCME_OK;
2377 #ifdef WL_CFG80211
2378     rtt_status_info_t *rtt_status;
2379     rtt_results_header_t *rtt_header, *next;
2380     rtt_result_t *rtt_result, *next2;
2381     struct rtt_noti_callback *iter, *iter2;
2382     NULL_CHECK(dhd, "dhd is NULL", err);
2383     rtt_status = GET_RTTSTATE(dhd);
2384     NULL_CHECK(rtt_status, "rtt_status is NULL", err);
2385     rtt_status->status = RTT_STOPPED;
2386     DHD_RTT(("rtt is stopped %s \n", __FUNCTION__));
2387     /* clear evt callback list */
2388 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2389 #pragma GCC diagnostic push
2390 #pragma GCC diagnostic ignored "-Wcast-qual"
2391 #endif
2392 
2393     if (!list_empty(&rtt_status->noti_fn_list)) {
2394         list_for_each_entry_safe(iter, iter2, &rtt_status->noti_fn_list, list) {
2395             list_del(&iter->list);
2396             kfree(iter);
2397         }
2398     }
2399     /* remove the rtt results */
2400     if (!list_empty(&rtt_status->rtt_results_cache)) {
2401         list_for_each_entry_safe(rtt_header, next, &rtt_status->rtt_results_cache, list) {
2402             list_del(&rtt_header->list);
2403             list_for_each_entry_safe(rtt_result, next2,
2404                 &rtt_header->result_list, list) {
2405                 list_del(&rtt_result->list);
2406                 kfree(rtt_result);
2407             }
2408             kfree(rtt_header);
2409         }
2410     }
2411 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2412 #pragma GCC diagnostic pop
2413 #endif
2414     kfree(rtt_status->rtt_config.target_info);
2415     kfree(dhd->rtt_state);
2416     dhd->rtt_state = NULL;
2417 #endif /* WL_CFG80211 */
2418     return err;
2419 }
2420