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