2 * Broadcom Dongle Host Driver (DHD), RTT
4 * Copyright (C) 1999-2017, Broadcom Corporation
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:
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.
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.
25 * <<Broadcom-WL-IPTag/Open:>>
35 #include <bcmendian.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>
48 #include <wldev_common.h>
50 #include <wl_cfg80211.h>
51 #endif /* WL_CFG80211 */
52 static DEFINE_SPINLOCK(noti_list_lock
);
53 #define NULL_CHECK(p, s, err) \
56 printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \
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)
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
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)
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
95 struct rtt_noti_callback
{
96 struct list_head list
;
98 dhd_rtt_compl_noti_fn noti_fn
;
102 /* bitmask indicating which command groups; */
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
109 /* proxd ftm config-category definition */
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
;
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) */
126 typedef struct ftm_config_options_info
{
127 uint32 flags
; /* wl_proxd_flags_t/wl_proxd_session_flags_t */
129 } ftm_config_options_info_t
;
131 typedef struct ftm_config_param_info
{
132 uint16 tlvid
; /* mapping TLV id for the item */
135 struct ether_addr mac_addr
;
136 wl_proxd_intvl_t data_intvl
;
141 } ftm_config_param_info_t
;
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
148 typedef struct ftm_strmap_entry
{
151 } ftm_strmap_entry_t
;
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
;
160 dhd_rtt_convert_results_to_host(rtt_report_t
*rtt_report
, uint8
*p_data
, uint16 tlvid
, uint16 len
);
163 dhd_rtt_convert_rate_to_host(uint32 ratespec
);
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};
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
}
198 /* ftm tlv-id mapping */
199 static const ftm_strmap_entry_t ftm_tlvid_loginfo
[] = {
200 /* { WL_PROXD_TLV_ID_xxx, "text for WL_PROXD_TLV_ID_xxx" }, */
201 { WL_PROXD_TLV_ID_NONE
, "none" },
202 { WL_PROXD_TLV_ID_METHOD
, "method" },
203 { WL_PROXD_TLV_ID_FLAGS
, "flags" },
204 { WL_PROXD_TLV_ID_CHANSPEC
, "chanspec" },
205 { WL_PROXD_TLV_ID_TX_POWER
, "tx power" },
206 { WL_PROXD_TLV_ID_RATESPEC
, "ratespec" },
207 { WL_PROXD_TLV_ID_BURST_DURATION
, "burst duration" },
208 { WL_PROXD_TLV_ID_BURST_PERIOD
, "burst period" },
209 { WL_PROXD_TLV_ID_BURST_FTM_SEP
, "burst ftm sep" },
210 { WL_PROXD_TLV_ID_BURST_NUM_FTM
, "burst num ftm" },
211 { WL_PROXD_TLV_ID_NUM_BURST
, "num burst" },
212 { WL_PROXD_TLV_ID_FTM_RETRIES
, "ftm retries" },
213 { WL_PROXD_TLV_ID_BSS_INDEX
, "BSS index" },
214 { WL_PROXD_TLV_ID_BSSID
, "bssid" },
215 { WL_PROXD_TLV_ID_INIT_DELAY
, "burst init delay" },
216 { WL_PROXD_TLV_ID_BURST_TIMEOUT
, "burst timeout" },
217 { WL_PROXD_TLV_ID_EVENT_MASK
, "event mask" },
218 { WL_PROXD_TLV_ID_FLAGS_MASK
, "flags mask" },
219 { WL_PROXD_TLV_ID_PEER_MAC
, "peer addr" },
220 { WL_PROXD_TLV_ID_FTM_REQ
, "ftm req" },
221 { WL_PROXD_TLV_ID_LCI_REQ
, "lci req" },
222 { WL_PROXD_TLV_ID_LCI
, "lci" },
223 { WL_PROXD_TLV_ID_CIVIC_REQ
, "civic req" },
224 { WL_PROXD_TLV_ID_CIVIC
, "civic" },
225 { WL_PROXD_TLV_ID_AVAIL
, "availability" },
226 { WL_PROXD_TLV_ID_SESSION_FLAGS
, "session flags" },
227 { WL_PROXD_TLV_ID_SESSION_FLAGS_MASK
, "session flags mask" },
228 { WL_PROXD_TLV_ID_RX_MAX_BURST
, "rx max bursts" },
229 { WL_PROXD_TLV_ID_RANGING_INFO
, "ranging info" },
230 { WL_PROXD_TLV_ID_RANGING_FLAGS
, "ranging flags" },
231 { WL_PROXD_TLV_ID_RANGING_FLAGS_MASK
, "ranging flags mask" },
232 /* output - 512 + x */
233 { WL_PROXD_TLV_ID_STATUS
, "status" },
234 { WL_PROXD_TLV_ID_COUNTERS
, "counters" },
235 { WL_PROXD_TLV_ID_INFO
, "info" },
236 { WL_PROXD_TLV_ID_RTT_RESULT
, "rtt result" },
237 { WL_PROXD_TLV_ID_AOA_RESULT
, "aoa result" },
238 { WL_PROXD_TLV_ID_SESSION_INFO
, "session info" },
239 { WL_PROXD_TLV_ID_SESSION_STATUS
, "session status" },
240 { WL_PROXD_TLV_ID_SESSION_ID_LIST
, "session ids" },
241 /* debug tlvs can be added starting 1024 */
242 { WL_PROXD_TLV_ID_DEBUG_MASK
, "debug mask" },
243 { WL_PROXD_TLV_ID_COLLECT
, "collect" },
244 { WL_PROXD_TLV_ID_STRBUF
, "result" },
245 { WL_PROXD_TLV_ID_COLLECT_DATA
, "collect-data" },
246 { WL_PROXD_TLV_ID_RI_RR
, "ri_rr" },
247 { WL_PROXD_TLV_ID_COLLECT_CHAN_DATA
, "chan est"}
250 static const ftm_strmap_entry_t ftm_event_type_loginfo
[] = {
251 /* wl_proxd_event_type_t, text-string */
252 { WL_PROXD_EVENT_NONE
, "none" },
253 { WL_PROXD_EVENT_SESSION_CREATE
, "session create" },
254 { WL_PROXD_EVENT_SESSION_START
, "session start" },
255 { WL_PROXD_EVENT_FTM_REQ
, "FTM req" },
256 { WL_PROXD_EVENT_BURST_START
, "burst start" },
257 { WL_PROXD_EVENT_BURST_END
, "burst end" },
258 { WL_PROXD_EVENT_SESSION_END
, "session end" },
259 { WL_PROXD_EVENT_SESSION_RESTART
, "session restart" },
260 { WL_PROXD_EVENT_BURST_RESCHED
, "burst rescheduled" },
261 { WL_PROXD_EVENT_SESSION_DESTROY
, "session destroy" },
262 { WL_PROXD_EVENT_RANGE_REQ
, "range request" },
263 { WL_PROXD_EVENT_FTM_FRAME
, "FTM frame" },
264 { WL_PROXD_EVENT_DELAY
, "delay" },
265 { WL_PROXD_EVENT_VS_INITIATOR_RPT
, "initiator-report " }, /* rx */
266 { WL_PROXD_EVENT_RANGING
, "ranging " },
267 { WL_PROXD_EVENT_COLLECT
, "collect" },
271 * session-state --> text string mapping
273 static const ftm_strmap_entry_t ftm_session_state_value_loginfo
[] = {
274 /* wl_proxd_session_state_t, text string */
275 { WL_PROXD_SESSION_STATE_CREATED
, "created" },
276 { WL_PROXD_SESSION_STATE_CONFIGURED
, "configured" },
277 { WL_PROXD_SESSION_STATE_STARTED
, "started" },
278 { WL_PROXD_SESSION_STATE_DELAY
, "delay" },
279 { WL_PROXD_SESSION_STATE_USER_WAIT
, "user-wait" },
280 { WL_PROXD_SESSION_STATE_SCHED_WAIT
, "sched-wait" },
281 { WL_PROXD_SESSION_STATE_BURST
, "burst" },
282 { WL_PROXD_SESSION_STATE_STOPPING
, "stopping" },
283 { WL_PROXD_SESSION_STATE_ENDED
, "ended" },
284 { WL_PROXD_SESSION_STATE_DESTROYING
, "destroying" },
285 { WL_PROXD_SESSION_STATE_NONE
, "none" }
289 * ranging-state --> text string mapping
291 static const ftm_strmap_entry_t ftm_ranging_state_value_loginfo
[] = {
292 /* wl_proxd_ranging_state_t, text string */
293 { WL_PROXD_RANGING_STATE_NONE
, "none" },
294 { WL_PROXD_RANGING_STATE_NOTSTARTED
, "nonstarted" },
295 { WL_PROXD_RANGING_STATE_INPROGRESS
, "inprogress" },
296 { WL_PROXD_RANGING_STATE_DONE
, "done" },
300 * status --> text string mapping
302 static const ftm_strmap_entry_t ftm_status_value_loginfo
[] = {
303 /* wl_proxd_status_t, text-string */
304 { WL_PROXD_E_OVERRIDDEN
, "overridden" },
305 { WL_PROXD_E_ASAP_FAILED
, "ASAP failed" },
306 { WL_PROXD_E_NOTSTARTED
, "not started" },
307 { WL_PROXD_E_INVALIDMEAS
, "invalid measurement" },
308 { WL_PROXD_E_INCAPABLE
, "incapable" },
309 { WL_PROXD_E_MISMATCH
, "mismatch"},
310 { WL_PROXD_E_DUP_SESSION
, "dup session" },
311 { WL_PROXD_E_REMOTE_FAIL
, "remote fail" },
312 { WL_PROXD_E_REMOTE_INCAPABLE
, "remote incapable" },
313 { WL_PROXD_E_SCHED_FAIL
, "sched failure" },
314 { WL_PROXD_E_PROTO
, "protocol error" },
315 { WL_PROXD_E_EXPIRED
, "expired" },
316 { WL_PROXD_E_TIMEOUT
, "timeout" },
317 { WL_PROXD_E_NOACK
, "no ack" },
318 { WL_PROXD_E_DEFERRED
, "deferred" },
319 { WL_PROXD_E_INVALID_SID
, "invalid session id" },
320 { WL_PROXD_E_REMOTE_CANCEL
, "remote cancel" },
321 { WL_PROXD_E_CANCELED
, "canceled" },
322 { WL_PROXD_E_INVALID_SESSION
, "invalid session" },
323 { WL_PROXD_E_BAD_STATE
, "bad state" },
324 { WL_PROXD_E_ERROR
, "error" },
325 { WL_PROXD_E_OK
, "OK" }
329 * time interval unit --> text string mapping
331 static const ftm_strmap_entry_t ftm_tmu_value_loginfo
[] = {
332 /* wl_proxd_tmu_t, text-string */
333 { WL_PROXD_TMU_TU
, "TU" },
334 { WL_PROXD_TMU_SEC
, "sec" },
335 { WL_PROXD_TMU_MILLI_SEC
, "ms" },
336 { WL_PROXD_TMU_MICRO_SEC
, "us" },
337 { WL_PROXD_TMU_NANO_SEC
, "ns" },
338 { WL_PROXD_TMU_PICO_SEC
, "ps" }
341 #define RSPEC_BW(rspec) ((rspec) & WL_RSPEC_BW_MASK)
342 #define RSPEC_IS20MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_20MHZ)
343 #define RSPEC_IS40MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_40MHZ)
344 #define RSPEC_IS80MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_80MHZ)
345 #define RSPEC_IS160MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_160MHZ)
347 #define IS_MCS(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) != WL_RSPEC_ENCODE_RATE)
348 #define IS_STBC(rspec) (((((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) || \
349 (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)) && \
350 (((rspec) & WL_RSPEC_STBC) == WL_RSPEC_STBC))
351 #define RSPEC_ISSGI(rspec) (((rspec) & WL_RSPEC_SGI) != 0)
352 #define RSPEC_ISLDPC(rspec) (((rspec) & WL_RSPEC_LDPC) != 0)
353 #define RSPEC_ISSTBC(rspec) (((rspec) & WL_RSPEC_STBC) != 0)
354 #define RSPEC_ISTXBF(rspec) (((rspec) & WL_RSPEC_TXBF) != 0)
355 #define RSPEC_ISVHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)
356 #define RSPEC_ISHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT)
357 #define RSPEC_ISLEGACY(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE)
358 #define RSPEC2RATE(rspec) (RSPEC_ISLEGACY(rspec) ? \
359 ((rspec) & RSPEC_RATE_MASK) : rate_rspec2rate(rspec))
360 /* return rate in unit of 500Kbps -- for internal use in wlc_rate_sel.c */
361 #define RSPEC2KBPS(rspec) rate_rspec2rate(rspec)
363 struct ieee_80211_mcs_rate_info
{
364 uint8 constellation_bits
;
369 static const struct ieee_80211_mcs_rate_info wl_mcs_info
[] = {
370 { 1, 1, 2 }, /* MCS 0: MOD: BPSK, CR 1/2 */
371 { 2, 1, 2 }, /* MCS 1: MOD: QPSK, CR 1/2 */
372 { 2, 3, 4 }, /* MCS 2: MOD: QPSK, CR 3/4 */
373 { 4, 1, 2 }, /* MCS 3: MOD: 16QAM, CR 1/2 */
374 { 4, 3, 4 }, /* MCS 4: MOD: 16QAM, CR 3/4 */
375 { 6, 2, 3 }, /* MCS 5: MOD: 64QAM, CR 2/3 */
376 { 6, 3, 4 }, /* MCS 6: MOD: 64QAM, CR 3/4 */
377 { 6, 5, 6 }, /* MCS 7: MOD: 64QAM, CR 5/6 */
378 { 8, 3, 4 }, /* MCS 8: MOD: 256QAM, CR 3/4 */
379 { 8, 5, 6 } /* MCS 9: MOD: 256QAM, CR 5/6 */
383 * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination.
384 * 'mcs' : a *single* spatial stream MCS (11n or 11ac)
387 rate_mcs2rate(uint mcs
, uint nss
, uint bw
, int sgi
)
389 const int ksps
= 250; /* kilo symbols per sec, 4 us sym */
390 const int Nsd_20MHz
= 52;
391 const int Nsd_40MHz
= 108;
392 const int Nsd_80MHz
= 234;
393 const int Nsd_160MHz
= 468;
397 /* just return fixed values for mcs32 instead of trying to parametrize */
398 rate
= (sgi
== 0) ? 6000 : 6778;
399 } else if (mcs
<= 9) {
400 /* This calculation works for 11n HT and 11ac VHT if the HT mcs values
401 * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8.
402 * That is, HT MCS 23 is a base MCS = 7, Nss = 3
405 /* find the number of complex numbers per symbol */
406 if (RSPEC_IS20MHZ(bw
)) {
408 } else if (RSPEC_IS40MHZ(bw
)) {
410 } else if (bw
== WL_RSPEC_BW_80MHZ
) {
412 } else if (bw
== WL_RSPEC_BW_160MHZ
) {
418 /* multiply by bits per number from the constellation in use */
419 rate
= rate
* wl_mcs_info
[mcs
].constellation_bits
;
421 /* adjust for the number of spatial streams */
424 /* adjust for the coding rate given as a quotient and divisor */
425 rate
= (rate
* wl_mcs_info
[mcs
].coding_q
) / wl_mcs_info
[mcs
].coding_d
;
427 /* multiply by Kilo symbols per sec to get Kbps */
430 /* adjust the symbols per sec for SGI
431 * symbol duration is 4 us without SGI, and 3.6 us with SGI,
435 /* add 4 for rounding of division by 9 */
436 rate
= ((rate
* 10) + 4) / 9;
443 } /* wlc_rate_mcs2rate */
445 /** take a well formed ratespec_t arg and return phy rate in [Kbps] units */
447 rate_rspec2rate(uint32 rspec
)
451 if (RSPEC_ISLEGACY(rspec
)) {
452 rate
= 500 * (rspec
& WL_RSPEC_RATE_MASK
);
453 } else if (RSPEC_ISHT(rspec
)) {
454 uint mcs
= (rspec
& WL_RSPEC_RATE_MASK
);
457 rate
= rate_mcs2rate(mcs
, 1, WL_RSPEC_BW_40MHZ
, RSPEC_ISSGI(rspec
));
459 uint nss
= 1 + (mcs
/ 8);
461 rate
= rate_mcs2rate(mcs
, nss
, RSPEC_BW(rspec
), RSPEC_ISSGI(rspec
));
463 } else if (RSPEC_ISVHT(rspec
)) {
464 uint mcs
= (rspec
& WL_RSPEC_VHT_MCS_MASK
);
465 uint nss
= (rspec
& WL_RSPEC_VHT_NSS_MASK
) >> WL_RSPEC_VHT_NSS_SHIFT
;
470 rate
= rate_mcs2rate(mcs
, nss
, RSPEC_BW(rspec
), RSPEC_ISSGI(rspec
));
475 return (rate
== 0) ? -1 : rate
;
478 char resp_buf
[WLC_IOCTL_SMLEN
];
481 ftm_intvl2nsec(const wl_proxd_intvl_t
*intvl
)
485 switch (intvl
->tmu
) {
486 case WL_PROXD_TMU_TU
: ret
= FTM_TU2MICRO(ret
) * 1000; break;
487 case WL_PROXD_TMU_SEC
: ret
*= 1000000000; break;
488 case WL_PROXD_TMU_MILLI_SEC
: ret
*= 1000000; break;
489 case WL_PROXD_TMU_MICRO_SEC
: ret
*= 1000; break;
490 case WL_PROXD_TMU_PICO_SEC
: ret
= intvl
->intvl
/ 1000; break;
491 case WL_PROXD_TMU_NANO_SEC
: /* fall through */
497 ftm_intvl2usec(const wl_proxd_intvl_t
*intvl
)
501 switch (intvl
->tmu
) {
502 case WL_PROXD_TMU_TU
: ret
= FTM_TU2MICRO(ret
); break;
503 case WL_PROXD_TMU_SEC
: ret
*= 1000000; break;
504 case WL_PROXD_TMU_NANO_SEC
: ret
= intvl
->intvl
/ 1000; break;
505 case WL_PROXD_TMU_PICO_SEC
: ret
= intvl
->intvl
/ 1000000; break;
506 case WL_PROXD_TMU_MILLI_SEC
: ret
*= 1000; break;
507 case WL_PROXD_TMU_MICRO_SEC
: /* fall through */
514 * lookup 'id' (as a key) from a fw status to host map table
515 * if found, return the corresponding reason code
519 ftm_get_statusmap_info(wl_proxd_status_t id
, const ftm_status_map_host_entry_t
*p_table
,
523 const ftm_status_map_host_entry_t
*p_entry
;
524 /* scan thru the table till end */
526 for (i
= 0; i
< (int) num_entries
; i
++)
528 if (p_entry
->proxd_status
== id
) {
529 return p_entry
->rtt_reason
;
531 p_entry
++; /* next entry */
533 return RTT_REASON_FAILURE
; /* not found */
536 * lookup 'id' (as a key) from a table
537 * if found, return the entry pointer, otherwise return NULL
539 static const ftm_strmap_entry_t
*
540 ftm_get_strmap_info(int32 id
, const ftm_strmap_entry_t
*p_table
, uint32 num_entries
)
543 const ftm_strmap_entry_t
*p_entry
;
545 /* scan thru the table till end */
547 for (i
= 0; i
< (int) num_entries
; i
++)
549 if (p_entry
->id
== id
)
551 p_entry
++; /* next entry */
553 return NULL
; /* not found */
557 * map enum to a text-string for display, this function is called by the following:
559 * ftm_[cmdid|tlvid]_to_str()
560 * For TLV-output log for 'get' commands
561 * ftm_[method|tmu|caps|status|state]_value_to_logstr()
563 * pTable -- point to a 'enum to string' table.
566 ftm_map_id_to_str(int32 id
, const ftm_strmap_entry_t
*p_table
, uint32 num_entries
)
568 const ftm_strmap_entry_t
*p_entry
= ftm_get_strmap_info(id
, p_table
, num_entries
);
570 return (p_entry
->text
);
578 /* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */
579 #define DEF_STRMAP_ENTRY(id) { (id), #id }
581 /* ftm cmd-id mapping */
582 static const ftm_strmap_entry_t ftm_cmdid_map
[] = {
583 /* {wl_proxd_cmd_t(WL_PROXD_CMD_xxx), "WL_PROXD_CMD_xxx" }, */
584 DEF_STRMAP_ENTRY(WL_PROXD_CMD_NONE
),
585 DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_VERSION
),
586 DEF_STRMAP_ENTRY(WL_PROXD_CMD_ENABLE
),
587 DEF_STRMAP_ENTRY(WL_PROXD_CMD_DISABLE
),
588 DEF_STRMAP_ENTRY(WL_PROXD_CMD_CONFIG
),
589 DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_SESSION
),
590 DEF_STRMAP_ENTRY(WL_PROXD_CMD_BURST_REQUEST
),
591 DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_SESSION
),
592 DEF_STRMAP_ENTRY(WL_PROXD_CMD_DELETE_SESSION
),
593 DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RESULT
),
594 DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_INFO
),
595 DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_STATUS
),
596 DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_SESSIONS
),
597 DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_COUNTERS
),
598 DEF_STRMAP_ENTRY(WL_PROXD_CMD_CLEAR_COUNTERS
),
599 DEF_STRMAP_ENTRY(WL_PROXD_CMD_COLLECT
),
600 DEF_STRMAP_ENTRY(WL_PROXD_CMD_TUNE
),
601 DEF_STRMAP_ENTRY(WL_PROXD_CMD_DUMP
),
602 DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_RANGING
),
603 DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_RANGING
),
604 DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RANGING_INFO
),
608 * map a ftm cmd-id to a text-string for display
611 ftm_cmdid_to_str(uint16 cmdid
)
613 return ftm_map_id_to_str((int32
) cmdid
, &ftm_cmdid_map
[0], ARRAYSIZE(ftm_cmdid_map
));
615 #endif /* RTT_DEBUG */
619 * convert BCME_xxx error codes into related error strings
620 * note, bcmerrorstr() defined in bcmutils is for BCMDRIVER only,
621 * this duplicate copy is for WL access and may need to clean up later
623 static const char *ftm_bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
625 ftm_status_value_to_logstr(wl_proxd_status_t status
)
627 static char ftm_msgbuf_status_undef
[32];
628 const ftm_strmap_entry_t
*p_loginfo
;
631 /* check if within BCME_xxx error range */
632 bcmerror
= (int) status
;
633 if (VALID_BCMERROR(bcmerror
))
634 return ftm_bcmerrorstrtable
[-bcmerror
];
636 /* otherwise, look for 'proxd ftm status' range */
637 p_loginfo
= ftm_get_strmap_info((int32
) status
,
638 &ftm_status_value_loginfo
[0], ARRAYSIZE(ftm_status_value_loginfo
));
640 return p_loginfo
->text
;
642 /* report for 'out of range' FTM-status error code */
643 memset(ftm_msgbuf_status_undef
, 0, sizeof(ftm_msgbuf_status_undef
));
644 snprintf(ftm_msgbuf_status_undef
, sizeof(ftm_msgbuf_status_undef
),
645 "Undefined status %d", status
);
646 return &ftm_msgbuf_status_undef
[0];
650 ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu
)
652 return ftm_map_id_to_str((int32
)tmu
,
653 &ftm_tmu_value_loginfo
[0], ARRAYSIZE(ftm_tmu_value_loginfo
));
656 static const ftm_strmap_entry_t
*
657 ftm_get_event_type_loginfo(wl_proxd_event_type_t event_type
)
659 /* look up 'event-type' from a predefined table */
660 return ftm_get_strmap_info((int32
) event_type
,
661 ftm_event_type_loginfo
, ARRAYSIZE(ftm_event_type_loginfo
));
665 ftm_session_state_value_to_logstr(wl_proxd_session_state_t state
)
667 return ftm_map_id_to_str((int32
)state
, &ftm_session_state_value_loginfo
[0],
668 ARRAYSIZE(ftm_session_state_value_loginfo
));
674 * send 'proxd' iovar for all ftm get-related commands
677 rtt_do_get_ioctl(dhd_pub_t
*dhd
, wl_proxd_iov_t
*p_proxd_iov
, uint16 proxd_iovsize
,
678 ftm_subcmd_info_t
*p_subcmd_info
)
681 wl_proxd_iov_t
*p_iovresp
= (wl_proxd_iov_t
*)resp_buf
;
684 /* send getbuf proxd iovar */
685 status
= dhd_getiovar(dhd
, 0, "proxd", (char *)p_proxd_iov
,
686 proxd_iovsize
, (char **)&p_iovresp
, WLC_IOCTL_SMLEN
);
687 if (status
!= BCME_OK
) {
688 DHD_ERROR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n",
689 __FUNCTION__
, p_subcmd_info
->cmdid
, status
));
692 if (p_subcmd_info
->cmdid
== WL_PROXD_CMD_GET_VERSION
) {
693 p_subcmd_info
->version
= ltoh16(p_iovresp
->version
);
694 DHD_RTT(("ftm version: 0x%x\n", ltoh16(p_iovresp
->version
)));
698 tlvs_len
= ltoh16(p_iovresp
->len
) - WL_PROXD_IOV_HDR_SIZE
;
700 DHD_ERROR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n",
701 __FUNCTION__
, ltoh16(p_iovresp
->len
), (int) WL_PROXD_IOV_HDR_SIZE
));
705 if (tlvs_len
> 0 && p_subcmd_info
->handler
) {
706 /* unpack TLVs and invokes the cbfn for processing */
707 status
= bcm_unpack_xtlv_buf(p_proxd_iov
, (uint8
*)p_iovresp
->tlvs
,
708 tlvs_len
, BCM_XTLV_OPTION_ALIGN32
, p_subcmd_info
->handler
);
715 static wl_proxd_iov_t
*
716 rtt_alloc_getset_buf(wl_proxd_method_t method
, wl_proxd_session_id_t session_id
,
717 wl_proxd_cmd_t cmdid
, uint16 tlvs_bufsize
, uint16
*p_out_bufsize
)
719 uint16 proxd_iovsize
;
721 wl_proxd_tlv_t
*p_tlv
;
722 wl_proxd_iov_t
*p_proxd_iov
= (wl_proxd_iov_t
*) NULL
;
724 *p_out_bufsize
= 0; /* init */
725 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
726 /* calculate the whole buffer size, including one reserve-tlv entry in the header */
727 proxd_iovsize
= sizeof(wl_proxd_iov_t
) + tlvs_bufsize
;
729 p_proxd_iov
= kzalloc(proxd_iovsize
, kflags
);
730 if (p_proxd_iov
== NULL
) {
731 DHD_ERROR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize
));
735 /* setup proxd-FTM-method iovar header */
736 p_proxd_iov
->version
= htol16(WL_PROXD_API_VERSION
);
737 p_proxd_iov
->len
= htol16(proxd_iovsize
); /* caller may adjust it based on #of TLVs */
738 p_proxd_iov
->cmd
= htol16(cmdid
);
739 p_proxd_iov
->method
= htol16(method
);
740 p_proxd_iov
->sid
= htol16(session_id
);
742 /* initialize the reserved/dummy-TLV in iovar header */
743 p_tlv
= p_proxd_iov
->tlvs
;
744 p_tlv
->id
= htol16(WL_PROXD_TLV_ID_NONE
);
745 p_tlv
->len
= htol16(0);
747 *p_out_bufsize
= proxd_iovsize
; /* for caller's reference */
754 dhd_rtt_common_get_handler(dhd_pub_t
*dhd
, ftm_subcmd_info_t
*p_subcmd_info
,
755 wl_proxd_method_t method
,
756 wl_proxd_session_id_t session_id
)
758 int status
= BCME_OK
;
759 uint16 proxd_iovsize
= 0;
760 wl_proxd_iov_t
*p_proxd_iov
;
762 DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
763 __FUNCTION__
, method
, session_id
, p_subcmd_info
->cmdid
,
764 ftm_cmdid_to_str(p_subcmd_info
->cmdid
)));
766 /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */
767 p_proxd_iov
= rtt_alloc_getset_buf(method
, session_id
, p_subcmd_info
->cmdid
,
770 if (p_proxd_iov
== NULL
)
773 status
= rtt_do_get_ioctl(dhd
, p_proxd_iov
, proxd_iovsize
, p_subcmd_info
);
775 if (status
!= BCME_OK
) {
776 DHD_RTT(("%s failed: status=%d\n", __FUNCTION__
, status
));
783 * common handler for set-related proxd method commands which require no TLV as input
784 * wl proxd ftm [session-id] <set-subcmd>
786 * wl proxd ftm enable -- to enable ftm
787 * wl proxd ftm disable -- to disable ftm
788 * wl proxd ftm <session-id> start -- to start a specified session
789 * wl proxd ftm <session-id> stop -- to cancel a specified session;
790 * state is maintained till session is delete.
791 * wl proxd ftm <session-id> delete -- to delete a specified session
792 * wl proxd ftm [<session-id>] clear-counters -- to clear counters
793 * wl proxd ftm <session-id> burst-request -- on initiator: to send burst request;
794 * on target: send FTM frame
795 * wl proxd ftm <session-id> collect
796 * wl proxd ftm tune (TBD)
799 dhd_rtt_common_set_handler(dhd_pub_t
*dhd
, const ftm_subcmd_info_t
*p_subcmd_info
,
800 wl_proxd_method_t method
, wl_proxd_session_id_t session_id
)
802 uint16 proxd_iovsize
;
803 wl_proxd_iov_t
*p_proxd_iov
;
807 DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n",
808 __FUNCTION__
, method
, session_id
, p_subcmd_info
->cmdid
,
809 ftm_cmdid_to_str(p_subcmd_info
->cmdid
)));
812 /* allocate and initialize a temp buffer for 'set proxd' iovar */
814 p_proxd_iov
= rtt_alloc_getset_buf(method
, session_id
, p_subcmd_info
->cmdid
,
815 0, &proxd_iovsize
); /* no TLV */
816 if (p_proxd_iov
== NULL
)
819 /* no TLV to pack, simply issue a set-proxd iovar */
820 ret
= dhd_iovar(dhd
, 0, "proxd", (char *)p_proxd_iov
, proxd_iovsize
, NULL
, 0, TRUE
);
822 if (ret
!= BCME_OK
) {
823 DHD_RTT(("error: IOVAR failed, status=%d\n", ret
));
831 #endif /* WL_CFG80211 */
834 rtt_unpack_xtlv_cbfn(void *ctx
, uint8
*p_data
, uint16 tlvid
, uint16 len
)
838 wl_proxd_ftm_session_status_t
*p_data_info
= NULL
;
839 wl_proxd_collect_event_data_t
*p_collect_data
= NULL
;
840 uint32 chan_data_entry
= 0;
843 case WL_PROXD_TLV_ID_RTT_RESULT
:
844 ret
= dhd_rtt_convert_results_to_host((rtt_report_t
*)ctx
,
847 case WL_PROXD_TLV_ID_SESSION_STATUS
:
848 DHD_RTT(("WL_PROXD_TLV_ID_SESSION_STATUS\n"));
849 memcpy(ctx
, p_data
, sizeof(wl_proxd_ftm_session_status_t
));
850 p_data_info
= (wl_proxd_ftm_session_status_t
*)ctx
;
851 p_data_info
->sid
= ltoh16_ua(&p_data_info
->sid
);
852 p_data_info
->state
= ltoh16_ua(&p_data_info
->state
);
853 p_data_info
->status
= ltoh32_ua(&p_data_info
->status
);
854 p_data_info
->burst_num
= ltoh16_ua(&p_data_info
->burst_num
);
855 DHD_RTT(("\tsid=%u, state=%d, status=%d, burst_num=%u\n",
856 p_data_info
->sid
, p_data_info
->state
,
857 p_data_info
->status
, p_data_info
->burst_num
));
860 case WL_PROXD_TLV_ID_COLLECT_DATA
:
861 DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_DATA\n"));
862 memcpy(ctx
, p_data
, sizeof(wl_proxd_collect_event_data_t
));
863 p_collect_data
= (wl_proxd_collect_event_data_t
*)ctx
;
864 DHD_RTT(("\tH_RX\n"));
865 for (i
= 0; i
< K_TOF_COLLECT_H_SIZE_20MHZ
; i
++) {
866 p_collect_data
->H_RX
[i
] = ltoh32_ua(&p_collect_data
->H_RX
[i
]);
867 DHD_RTT(("\t%u\n", p_collect_data
->H_RX
[i
]));
870 DHD_RTT(("\tH_LB\n"));
871 for (i
= 0; i
< K_TOF_COLLECT_H_SIZE_20MHZ
; i
++) {
872 p_collect_data
->H_LB
[i
] = ltoh32_ua(&p_collect_data
->H_LB
[i
]);
873 DHD_RTT(("\t%u\n", p_collect_data
->H_LB
[i
]));
876 DHD_RTT(("\tri_rr\n"));
877 for (i
= 0; i
< FTM_TPK_RI_RR_LEN
; i
++) {
878 DHD_RTT(("\t%u\n", p_collect_data
->ri_rr
[i
]));
880 p_collect_data
->phy_err_mask
= ltoh32_ua(&p_collect_data
->phy_err_mask
);
881 DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data
->phy_err_mask
));
883 case WL_PROXD_TLV_ID_COLLECT_CHAN_DATA
:
884 DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_CHAN_DATA\n"));
885 DHD_RTT(("\tchan est %u\n", (uint32
) (len
/ sizeof(uint32
))));
886 for (i
= 0; i
< (len
/sizeof(chan_data_entry
)); i
++) {
887 uint32
*p
= (uint32
*)p_data
;
888 chan_data_entry
= ltoh32_ua(p
+ i
);
889 DHD_RTT(("\t%u\n", chan_data_entry
));
893 DHD_ERROR(("> Unsupported TLV ID %d\n", tlvid
));
903 rtt_handle_config_options(wl_proxd_session_id_t session_id
, wl_proxd_tlv_t
**p_tlv
,
904 uint16
*p_buf_space_left
, ftm_config_options_info_t
*ftm_configs
, int ftm_cfg_cnt
)
908 uint32 flags
= WL_PROXD_FLAG_NONE
;
909 uint32 flags_mask
= WL_PROXD_FLAG_NONE
;
910 uint32 new_mask
; /* cmdline input */
911 ftm_config_options_info_t
*p_option_info
;
912 uint16 type
= (session_id
== WL_PROXD_SESSION_ID_GLOBAL
) ?
913 WL_PROXD_TLV_ID_FLAGS_MASK
: WL_PROXD_TLV_ID_SESSION_FLAGS_MASK
;
914 for (cfg_idx
= 0; cfg_idx
< ftm_cfg_cnt
; cfg_idx
++) {
915 p_option_info
= (ftm_configs
+ cfg_idx
);
916 if (p_option_info
!= NULL
) {
917 new_mask
= p_option_info
->flags
;
918 /* update flags mask */
919 flags_mask
|= new_mask
;
920 if (p_option_info
->enable
) {
921 flags
|= new_mask
; /* set the bit on */
923 flags
&= ~new_mask
; /* set the bit off */
927 flags
= htol32(flags
);
928 flags_mask
= htol32(flags_mask
);
929 /* setup flags_mask TLV */
930 ret
= bcm_pack_xtlv_entry((uint8
**)p_tlv
, p_buf_space_left
,
931 type
, sizeof(uint32
), &flags_mask
, BCM_XTLV_OPTION_ALIGN32
);
932 if (ret
!= BCME_OK
) {
933 DHD_ERROR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n",
938 type
= (session_id
== WL_PROXD_SESSION_ID_GLOBAL
)?
939 WL_PROXD_TLV_ID_FLAGS
: WL_PROXD_TLV_ID_SESSION_FLAGS
;
940 /* setup flags TLV */
941 ret
= bcm_pack_xtlv_entry((uint8
**)p_tlv
, p_buf_space_left
,
942 type
, sizeof(uint32
), &flags
, BCM_XTLV_OPTION_ALIGN32
);
943 if (ret
!= BCME_OK
) {
945 DHD_RTT(("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n",
954 rtt_handle_config_general(wl_proxd_session_id_t session_id
, wl_proxd_tlv_t
**p_tlv
,
955 uint16
*p_buf_space_left
, ftm_config_param_info_t
*ftm_configs
, int ftm_cfg_cnt
)
960 ftm_config_param_info_t
*p_config_param_info
;
962 uint16 src_data_size
; /* size of data pointed by p_src_data as 'source' */
963 for (cfg_idx
= 0; cfg_idx
< ftm_cfg_cnt
; cfg_idx
++) {
964 p_config_param_info
= (ftm_configs
+ cfg_idx
);
965 if (p_config_param_info
!= NULL
) {
966 switch (p_config_param_info
->tlvid
) {
967 case WL_PROXD_TLV_ID_BSS_INDEX
:
968 case WL_PROXD_TLV_ID_FTM_RETRIES
:
969 case WL_PROXD_TLV_ID_FTM_REQ_RETRIES
:
970 p_src_data
= &p_config_param_info
->data8
;
971 src_data_size
= sizeof(uint8
);
973 case WL_PROXD_TLV_ID_BURST_NUM_FTM
: /* uint16 */
974 case WL_PROXD_TLV_ID_NUM_BURST
:
975 case WL_PROXD_TLV_ID_RX_MAX_BURST
:
976 p_src_data
= &p_config_param_info
->data16
;
977 src_data_size
= sizeof(uint16
);
979 case WL_PROXD_TLV_ID_TX_POWER
: /* uint32 */
980 case WL_PROXD_TLV_ID_RATESPEC
:
981 case WL_PROXD_TLV_ID_EVENT_MASK
: /* wl_proxd_event_mask_t/uint32 */
982 case WL_PROXD_TLV_ID_DEBUG_MASK
:
983 p_src_data
= &p_config_param_info
->data32
;
984 src_data_size
= sizeof(uint32
);
986 case WL_PROXD_TLV_ID_CHANSPEC
: /* chanspec_t --> 32bit */
987 chanspec
= p_config_param_info
->chanspec
;
988 p_src_data
= (void *) &chanspec
;
989 src_data_size
= sizeof(uint32
);
991 case WL_PROXD_TLV_ID_BSSID
: /* mac address */
992 case WL_PROXD_TLV_ID_PEER_MAC
:
993 p_src_data
= &p_config_param_info
->mac_addr
;
994 src_data_size
= sizeof(struct ether_addr
);
996 case WL_PROXD_TLV_ID_BURST_DURATION
: /* wl_proxd_intvl_t */
997 case WL_PROXD_TLV_ID_BURST_PERIOD
:
998 case WL_PROXD_TLV_ID_BURST_FTM_SEP
:
999 case WL_PROXD_TLV_ID_BURST_TIMEOUT
:
1000 case WL_PROXD_TLV_ID_INIT_DELAY
:
1001 p_src_data
= &p_config_param_info
->data_intvl
;
1002 src_data_size
= sizeof(wl_proxd_intvl_t
);
1008 if (ret
!= BCME_OK
) {
1009 DHD_ERROR(("%s bad TLV ID : %d\n",
1010 __FUNCTION__
, p_config_param_info
->tlvid
));
1014 ret
= bcm_pack_xtlv_entry((uint8
**) p_tlv
, p_buf_space_left
,
1015 p_config_param_info
->tlvid
, src_data_size
, p_src_data
,
1016 BCM_XTLV_OPTION_ALIGN32
);
1017 if (ret
!= BCME_OK
) {
1018 DHD_ERROR(("%s: bcm_pack_xltv_entry() failed,"
1019 " status=%d\n", __FUNCTION__
, ret
));
1029 dhd_rtt_ftm_enable(dhd_pub_t
*dhd
, bool enable
)
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
);
1040 dhd_rtt_start_session(dhd_pub_t
*dhd
, wl_proxd_session_id_t session_id
, bool start
)
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
);
1051 dhd_rtt_delete_session(dhd_pub_t
*dhd
, wl_proxd_session_id_t session_id
)
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
);
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
)
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;
1071 uint16 buf_space_left
;
1075 subcmd_info
.name
= "config";
1076 subcmd_info
.cmdid
= WL_PROXD_CMD_CONFIG
;
1078 p_proxd_iov
= rtt_alloc_getset_buf(WL_PROXD_METHOD_FTM
, session_id
, subcmd_info
.cmdid
,
1079 FTM_IOC_BUFSZ
, &proxd_iovsize
);
1081 if (p_proxd_iov
== NULL
) {
1082 DHD_ERROR(("%s : failed to allocate the iovar (size :%d)\n",
1083 __FUNCTION__
, FTM_IOC_BUFSZ
));
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
);
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__
));
1114 dhd_rtt_get_version(dhd_pub_t
*dhd
, int *out_version
)
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;
1126 #endif /* WL_CFG80211 */
1129 dhd_rtt_convert_to_chspec(wifi_channel_info_t channel
)
1132 chanspec_t chanspec
= 0;
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
;
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
);
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
);
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
);
1157 DHD_ERROR(("doesn't support this bandwith : %d", channel
.width
));
1165 dhd_rtt_idx_to_burst_duration(uint idx
)
1167 if (idx
>= ARRAY_SIZE(burst_duration_idx
)) {
1170 return burst_duration_idx
[idx
];
1174 dhd_rtt_set_cfg(dhd_pub_t
*dhd
, rtt_config_params_t
*params
)
1178 rtt_status_info_t
*rtt_status
;
1179 NULL_CHECK(params
, "params is NULL", err
);
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"));
1188 if (rtt_status
->status
!= RTT_STOPPED
) {
1189 DHD_ERROR(("rtt is already started\n"));
1192 DHD_RTT(("%s enter\n", __FUNCTION__
));
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
) {
1206 /* set the idx to cur_idx */
1207 rtt_status
->cur_idx
= idx
;
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
);
1219 dhd_rtt_stop(dhd_pub_t
*dhd
, struct ether_addr
*mac_list
, int mac_cnt
)
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
;
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"));
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
,
1242 rtt_status
->rtt_config
.target_info
[j
].disable
= TRUE
;
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"
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
);
1268 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1269 #pragma GCC diagnostic pop
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"
1277 list_for_each_entry(iter
, &rtt_status
->noti_fn_list
, list
) {
1278 iter
->noti_fn(iter
->ctx
, &rtt_status
->rtt_results_cache
);
1280 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1281 #pragma GCC diagnostic pop
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
);
1293 mutex_unlock(&rtt_status
->rtt_mutex
);
1294 #endif /* WL_CFG80211 */
1301 dhd_rtt_start(dhd_pub_t
*dhd
)
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;
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
;
1314 struct net_device
*dev
= dhd_linux_get_primary_netdev(dhd
);
1315 NULL_CHECK(dhd
, "dhd is NULL", err
);
1317 rtt_status
= GET_RTTSTATE(dhd
);
1318 NULL_CHECK(rtt_status
, "rtt_status is NULL", err
);
1320 DHD_RTT(("Enter %s\n", __FUNCTION__
));
1321 if (rtt_status
->cur_idx
>= rtt_status
->rtt_config
.rtt_target_cnt
) {
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"));
1330 if (RTT_IS_STOPPED(rtt_status
)) {
1331 DHD_RTT(("RTT is stopped\n"));
1334 err
= wldev_ioctl_get(dev
, WLC_GET_PM
, &rtt_status
->pm
, sizeof(rtt_status
->pm
));
1336 DHD_ERROR(("Failed to get the PM value\n"));
1338 err
= wldev_ioctl_set(dev
, WLC_SET_PM
, &pm
, sizeof(pm
));
1340 DHD_ERROR(("Failed to set the PM\n"));
1341 rtt_status
->pm_restore
= FALSE
;
1343 rtt_status
->pm_restore
= TRUE
;
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
)) {
1354 err
= dhd_rtt_ftm_enable(dhd
, TRUE
);
1356 DHD_ERROR(("failed to enable FTM (%d)\n", err
));
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
));
1367 rtt_status
->status
= RTT_ENABLED
;
1368 memset(ftm_configs
, 0, sizeof(ftm_configs
));
1369 memset(ftm_params
, 0, sizeof(ftm_params
));
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
));
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
));
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
));
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
;
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
));
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
));
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
));
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
));
1435 if (rtt_target
->bw
&& rtt_target
->preamble
) {
1436 bool use_default
= FALSE
;
1439 switch (rtt_target
->preamble
) {
1440 case RTT_PREAMBLE_LEGACY
:
1441 rspec
|= WL_RSPEC_ENCODE_RATE
; /* 11abg */
1442 rspec
|= WL_RATE_6M
;
1444 case RTT_PREAMBLE_HT
:
1445 rspec
|= WL_RSPEC_ENCODE_HT
; /* 11n HT */
1446 mcs
= 0; /* default MCS 0 */
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
;
1456 DHD_RTT(("doesn't support this preamble : %d\n", rtt_target
->preamble
));
1460 switch (rtt_target
->bw
) {
1462 rspec
|= WL_RSPEC_BW_20MHZ
;
1465 rspec
|= WL_RSPEC_BW_40MHZ
;
1468 rspec
|= WL_RSPEC_BW_80MHZ
;
1471 DHD_RTT(("doesn't support this BW : %d\n", rtt_target
->bw
));
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
));
1482 dhd_set_rand_mac_oui(dhd
);
1483 dhd_rtt_ftm_config(dhd
, FTM_DEFAULT_SESSION
, FTM_CONFIG_CAT_GENERAL
,
1484 ftm_params
, ftm_param_cnt
);
1486 err
= dhd_rtt_start_session(dhd
, FTM_DEFAULT_SESSION
, TRUE
);
1488 DHD_ERROR(("failed to start session of FTM : error %d\n", err
));
1492 DHD_ERROR(("rtt is stopped %s \n", __FUNCTION__
));
1493 rtt_status
->status
= RTT_STOPPED
;
1495 dhd_rtt_ftm_enable(dhd
, FALSE
);
1496 if (rtt_status
->pm_restore
) {
1497 DHD_ERROR(("pm_restore =%d func =%s \n",
1498 rtt_status
->pm_restore
, __FUNCTION__
));
1500 err
= wldev_ioctl_set(dev
, WLC_SET_PM
, &pm
, sizeof(pm
));
1502 DHD_ERROR(("Failed to set PM \n"));
1504 rtt_status
->pm_restore
= FALSE
;
1510 #endif /* WL_CFG80211 */
1513 dhd_rtt_register_noti_callback(dhd_pub_t
*dhd
, void *ctx
, dhd_rtt_compl_noti_fn noti_fn
)
1516 struct rtt_noti_callback
*cb
= NULL
, *iter
;
1517 rtt_status_info_t
*rtt_status
;
1518 NULL_CHECK(dhd
, "dhd is NULL", err
);
1519 NULL_CHECK(noti_fn
, "noti_fn is NULL", err
);
1521 rtt_status
= GET_RTTSTATE(dhd
);
1522 NULL_CHECK(rtt_status
, "rtt_status is NULL", err
);
1523 spin_lock_bh(¬i_list_lock
);
1524 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1525 #pragma GCC diagnostic push
1526 #pragma GCC diagnostic ignored "-Wcast-qual"
1528 list_for_each_entry(iter
, &rtt_status
->noti_fn_list
, list
) {
1529 if (iter
->noti_fn
== noti_fn
) {
1533 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1534 #pragma GCC diagnostic pop
1536 cb
= kmalloc(sizeof(struct rtt_noti_callback
), GFP_ATOMIC
);
1541 cb
->noti_fn
= noti_fn
;
1543 list_add(&cb
->list
, &rtt_status
->noti_fn_list
);
1545 spin_unlock_bh(¬i_list_lock
);
1550 dhd_rtt_unregister_noti_callback(dhd_pub_t
*dhd
, dhd_rtt_compl_noti_fn noti_fn
)
1553 struct rtt_noti_callback
*cb
= NULL
, *iter
;
1554 rtt_status_info_t
*rtt_status
;
1555 NULL_CHECK(dhd
, "dhd is NULL", err
);
1556 NULL_CHECK(noti_fn
, "noti_fn is NULL", err
);
1557 rtt_status
= GET_RTTSTATE(dhd
);
1558 NULL_CHECK(rtt_status
, "rtt_status is NULL", err
);
1559 spin_lock_bh(¬i_list_lock
);
1560 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1561 #pragma GCC diagnostic push
1562 #pragma GCC diagnostic ignored "-Wcast-qual"
1564 list_for_each_entry(iter
, &rtt_status
->noti_fn_list
, list
) {
1565 if (iter
->noti_fn
== noti_fn
) {
1567 list_del(&cb
->list
);
1571 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1572 #pragma GCC diagnostic pop
1575 spin_unlock_bh(¬i_list_lock
);
1583 dhd_rtt_convert_rate_to_host(uint32 rspec
)
1585 wifi_rate_t host_rate
;
1586 memset(&host_rate
, 0, sizeof(wifi_rate_t
));
1587 if ((rspec
& WL_RSPEC_ENCODING_MASK
) == WL_RSPEC_ENCODE_RATE
) {
1588 host_rate
.preamble
= 0;
1589 } else if ((rspec
& WL_RSPEC_ENCODING_MASK
) == WL_RSPEC_ENCODE_HT
) {
1590 host_rate
.preamble
= 2;
1591 host_rate
.rateMcsIdx
= rspec
& WL_RSPEC_RATE_MASK
;
1592 } else if ((rspec
& WL_RSPEC_ENCODING_MASK
) == WL_RSPEC_ENCODE_VHT
) {
1593 host_rate
.preamble
= 3;
1594 host_rate
.rateMcsIdx
= rspec
& WL_RSPEC_VHT_MCS_MASK
;
1595 host_rate
.nss
= (rspec
& WL_RSPEC_VHT_NSS_MASK
) >> WL_RSPEC_VHT_NSS_SHIFT
;
1597 host_rate
.bw
= (rspec
& WL_RSPEC_BW_MASK
) - 1;
1598 host_rate
.bitrate
= rate_rspec2rate(rspec
) / 100; /* 100kbps */
1599 DHD_RTT(("bit rate : %d\n", host_rate
.bitrate
));
1605 dhd_rtt_convert_results_to_host(rtt_report_t
*rtt_report
, uint8
*p_data
, uint16 tlvid
, uint16 len
)
1608 char eabuf
[ETHER_ADDR_STR_LEN
];
1609 wl_proxd_rtt_result_t
*p_data_info
;
1610 wl_proxd_result_flags_t flags
;
1611 wl_proxd_session_state_t session_state
;
1612 wl_proxd_status_t proxd_status
;
1613 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
1615 #endif /* LINUX_VER >= 2.6.39 */
1618 wl_proxd_rtt_sample_t
*p_sample
;
1619 wl_proxd_intvl_t rtt
;
1620 wl_proxd_intvl_t p_time
;
1622 NULL_CHECK(rtt_report
, "rtt_report is NULL", err
);
1623 NULL_CHECK(p_data
, "p_data is NULL", err
);
1624 DHD_RTT(("%s enter\n", __FUNCTION__
));
1625 p_data_info
= (wl_proxd_rtt_result_t
*) p_data
;
1626 /* unpack and format 'flags' for display */
1627 flags
= ltoh16_ua(&p_data_info
->flags
);
1629 /* session state and status */
1630 session_state
= ltoh16_ua(&p_data_info
->state
);
1631 proxd_status
= ltoh32_ua(&p_data_info
->status
);
1632 bcm_ether_ntoa((&(p_data_info
->peer
)), eabuf
);
1633 ftm_session_state_value_to_logstr(session_state
);
1634 ftm_status_value_to_logstr(proxd_status
);
1635 DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n",
1638 ftm_session_state_value_to_logstr(session_state
),
1640 ftm_status_value_to_logstr(proxd_status
)));
1642 /* show avg_dist (1/256m units), burst_num */
1643 avg_dist
= ltoh32_ua(&p_data_info
->avg_dist
);
1644 if (avg_dist
== 0xffffffff) { /* report 'failure' case */
1645 DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n",
1646 ltoh16_ua(&p_data_info
->burst_num
),
1647 p_data_info
->num_valid_rtt
)); /* in a session */
1648 avg_dist
= FTM_INVALID
;
1651 DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n",
1652 avg_dist
>> 8, /* 1/256m units */
1653 ((avg_dist
& 0xff) * 625) >> 4,
1654 ltoh16_ua(&p_data_info
->burst_num
),
1655 p_data_info
->num_valid_rtt
,
1656 p_data_info
->num_ftm
)); /* in a session */
1658 /* show 'avg_rtt' sample */
1659 p_sample
= &p_data_info
->avg_rtt
;
1660 ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample
->rtt
.tmu
));
1661 DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d ratespec=0x%08x\n",
1662 (int16
) ltoh16_ua(&p_sample
->rssi
),
1663 ltoh32_ua(&p_sample
->rtt
.intvl
),
1664 ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample
->rtt
.tmu
)),
1665 ltoh16_ua(&p_data_info
->sd_rtt
)/10, ltoh16_ua(&p_data_info
->sd_rtt
)%10,
1666 ltoh32_ua(&p_sample
->ratespec
)));
1668 /* set peer address */
1669 rtt_report
->addr
= p_data_info
->peer
;
1671 rtt_report
->burst_num
= ltoh16_ua(&p_data_info
->burst_num
);
1673 rtt_report
->success_num
= p_data_info
->num_valid_rtt
;
1674 /* actual number of FTM supported by peer */
1675 rtt_report
->num_per_burst_peer
= p_data_info
->num_ftm
;
1676 rtt_report
->negotiated_burst_num
= p_data_info
->num_ftm
;
1678 rtt_report
->status
= ftm_get_statusmap_info(proxd_status
,
1679 &ftm_status_map_info
[0], ARRAYSIZE(ftm_status_map_info
));
1682 rtt_report
->rssi
= ABS((wl_proxd_rssi_t
)ltoh16_ua(&p_data_info
->avg_rtt
.rssi
)) * 2;
1685 ratespec
= ltoh32_ua(&p_data_info
->avg_rtt
.ratespec
);
1686 rtt_report
->rx_rate
= dhd_rtt_convert_rate_to_host(ratespec
);
1688 if (flags
& WL_PROXD_RESULT_FLAG_VHTACK
) {
1689 rtt_report
->tx_rate
= dhd_rtt_convert_rate_to_host(0x2010010);
1691 rtt_report
->tx_rate
= dhd_rtt_convert_rate_to_host(0xc);
1694 rtt
.tmu
= ltoh16_ua(&p_data_info
->avg_rtt
.rtt
.tmu
);
1695 rtt
.intvl
= ltoh32_ua(&p_data_info
->avg_rtt
.rtt
.intvl
);
1696 rtt_report
->rtt
= (wifi_timespan
)FTM_INTVL2NSEC(&rtt
) * 1000; /* nano -> pico seconds */
1697 rtt_report
->rtt_sd
= ltoh16_ua(&p_data_info
->sd_rtt
); /* nano -> 0.1 nano */
1698 DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report
->rtt
));
1699 DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report
->rssi
));
1701 /* average distance */
1702 if (avg_dist
!= FTM_INVALID
) {
1703 rtt_report
->distance
= (avg_dist
>> 8) * 1000; /* meter -> mm */
1704 rtt_report
->distance
+= (avg_dist
& 0xff) * 1000 / 256;
1706 rtt_report
->distance
= FTM_INVALID
;
1709 /* get the time elapsed from boot time */
1710 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
1711 get_monotonic_boottime(&ts
);
1712 rtt_report
->ts
= (uint64
)TIMESPEC_TO_US(ts
);
1713 #endif /* LINUX_VER >= 2.6.39 */
1715 if (proxd_status
== WL_PROXD_E_REMOTE_FAIL
) {
1716 /* retry time after failure */
1717 p_time
.intvl
= ltoh32_ua(&p_data_info
->u
.retry_after
.intvl
);
1718 p_time
.tmu
= ltoh16_ua(&p_data_info
->u
.retry_after
.tmu
);
1719 rtt_report
->retry_after_duration
= FTM_INTVL2SEC(&p_time
); /* s -> s */
1720 DHD_RTT((">\tretry_after: %d%s\n",
1721 ltoh32_ua(&p_data_info
->u
.retry_after
.intvl
),
1722 ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info
->u
.retry_after
.tmu
))));
1724 /* burst duration */
1725 p_time
.intvl
= ltoh32_ua(&p_data_info
->u
.retry_after
.intvl
);
1726 p_time
.tmu
= ltoh16_ua(&p_data_info
->u
.retry_after
.tmu
);
1727 rtt_report
->burst_duration
= FTM_INTVL2MSEC(&p_time
); /* s -> ms */
1728 DHD_RTT((">\tburst_duration: %d%s\n",
1729 ltoh32_ua(&p_data_info
->u
.burst_duration
.intvl
),
1730 ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info
->u
.burst_duration
.tmu
))));
1731 DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report
->burst_duration
));
1737 dhd_rtt_event_handler(dhd_pub_t
*dhd
, wl_event_msg_t
*event
, void *event_data
)
1742 wl_proxd_event_t
*p_event
;
1743 wl_proxd_event_type_t event_type
;
1744 wl_proxd_ftm_session_status_t session_status
;
1745 wl_proxd_collect_event_data_t
*collect_event_data
;
1746 const ftm_strmap_entry_t
*p_loginfo
;
1747 rtt_result_t
*rtt_result
;
1751 struct rtt_noti_callback
*iter
;
1753 rtt_status_info_t
*rtt_status
;
1754 rtt_result_t
*next2
;
1755 rtt_results_header_t
*next
= NULL
;
1756 rtt_target_info_t
*rtt_target_info
;
1757 rtt_results_header_t
*entry
, *rtt_results_header
= NULL
;
1758 #endif /* WL_CFG80211 */
1760 DHD_RTT(("Enter %s \n", __FUNCTION__
));
1761 NULL_CHECK(dhd
, "dhd is NULL", ret
);
1764 rtt_status
= GET_RTTSTATE(dhd
);
1765 NULL_CHECK(rtt_status
, "rtt_status is NULL", ret
);
1767 if (RTT_IS_STOPPED(rtt_status
)) {
1768 /* Ignore the Proxd event */
1769 DHD_RTT((" event handler rtt is stopped \n"));
1770 if (rtt_status
->flags
== WL_PROXD_SESSION_FLAG_TARGET
) {
1771 DHD_RTT(("Device is target/Responder. Recv the event. \n"));
1776 #endif /* WL_CFG80211 */
1777 if (ntoh32_ua((void *)&event
->datalen
) < OFFSETOF(wl_proxd_event_t
, tlvs
)) {
1778 DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__
,
1779 ntoh32_ua((void *)&event
->datalen
)));
1782 event_type
= ntoh32_ua((void *)&event
->event_type
);
1783 if (event_type
!= WLC_E_PROXD
) {
1784 DHD_ERROR((" failed event \n"));
1789 DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__
));
1792 p_event
= (wl_proxd_event_t
*) event_data
;
1793 version
= ltoh16(p_event
->version
);
1794 if (version
< WL_PROXD_API_VERSION
) {
1795 DHD_ERROR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n",
1796 version
, WL_PROXD_API_VERSION
));
1801 mutex_lock(&rtt_status
->rtt_mutex
);
1803 #endif /* WL_CFG80211 */
1804 event_type
= (wl_proxd_event_type_t
) ltoh16(p_event
->type
);
1806 kflags
= in_softirq()? GFP_ATOMIC
: GFP_KERNEL
;
1808 DHD_RTT(("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x\n",
1809 p_event
->type
, ntoh16(p_event
->type
), ltoh16(p_event
->type
)));
1810 p_loginfo
= ftm_get_event_type_loginfo(event_type
);
1811 if (p_loginfo
== NULL
) {
1812 DHD_ERROR(("receive an invalid FTM event %d\n", event_type
));
1814 goto exit
; /* ignore this event */
1816 /* get TLVs len, skip over event header */
1817 if (ltoh16(p_event
->len
) < OFFSETOF(wl_proxd_event_t
, tlvs
)) {
1818 DHD_ERROR(("invalid FTM event length:%d\n", ltoh16(p_event
->len
)));
1822 tlvs_len
= ltoh16(p_event
->len
) - OFFSETOF(wl_proxd_event_t
, tlvs
);
1823 DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n",
1826 ltoh16(p_event
->len
),
1827 ltoh16(p_event
->method
),
1828 ltoh16(p_event
->sid
),
1831 rtt_target_info
= &rtt_status
->rtt_config
.target_info
[rtt_status
->cur_idx
];
1832 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1833 #pragma GCC diagnostic push
1834 #pragma GCC diagnostic ignored "-Wcast-qual"
1836 /* find a rtt_report_header for this mac address */
1837 list_for_each_entry(entry
, &rtt_status
->rtt_results_cache
, list
) {
1838 if (!memcmp(&entry
->peer_mac
, &event
->addr
, ETHER_ADDR_LEN
)) {
1839 /* found a rtt_report_header for peer_mac in the list */
1841 rtt_results_header
= entry
;
1845 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1846 #pragma GCC diagnostic pop
1848 #endif /* WL_CFG80211 */
1849 switch (event_type
) {
1850 case WL_PROXD_EVENT_SESSION_CREATE
:
1851 DHD_RTT(("WL_PROXD_EVENT_SESSION_CREATE\n"));
1853 case WL_PROXD_EVENT_SESSION_START
:
1854 DHD_RTT(("WL_PROXD_EVENT_SESSION_START\n"));
1856 case WL_PROXD_EVENT_BURST_START
:
1857 DHD_RTT(("WL_PROXD_EVENT_BURST_START\n"));
1859 case WL_PROXD_EVENT_BURST_END
:
1860 DHD_RTT(("WL_PROXD_EVENT_BURST_END\n"));
1863 /* allocate new header for rtt_results */
1864 rtt_results_header
= kzalloc(sizeof(rtt_results_header_t
), kflags
);
1865 if (!rtt_results_header
) {
1869 /* Initialize the head of list for rtt result */
1870 INIT_LIST_HEAD(&rtt_results_header
->result_list
);
1871 rtt_results_header
->peer_mac
= event
->addr
;
1872 list_add_tail(&rtt_results_header
->list
, &rtt_status
->rtt_results_cache
);
1874 #endif /* WL_CFG80211 */
1876 /* allocate rtt_results for new results */
1877 rtt_result
= kzalloc(sizeof(rtt_result_t
), kflags
);
1882 /* unpack TLVs and invokes the cbfn to print the event content TLVs */
1883 ret
= bcm_unpack_xtlv_buf((void *) &(rtt_result
->report
),
1884 (uint8
*)&p_event
->tlvs
[0], tlvs_len
,
1885 BCM_XTLV_OPTION_ALIGN32
, rtt_unpack_xtlv_cbfn
);
1886 if (ret
!= BCME_OK
) {
1887 DHD_ERROR(("%s : Failed to unpack xtlv for an event\n",
1892 /* fill out the results from the configuration param */
1893 rtt_result
->report
.ftm_num
= rtt_target_info
->num_frames_per_burst
;
1894 rtt_result
->report
.type
= RTT_TWO_WAY
;
1895 DHD_RTT(("report->ftm_num : %d\n", rtt_result
->report
.ftm_num
));
1896 rtt_result
->report_len
= RTT_REPORT_SIZE
;
1898 list_add_tail(&rtt_result
->list
, &rtt_results_header
->result_list
);
1899 rtt_results_header
->result_cnt
++;
1900 rtt_results_header
->result_tot_len
+= rtt_result
->report_len
;
1901 #endif /* WL_CFG80211 */
1904 case WL_PROXD_EVENT_SESSION_END
:
1905 DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n"));
1907 if (!RTT_IS_ENABLED(rtt_status
)) {
1908 DHD_RTT(("Ignore the session end evt\n"));
1911 #endif /* WL_CFG80211 */
1913 /* unpack TLVs and invokes the cbfn to print the event content TLVs */
1914 ret
= bcm_unpack_xtlv_buf((void *) &session_status
,
1915 (uint8
*)&p_event
->tlvs
[0], tlvs_len
,
1916 BCM_XTLV_OPTION_ALIGN32
, rtt_unpack_xtlv_cbfn
);
1917 if (ret
!= BCME_OK
) {
1918 DHD_ERROR(("%s : Failed to unpack xtlv for an event\n",
1924 /* In case of no result for the peer device, make fake result for error case */
1926 /* allocate new header for rtt_results */
1927 rtt_results_header
= kzalloc(sizeof(rtt_results_header_t
), GFP_KERNEL
);
1928 if (!rtt_results_header
) {
1932 /* Initialize the head of list for rtt result */
1933 INIT_LIST_HEAD(&rtt_results_header
->result_list
);
1934 rtt_results_header
->peer_mac
= event
->addr
;
1935 list_add_tail(&rtt_results_header
->list
, &rtt_status
->rtt_results_cache
);
1937 /* allocate rtt_results for new results */
1938 rtt_result
= kzalloc(sizeof(rtt_result_t
), kflags
);
1941 kfree(rtt_results_header
);
1944 /* fill out the results from the configuration param */
1945 rtt_result
->report
.ftm_num
= rtt_target_info
->num_frames_per_burst
;
1946 rtt_result
->report
.type
= RTT_TWO_WAY
;
1947 DHD_RTT(("report->ftm_num : %d\n", rtt_result
->report
.ftm_num
));
1948 rtt_result
->report_len
= RTT_REPORT_SIZE
;
1949 rtt_result
->report
.status
= RTT_REASON_FAIL_NO_RSP
;
1950 rtt_result
->report
.addr
= rtt_target_info
->addr
;
1951 rtt_result
->report
.distance
= FTM_INVALID
;
1952 list_add_tail(&rtt_result
->list
, &rtt_results_header
->result_list
);
1953 rtt_results_header
->result_cnt
++;
1954 rtt_results_header
->result_tot_len
+= rtt_result
->report_len
;
1956 /* find next target to trigger RTT */
1957 for (idx
= (rtt_status
->cur_idx
+ 1);
1958 idx
< rtt_status
->rtt_config
.rtt_target_cnt
; idx
++) {
1959 /* skip the disabled device */
1960 if (rtt_status
->rtt_config
.target_info
[idx
].disable
) {
1963 /* set the idx to cur_idx */
1964 rtt_status
->cur_idx
= idx
;
1968 if (idx
< rtt_status
->rtt_config
.rtt_target_cnt
) {
1969 /* restart to measure RTT from next device */
1970 DHD_ERROR(("restart to measure rtt\n"));
1971 schedule_work(&rtt_status
->work
);
1973 DHD_RTT(("RTT_STOPPED\n"));
1974 rtt_status
->status
= RTT_STOPPED
;
1975 /* to turn on mpc mode */
1976 schedule_work(&rtt_status
->work
);
1977 /* notify the completed information to others */
1978 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1979 #pragma GCC diagnostic push
1980 #pragma GCC diagnostic ignored "-Wcast-qual"
1982 list_for_each_entry(iter
, &rtt_status
->noti_fn_list
, list
) {
1983 iter
->noti_fn(iter
->ctx
, &rtt_status
->rtt_results_cache
);
1985 /* remove the rtt results in cache */
1986 if (!list_empty(&rtt_status
->rtt_results_cache
)) {
1987 /* Iterate rtt_results_header list */
1988 list_for_each_entry_safe(entry
, next
,
1989 &rtt_status
->rtt_results_cache
, list
) {
1990 list_del(&entry
->list
);
1991 /* Iterate rtt_result list */
1992 list_for_each_entry_safe(rtt_result
, next2
,
1993 &entry
->result_list
, list
) {
1994 list_del(&rtt_result
->list
);
2000 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2001 #pragma GCC diagnostic pop
2003 /* reinitialize the HEAD */
2004 INIT_LIST_HEAD(&rtt_status
->rtt_results_cache
);
2005 /* clear information for rtt_config */
2006 rtt_status
->rtt_config
.rtt_target_cnt
= 0;
2007 memset(rtt_status
->rtt_config
.target_info
, 0,
2008 TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT
));
2009 rtt_status
->cur_idx
= 0;
2011 #endif /* WL_CFG80211 */
2013 case WL_PROXD_EVENT_SESSION_RESTART
:
2014 DHD_RTT(("WL_PROXD_EVENT_SESSION_RESTART\n"));
2016 case WL_PROXD_EVENT_BURST_RESCHED
:
2017 DHD_RTT(("WL_PROXD_EVENT_BURST_RESCHED\n"));
2019 case WL_PROXD_EVENT_SESSION_DESTROY
:
2020 DHD_RTT(("WL_PROXD_EVENT_SESSION_DESTROY\n"));
2022 case WL_PROXD_EVENT_FTM_FRAME
:
2023 DHD_RTT(("WL_PROXD_EVENT_FTM_FRAME\n"));
2025 case WL_PROXD_EVENT_DELAY
:
2026 DHD_RTT(("WL_PROXD_EVENT_DELAY\n"));
2028 case WL_PROXD_EVENT_VS_INITIATOR_RPT
:
2029 DHD_RTT(("WL_PROXD_EVENT_VS_INITIATOR_RPT\n "));
2031 case WL_PROXD_EVENT_RANGING
:
2032 DHD_RTT(("WL_PROXD_EVENT_RANGING\n"));
2034 case WL_PROXD_EVENT_COLLECT
:
2035 DHD_RTT(("WL_PROXD_EVENT_COLLECT\n"));
2037 collect_event_data
= kzalloc(sizeof(wl_proxd_collect_event_data_t
), kflags
);
2038 if (!collect_event_data
) {
2042 /* unpack TLVs and invokes the cbfn to print the event content TLVs */
2043 ret
= bcm_unpack_xtlv_buf((void *) collect_event_data
,
2044 (uint8
*)&p_event
->tlvs
[0], tlvs_len
,
2045 BCM_XTLV_OPTION_NONE
, rtt_unpack_xtlv_cbfn
);
2046 kfree(collect_event_data
);
2047 if (ret
!= BCME_OK
) {
2048 DHD_ERROR(("%s : Failed to unpack xtlv for an event\n",
2057 DHD_ERROR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type
));
2063 mutex_unlock(&rtt_status
->rtt_mutex
);
2065 #endif /* WL_CFG80211 */
2072 dhd_rtt_work(struct work_struct
*work
)
2074 rtt_status_info_t
*rtt_status
;
2076 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2077 #pragma GCC diagnostic push
2078 #pragma GCC diagnostic ignored "-Wcast-qual"
2080 rtt_status
= container_of(work
, rtt_status_info_t
, work
);
2081 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2082 #pragma GCC diagnostic pop
2084 if (rtt_status
== NULL
) {
2085 DHD_ERROR(("%s : rtt_status is NULL\n", __FUNCTION__
));
2088 dhd
= rtt_status
->dhd
;
2090 DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__
));
2093 (void) dhd_rtt_start(dhd
);
2095 #endif /* WL_CFG80211 */
2098 dhd_rtt_capability(dhd_pub_t
*dhd
, rtt_capabilities_t
*capa
)
2100 rtt_status_info_t
*rtt_status
;
2102 NULL_CHECK(dhd
, "dhd is NULL", err
);
2103 rtt_status
= GET_RTTSTATE(dhd
);
2104 NULL_CHECK(rtt_status
, "rtt_status is NULL", err
);
2105 NULL_CHECK(capa
, "capa is NULL", err
);
2106 bzero(capa
, sizeof(rtt_capabilities_t
));
2108 /* set rtt capabilities */
2109 if (rtt_status
->rtt_capa
.proto
& RTT_CAP_ONE_WAY
)
2110 capa
->rtt_one_sided_supported
= 1;
2111 if (rtt_status
->rtt_capa
.proto
& RTT_CAP_FTM_WAY
)
2112 capa
->rtt_ftm_supported
= 1;
2114 if (rtt_status
->rtt_capa
.feature
& RTT_FEATURE_LCI
)
2115 capa
->lci_support
= 1;
2116 if (rtt_status
->rtt_capa
.feature
& RTT_FEATURE_LCR
)
2117 capa
->lcr_support
= 1;
2118 if (rtt_status
->rtt_capa
.feature
& RTT_FEATURE_PREAMBLE
)
2119 capa
->preamble_support
= 1;
2120 if (rtt_status
->rtt_capa
.feature
& RTT_FEATURE_BW
)
2121 capa
->bw_support
= 1;
2124 capa
->preamble_support
= rtt_status
->rtt_capa
.preamble
;
2125 capa
->bw_support
= rtt_status
->rtt_capa
.bw
;
2132 dhd_rtt_avail_channel(dhd_pub_t
*dhd
, wifi_channel_info
*channel_info
)
2138 struct net_device
*dev
= dhd_linux_get_primary_netdev(dhd
);
2140 if ((err
= wldev_iovar_getint(dev
, "chanspec",
2141 (s32
*)&chanspec
)) == BCME_OK
) {
2142 c
= (chanspec_t
)dtoh32(chanspec
);
2143 c
= wl_chspec_driver_to_host(c
);
2144 channel
= wf_chspec_ctlchan(c
);
2145 DHD_RTT((" control channel is %d \n", channel
));
2146 if (CHSPEC_IS20(c
)) {
2147 channel_info
->width
= WIFI_CHAN_WIDTH_20
;
2148 DHD_RTT((" band is 20 \n"));
2149 } else if (CHSPEC_IS40(c
)) {
2150 channel_info
->width
= WIFI_CHAN_WIDTH_40
;
2151 DHD_RTT(("band is 40 \n"));
2153 channel_info
->width
= WIFI_CHAN_WIDTH_80
;
2154 DHD_RTT(("band is 80 \n"));
2156 if (CHSPEC_IS2G(c
) && (channel
>= CH_MIN_2G_CHANNEL
) &&
2157 (channel
<= CH_MAX_2G_CHANNEL
)) {
2158 channel_info
->center_freq
=
2159 ieee80211_channel_to_frequency(channel
, IEEE80211_BAND_2GHZ
);
2160 } else if (CHSPEC_IS5G(c
) && channel
>= CH_MIN_5G_CHANNEL
) {
2161 channel_info
->center_freq
=
2162 ieee80211_channel_to_frequency(channel
, IEEE80211_BAND_5GHZ
);
2164 if ((channel_info
->width
== WIFI_CHAN_WIDTH_80
) ||
2165 (channel_info
->width
== WIFI_CHAN_WIDTH_40
)) {
2166 channel
= CHSPEC_CHANNEL(c
);
2167 channel_info
->center_freq0
=
2168 ieee80211_channel_to_frequency(channel
, IEEE80211_BAND_5GHZ
);
2171 DHD_ERROR(("Failed to get the chanspec \n"));
2177 dhd_rtt_enable_responder(dhd_pub_t
*dhd
, wifi_channel_info
*channel_info
)
2180 char chanbuf
[CHANSPEC_STR_LEN
];
2182 int ftm_cfg_cnt
= 0;
2183 chanspec_t chanspec
;
2184 wifi_channel_info_t channel
;
2185 struct net_device
*dev
= dhd_linux_get_primary_netdev(dhd
);
2186 ftm_config_options_info_t ftm_configs
[FTM_MAX_CONFIGS
];
2187 ftm_config_param_info_t ftm_params
[FTM_MAX_PARAMS
];
2188 rtt_status_info_t
*rtt_status
;
2190 memset(&channel
, 0, sizeof(channel
));
2191 BCM_REFERENCE(chanbuf
);
2192 NULL_CHECK(dhd
, "dhd is NULL", err
);
2193 rtt_status
= GET_RTTSTATE(dhd
);
2194 NULL_CHECK(rtt_status
, "rtt_status is NULL", err
);
2195 if (RTT_IS_STOPPED(rtt_status
)) {
2196 DHD_RTT(("STA responder/Target. \n"));
2198 DHD_RTT(("Enter %s \n", __FUNCTION__
));
2199 if (!dhd_is_associated(dhd
, 0, NULL
)) {
2201 channel
.width
= channel_info
->width
;
2202 channel
.center_freq
= channel_info
->center_freq
;
2203 channel
.center_freq0
= channel_info
->center_freq
;
2206 channel
.width
= WIFI_CHAN_WIDTH_80
;
2207 channel
.center_freq
= DEFAULT_FTM_FREQ
;
2208 channel
.center_freq0
= DEFAULT_FTM_CNTR_FREQ0
;
2210 chanspec
= dhd_rtt_convert_to_chspec(channel
);
2211 DHD_RTT(("chanspec/channel set as %s for rtt.\n",
2212 wf_chspec_ntoa(chanspec
, chanbuf
)));
2213 err
= wldev_iovar_setint(dev
, "chanspec", chanspec
);
2215 DHD_ERROR(("Failed to set the chanspec \n"));
2218 err
= wldev_ioctl_get(dev
, WLC_GET_PM
, &rtt_status
->pm
, sizeof(rtt_status
->pm
));
2219 DHD_RTT(("Current PM value read %d\n", rtt_status
->pm
));
2221 DHD_ERROR(("Failed to get the PM value \n"));
2223 err
= wldev_ioctl_set(dev
, WLC_SET_PM
, &pm
, sizeof(pm
));
2225 DHD_ERROR(("Failed to set the PM \n"));
2226 rtt_status
->pm_restore
= FALSE
;
2228 rtt_status
->pm_restore
= TRUE
;
2231 if (!RTT_IS_ENABLED(rtt_status
)) {
2232 err
= dhd_rtt_ftm_enable(dhd
, TRUE
);
2234 DHD_ERROR(("Failed to enable FTM (%d)\n", err
));
2237 DHD_RTT(("FTM enabled \n"));
2239 rtt_status
->status
= RTT_ENABLED
;
2240 DHD_RTT(("Responder enabled \n"));
2241 memset(ftm_configs
, 0, sizeof(ftm_configs
));
2242 memset(ftm_params
, 0, sizeof(ftm_params
));
2243 ftm_configs
[ftm_cfg_cnt
].enable
= TRUE
;
2244 ftm_configs
[ftm_cfg_cnt
++].flags
= WL_PROXD_SESSION_FLAG_TARGET
;
2245 rtt_status
->flags
= WL_PROXD_SESSION_FLAG_TARGET
;
2246 DHD_RTT(("Set the device as responder \n"));
2247 err
= dhd_rtt_ftm_config(dhd
, FTM_DEFAULT_SESSION
, FTM_CONFIG_CAT_OPTIONS
,
2248 ftm_configs
, ftm_cfg_cnt
);
2251 rtt_status
->status
= RTT_STOPPED
;
2252 DHD_ERROR(("rtt is stopped %s \n", __FUNCTION__
));
2253 dhd_rtt_ftm_enable(dhd
, FALSE
);
2254 DHD_RTT(("restoring the PM value \n"));
2255 if (rtt_status
->pm_restore
) {
2257 err
= wldev_ioctl_set(dev
, WLC_SET_PM
, &pm
, sizeof(pm
));
2259 DHD_ERROR(("Failed to restore PM \n"));
2261 rtt_status
->pm_restore
= FALSE
;
2269 dhd_rtt_cancel_responder(dhd_pub_t
*dhd
)
2272 rtt_status_info_t
*rtt_status
;
2274 struct net_device
*dev
= dhd_linux_get_primary_netdev(dhd
);
2275 NULL_CHECK(dhd
, "dhd is NULL", err
);
2276 rtt_status
= GET_RTTSTATE(dhd
);
2277 NULL_CHECK(rtt_status
, "rtt_status is NULL", err
);
2278 DHD_RTT(("Enter %s \n", __FUNCTION__
));
2279 err
= dhd_rtt_ftm_enable(dhd
, FALSE
);
2281 DHD_ERROR(("failed to disable FTM (%d)\n", err
));
2283 rtt_status
->status
= RTT_STOPPED
;
2284 if (rtt_status
->pm_restore
) {
2286 DHD_RTT(("pm_restore =%d \n", rtt_status
->pm_restore
));
2287 err
= wldev_ioctl_set(dev
, WLC_SET_PM
, &pm
, sizeof(pm
));
2289 DHD_ERROR(("Failed to restore PM \n"));
2291 rtt_status
->pm_restore
= FALSE
;
2296 #endif /* WL_CFG80211 */
2299 dhd_rtt_init(dhd_pub_t
*dhd
)
2306 rtt_status_info_t
*rtt_status
;
2307 NULL_CHECK(dhd
, "dhd is NULL", err
);
2308 dhd
->rtt_supported
= FALSE
;
2309 if (dhd
->rtt_state
) {
2312 dhd
->rtt_state
= kzalloc(sizeof(rtt_status_info_t
), GFP_KERNEL
);
2313 if (dhd
->rtt_state
== NULL
) {
2315 DHD_ERROR(("%s : failed to create rtt_state\n", __FUNCTION__
));
2318 bzero(dhd
->rtt_state
, sizeof(rtt_status_info_t
));
2319 rtt_status
= GET_RTTSTATE(dhd
);
2320 rtt_status
->rtt_config
.target_info
=
2321 kzalloc(TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT
), GFP_KERNEL
);
2322 if (rtt_status
->rtt_config
.target_info
== NULL
) {
2323 DHD_ERROR(("%s failed to allocate the target info for %d\n",
2324 __FUNCTION__
, RTT_MAX_TARGET_CNT
));
2328 rtt_status
->dhd
= dhd
;
2329 /* need to do WLC_UP */
2330 dhd_wl_ioctl_cmd(dhd
, WLC_UP
, (char *)&drv_up
, sizeof(int32
), TRUE
, 0);
2332 ret
= dhd_rtt_get_version(dhd
, &version
);
2333 if (ret
== BCME_OK
&& (version
== WL_PROXD_API_VERSION
)) {
2334 DHD_ERROR(("%s : FTM is supported\n", __FUNCTION__
));
2335 dhd
->rtt_supported
= TRUE
;
2336 /* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */
2337 rtt_status
->rtt_capa
.proto
|= RTT_CAP_FTM_WAY
;
2339 /* indicate to set tx rate */
2340 rtt_status
->rtt_capa
.feature
|= RTT_FEATURE_LCI
;
2341 rtt_status
->rtt_capa
.feature
|= RTT_FEATURE_LCR
;
2342 rtt_status
->rtt_capa
.feature
|= RTT_FEATURE_PREAMBLE
;
2343 rtt_status
->rtt_capa
.preamble
|= RTT_PREAMBLE_VHT
;
2344 rtt_status
->rtt_capa
.preamble
|= RTT_PREAMBLE_HT
;
2346 /* indicate to set bandwith */
2347 rtt_status
->rtt_capa
.feature
|= RTT_FEATURE_BW
;
2348 rtt_status
->rtt_capa
.bw
|= RTT_BW_20
;
2349 rtt_status
->rtt_capa
.bw
|= RTT_BW_40
;
2350 rtt_status
->rtt_capa
.bw
|= RTT_BW_80
;
2352 if ((ret
!= BCME_OK
) || (version
== 0)) {
2353 DHD_ERROR(("%s : FTM is not supported\n", __FUNCTION__
));
2355 DHD_ERROR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n",
2356 __FUNCTION__
, WL_PROXD_API_VERSION
, version
));
2359 /* cancel all of RTT request once we got the cancel request */
2360 rtt_status
->all_cancel
= TRUE
;
2361 mutex_init(&rtt_status
->rtt_mutex
);
2362 INIT_LIST_HEAD(&rtt_status
->noti_fn_list
);
2363 INIT_LIST_HEAD(&rtt_status
->rtt_results_cache
);
2364 INIT_WORK(&rtt_status
->work
, dhd_rtt_work
);
2367 kfree(rtt_status
->rtt_config
.target_info
);
2368 kfree(dhd
->rtt_state
);
2370 #endif /* WL_CFG80211 */
2376 dhd_rtt_deinit(dhd_pub_t
*dhd
)
2380 rtt_status_info_t
*rtt_status
;
2381 rtt_results_header_t
*rtt_header
, *next
;
2382 rtt_result_t
*rtt_result
, *next2
;
2383 struct rtt_noti_callback
*iter
, *iter2
;
2384 NULL_CHECK(dhd
, "dhd is NULL", err
);
2385 rtt_status
= GET_RTTSTATE(dhd
);
2386 NULL_CHECK(rtt_status
, "rtt_status is NULL", err
);
2387 rtt_status
->status
= RTT_STOPPED
;
2388 DHD_RTT(("rtt is stopped %s \n", __FUNCTION__
));
2389 /* clear evt callback list */
2390 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2391 #pragma GCC diagnostic push
2392 #pragma GCC diagnostic ignored "-Wcast-qual"
2395 if (!list_empty(&rtt_status
->noti_fn_list
)) {
2396 list_for_each_entry_safe(iter
, iter2
, &rtt_status
->noti_fn_list
, list
) {
2397 list_del(&iter
->list
);
2401 /* remove the rtt results */
2402 if (!list_empty(&rtt_status
->rtt_results_cache
)) {
2403 list_for_each_entry_safe(rtt_header
, next
, &rtt_status
->rtt_results_cache
, list
) {
2404 list_del(&rtt_header
->list
);
2405 list_for_each_entry_safe(rtt_result
, next2
,
2406 &rtt_header
->result_list
, list
) {
2407 list_del(&rtt_result
->list
);
2413 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2414 #pragma GCC diagnostic pop
2416 kfree(rtt_status
->rtt_config
.target_info
);
2417 kfree(dhd
->rtt_state
);
2418 dhd
->rtt_state
= NULL
;
2419 #endif /* WL_CFG80211 */