2 * Broadcom Dongle Host Driver (DHD), RTT
4 * Copyright (C) 1999-2016, Broadcom Corporation
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
24 * $Id: dhd_rtt.c 606280 2015-12-15 05:28:25Z $
33 #include <bcmendian.h>
35 #include <linux/init.h>
36 #include <linux/kernel.h>
37 #include <linux/list.h>
38 #include <linux/sort.h>
39 #include <dngl_stats.h>
42 #include <proto/bcmevent.h>
46 #define GET_RTTSTATE(dhd) ((rtt_status_info_t *)dhd->rtt_state)
47 static DEFINE_SPINLOCK(noti_list_lock);
48 #define NULL_CHECK(p, s, err) \
51 printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \
57 #define RTT_TWO_SIDED(capability) \
59 if ((capability & RTT_CAP_ONE_WAY) == (uint8) (RTT_CAP_ONE_WAY)) \
64 #define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \
65 (ts).tv_nsec / NSEC_PER_USEC)
66 struct rtt_noti_callback {
67 struct list_head list;
69 dhd_rtt_compl_noti_fn noti_fn;
72 typedef struct rtt_status_info {
74 int8 status; /* current status for the current entry */
75 int8 cur_idx; /* current entry to do RTT */
76 int32 capability; /* rtt capability */
77 struct mutex rtt_mutex;
78 rtt_config_params_t rtt_config;
79 struct work_struct work;
80 struct list_head noti_fn_list;
81 struct list_head rtt_results_cache; /* store results for RTT */
84 static int dhd_rtt_start(dhd_pub_t *dhd);
87 dhd_rtt_convert_to_chspec(wifi_channel_info_t channel)
90 /* set witdh to 20MHZ for 2.4G HZ */
91 if (channel.center_freq >= 2400 && channel.center_freq <= 2500) {
92 channel.width = WIFI_CHAN_WIDTH_20;
94 switch (channel.width) {
95 case WIFI_CHAN_WIDTH_20:
96 bw = WL_CHANSPEC_BW_20;
98 case WIFI_CHAN_WIDTH_40:
99 bw = WL_CHANSPEC_BW_40;
101 case WIFI_CHAN_WIDTH_80:
102 bw = WL_CHANSPEC_BW_80;
104 case WIFI_CHAN_WIDTH_160:
105 bw = WL_CHANSPEC_BW_160;
108 DHD_ERROR(("doesn't support this bandwith : %d", channel.width));
112 return wf_channel2chspec(wf_mhz2channel(channel.center_freq, 0), bw);
116 dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params)
120 rtt_status_info_t *rtt_status;
121 NULL_CHECK(params, "params is NULL", err);
123 NULL_CHECK(dhd, "dhd is NULL", err);
124 rtt_status = GET_RTTSTATE(dhd);
125 NULL_CHECK(rtt_status, "rtt_status is NULL", err);
126 if (rtt_status->capability == RTT_CAP_NONE) {
127 DHD_ERROR(("doesn't support RTT \n"));
130 if (rtt_status->status == RTT_STARTED) {
131 DHD_ERROR(("rtt is already started\n"));
134 DHD_RTT(("%s enter\n", __FUNCTION__));
135 bcopy(params, &rtt_status->rtt_config, sizeof(rtt_config_params_t));
136 rtt_status->status = RTT_STARTED;
137 /* start to measure RTT from 1th device */
138 /* find next target to trigger RTT */
139 for (idx = rtt_status->cur_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
140 /* skip the disabled device */
141 if (rtt_status->rtt_config.target_info[idx].disable) {
144 /* set the idx to cur_idx */
145 rtt_status->cur_idx = idx;
149 if (idx < rtt_status->rtt_config.rtt_target_cnt) {
150 DHD_RTT(("rtt_status->cur_idx : %d\n", rtt_status->cur_idx));
151 schedule_work(&rtt_status->work);
157 dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt)
161 rtt_status_info_t *rtt_status;
163 NULL_CHECK(dhd, "dhd is NULL", err);
164 rtt_status = GET_RTTSTATE(dhd);
165 NULL_CHECK(rtt_status, "rtt_status is NULL", err);
166 if (rtt_status->status == RTT_STOPPED) {
167 DHD_ERROR(("rtt is not started\n"));
170 DHD_RTT(("%s enter\n", __FUNCTION__));
171 mutex_lock(&rtt_status->rtt_mutex);
172 for (i = 0; i < mac_cnt; i++) {
173 for (j = 0; j < rtt_status->rtt_config.rtt_target_cnt; j++) {
174 if (!bcmp(&mac_list[i], &rtt_status->rtt_config.target_info[j].addr,
176 rtt_status->rtt_config.target_info[j].disable = TRUE;
180 mutex_unlock(&rtt_status->rtt_mutex);
185 dhd_rtt_start(dhd_pub_t *dhd)
191 int8 eabuf[ETHER_ADDR_STR_LEN];
192 int8 chanbuf[CHANSPEC_STR_LEN];
193 bool set_mpc = FALSE;
194 wl_proxd_iovar_t proxd_iovar;
195 wl_proxd_params_iovar_t proxd_params;
196 wl_proxd_params_iovar_t proxd_tune;
197 wl_proxd_params_tof_method_t *tof_params = &proxd_params.u.tof_params;
198 rtt_status_info_t *rtt_status;
199 rtt_target_info_t *rtt_target;
200 NULL_CHECK(dhd, "dhd is NULL", err);
202 rtt_status = GET_RTTSTATE(dhd);
203 NULL_CHECK(rtt_status, "rtt_status is NULL", err);
204 /* turn off mpc in case of non-associted */
205 if (!dhd_is_associated(dhd, 0, NULL)) {
206 err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), 1);
208 DHD_ERROR(("%s : failed to set proxd_tune\n", __FUNCTION__));
214 if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) {
218 DHD_RTT(("%s enter\n", __FUNCTION__));
219 bzero(&proxd_tune, sizeof(proxd_tune));
220 bzero(&proxd_params, sizeof(proxd_params));
221 mutex_lock(&rtt_status->rtt_mutex);
222 /* Get a target information */
223 rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
224 mutex_unlock(&rtt_status->rtt_mutex);
226 proxd_iovar.method = PROXD_TOF_METHOD;
227 proxd_iovar.mode = WL_PROXD_MODE_INITIATOR;
229 /* make sure that proxd is stop */
230 /* dhd_iovar(dhd, 0, "proxd_stop", (char *)NULL, 0, 1); */
232 err = dhd_iovar(dhd, 0, "proxd", (char *)&proxd_iovar, sizeof(proxd_iovar), 1);
233 if (err < 0 && err != BCME_BUSY) {
234 DHD_ERROR(("%s : failed to set proxd %d\n", __FUNCTION__, err));
237 if (err == BCME_BUSY) {
238 DHD_RTT(("BCME_BUSY occurred\n"));
241 bcopy(&rtt_target->addr, &tof_params->tgt_mac, ETHER_ADDR_LEN);
243 if (rtt_target->ftm_cnt > RTT_MAX_FRAME_CNT) {
244 rtt_target->ftm_cnt = RTT_MAX_FRAME_CNT;
247 if (rtt_target->ftm_cnt) {
248 tof_params->ftm_cnt = htol16(rtt_target->ftm_cnt);
250 tof_params->ftm_cnt = htol16(DEFAULT_FTM_CNT);
253 if (rtt_target->retry_cnt > RTT_MAX_RETRY_CNT) {
254 rtt_target->retry_cnt = RTT_MAX_RETRY_CNT;
258 if (rtt_target->retry_cnt) {
259 tof_params->retry_cnt = htol16(rtt_target->retry_cnt);
261 tof_params->retry_cnt = htol16(DEFAULT_RETRY_CNT);
265 tof_params->chanspec = htol16(rtt_target->chanspec);
267 DHD_RTT(("Target addr(Idx %d) %s, Channel : %s for RTT (ftm_cnt %d, rety_cnt : %d)\n",
269 bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, eabuf),
270 wf_chspec_ntoa(rtt_target->chanspec, chanbuf), rtt_target->ftm_cnt,
271 rtt_target->retry_cnt));
273 if (rtt_target->type == RTT_ONE_WAY) {
274 proxd_tune.u.tof_tune.flags = htol32(WL_PROXD_FLAG_ONEWAY);
275 /* report RTT results for initiator */
276 proxd_tune.u.tof_tune.flags |= htol32(WL_PROXD_FLAG_INITIATOR_RPTRTT);
277 proxd_tune.u.tof_tune.vhtack = 0;
278 tof_params->tx_rate = htol16(WL_RATE_6M);
279 tof_params->vht_rate = htol16((WL_RATE_6M >> 16));
280 } else { /* RTT TWO WAY */
281 /* initiator will send the rtt result to the target */
282 proxd_tune.u.tof_tune.flags = htol32(WL_PROXD_FLAG_INITIATOR_REPORT);
283 tof_params->timeout = 10; /* 10ms for timeout */
284 rspec = WL_RSPEC_ENCODE_VHT; /* 11ac VHT */
285 nss = 1; /* default Nss = 1 */
286 mcs = 0; /* default MCS 0 */
287 rspec |= (nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs;
289 switch (CHSPEC_BW(rtt_target->chanspec)) {
290 case WL_CHANSPEC_BW_20:
291 bw = WL_RSPEC_BW_20MHZ;
293 case WL_CHANSPEC_BW_40:
294 bw = WL_RSPEC_BW_40MHZ;
296 case WL_CHANSPEC_BW_80:
297 bw = WL_RSPEC_BW_80MHZ;
299 case WL_CHANSPEC_BW_160:
300 bw = WL_RSPEC_BW_160MHZ;
303 DHD_ERROR(("CHSPEC_BW not supported : %d",
304 CHSPEC_BW(rtt_target->chanspec)));
308 tof_params->tx_rate = htol16(rspec & 0xffff);
309 tof_params->vht_rate = htol16(rspec >> 16);
312 /* Set Method to TOF */
313 proxd_tune.method = PROXD_TOF_METHOD;
314 err = dhd_iovar(dhd, 0, "proxd_tune", (char *)&proxd_tune, sizeof(proxd_tune), 1);
316 DHD_ERROR(("%s : failed to set proxd_tune %d\n", __FUNCTION__, err));
320 /* Set Method to TOF */
321 proxd_params.method = PROXD_TOF_METHOD;
322 err = dhd_iovar(dhd, 0, "proxd_params", (char *)&proxd_params, sizeof(proxd_params), 1);
324 DHD_ERROR(("%s : failed to set proxd_params %d\n", __FUNCTION__, err));
327 err = dhd_iovar(dhd, 0, "proxd_find", (char *)NULL, 0, 1);
329 DHD_ERROR(("%s : failed to set proxd_find %d\n", __FUNCTION__, err));
334 rtt_status->status = RTT_STOPPED;
336 /* enable mpc again in case of error */
338 err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), 1);
345 dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn)
348 struct rtt_noti_callback *cb = NULL, *iter;
349 rtt_status_info_t *rtt_status;
350 NULL_CHECK(dhd, "dhd is NULL", err);
351 NULL_CHECK(noti_fn, "noti_fn is NULL", err);
353 rtt_status = GET_RTTSTATE(dhd);
354 NULL_CHECK(rtt_status, "rtt_status is NULL", err);
355 spin_lock_bh(¬i_list_lock);
356 list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
357 if (iter->noti_fn == noti_fn) {
361 cb = kmalloc(sizeof(struct rtt_noti_callback), GFP_ATOMIC);
366 cb->noti_fn = noti_fn;
368 list_add(&cb->list, &rtt_status->noti_fn_list);
370 spin_unlock_bh(¬i_list_lock);
375 dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn)
378 struct rtt_noti_callback *cb = NULL, *iter;
379 rtt_status_info_t *rtt_status;
380 NULL_CHECK(dhd, "dhd is NULL", err);
381 NULL_CHECK(noti_fn, "noti_fn is NULL", err);
382 rtt_status = GET_RTTSTATE(dhd);
383 NULL_CHECK(rtt_status, "rtt_status is NULL", err);
384 spin_lock_bh(¬i_list_lock);
385 list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
386 if (iter->noti_fn == noti_fn) {
392 spin_unlock_bh(¬i_list_lock);
400 dhd_rtt_convert_to_host(rtt_result_t *rtt_results, const wl_proxd_event_data_t* evp)
404 char eabuf[ETHER_ADDR_STR_LEN];
407 NULL_CHECK(rtt_results, "rtt_results is NULL", err);
408 NULL_CHECK(evp, "evp is NULL", err);
409 DHD_RTT(("%s enter\n", __FUNCTION__));
410 rtt_results->distance = ntoh32(evp->distance);
411 rtt_results->sdrtt = ntoh32(evp->sdrtt);
412 rtt_results->ftm_cnt = ntoh16(evp->ftm_cnt);
413 rtt_results->avg_rssi = ntoh16(evp->avg_rssi);
414 rtt_results->validfrmcnt = ntoh16(evp->validfrmcnt);
415 rtt_results->meanrtt = ntoh32(evp->meanrtt);
416 rtt_results->modertt = ntoh32(evp->modertt);
417 rtt_results->medianrtt = ntoh32(evp->medianrtt);
418 rtt_results->err_code = evp->err_code;
419 rtt_results->tx_rate.preamble = (evp->OFDM_frame_type == TOF_FRAME_RATE_VHT)? 3 : 0;
420 rtt_results->tx_rate.nss = 0; /* 1 x 1 */
421 rtt_results->tx_rate.bw =
422 (evp->bandwidth == TOF_BW_80MHZ)? 2 : (evp->bandwidth == TOF_BW_40MHZ)? 1 : 0;
423 rtt_results->TOF_type = evp->TOF_type;
424 if (evp->TOF_type == TOF_TYPE_ONE_WAY) {
425 /* convert to 100kbps unit */
426 rtt_results->tx_rate.bitrate = WL_RATE_6M * 5;
427 rtt_results->tx_rate.rateMcsIdx = WL_RATE_6M;
429 rtt_results->tx_rate.bitrate = WL_RATE_6M * 5;
430 rtt_results->tx_rate.rateMcsIdx = 0; /* MCS 0 */
432 memset(diststr, 0, sizeof(diststr));
433 if (rtt_results->distance == 0xffffffff || rtt_results->distance == 0) {
434 sprintf(diststr, "distance=-1m\n");
436 sprintf(diststr, "distance=%d.%d m\n",
437 rtt_results->distance >> 4, ((rtt_results->distance & 0xf) * 125) >> 1);
440 if (ntoh32(evp->mode) == WL_PROXD_MODE_INITIATOR) {
441 DHD_RTT(("Target:(%s) %s;\n", bcm_ether_ntoa((&evp->peer_mac), eabuf), diststr));
442 DHD_RTT(("RTT : mean %d mode %d median %d\n", rtt_results->meanrtt,
443 rtt_results->modertt, rtt_results->medianrtt));
445 DHD_RTT(("Initiator:(%s) %s; ", bcm_ether_ntoa((&evp->peer_mac), eabuf), diststr));
447 if (rtt_results->sdrtt > 0) {
448 DHD_RTT(("sigma:%d.%d\n", rtt_results->sdrtt/10, rtt_results->sdrtt % 10));
450 DHD_RTT(("sigma:0\n"));
453 DHD_RTT(("rssi:%d validfrmcnt %d, err_code : %d\n", rtt_results->avg_rssi,
454 rtt_results->validfrmcnt, evp->err_code));
456 switch (evp->err_code) {
458 rtt_results->err_code = RTT_REASON_SUCCESS;
460 case TOF_REASON_TIMEOUT:
461 rtt_results->err_code = RTT_REASON_TIMEOUT;
463 case TOF_REASON_NOACK:
464 rtt_results->err_code = RTT_REASON_NO_RSP;
466 case TOF_REASON_ABORT:
467 rtt_results->err_code = RTT_REASON_ABORT;
470 rtt_results->err_code = RTT_REASON_FAILURE;
473 rtt_results->peer_mac = evp->peer_mac;
474 /* get the time elapsed from boot time */
475 get_monotonic_boottime(&ts);
476 rtt_results->ts = (uint64) TIMESPEC_TO_US(ts);
478 for (i = 0; i < rtt_results->ftm_cnt; i++) {
479 rtt_results->ftm_buff[i].value = ltoh32(evp->ftm_buff[i].value);
480 rtt_results->ftm_buff[i].rssi = ltoh32(evp->ftm_buff[i].rssi);
486 dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
491 uint status, event_type, flags, reason, ftm_cnt;
492 rtt_status_info_t *rtt_status;
493 wl_proxd_event_data_t* evp;
494 struct rtt_noti_callback *iter;
495 rtt_result_t *rtt_result, *entry, *next;
497 NULL_CHECK(dhd, "dhd is NULL", err);
498 rtt_status = GET_RTTSTATE(dhd);
499 NULL_CHECK(rtt_status, "rtt_status is NULL", err);
500 event_type = ntoh32_ua((void *)&event->event_type);
501 flags = ntoh16_ua((void *)&event->flags);
502 status = ntoh32_ua((void *)&event->status);
503 reason = ntoh32_ua((void *)&event->reason);
505 if (event_type != WLC_E_PROXD) {
508 kflags = in_softirq()? GFP_ATOMIC : GFP_KERNEL;
509 evp = (wl_proxd_event_data_t*)event_data;
510 DHD_RTT(("%s enter : mode: %s, reason :%d \n", __FUNCTION__,
511 (ntoh16(evp->mode) == WL_PROXD_MODE_INITIATOR)?
512 "initiator":"target", reason));
514 case WLC_E_PROXD_STOP:
515 DHD_RTT(("WLC_E_PROXD_STOP\n"));
517 case WLC_E_PROXD_ERROR:
518 case WLC_E_PROXD_COMPLETED:
519 if (reason == WLC_E_PROXD_ERROR) {
520 DHD_RTT(("WLC_E_PROXD_ERROR\n"));
522 DHD_RTT(("WLC_E_PROXD_COMPLETED\n"));
526 mutex_lock(&rtt_status->rtt_mutex);
528 ftm_cnt = ntoh16(evp->ftm_cnt);
531 len = OFFSETOF(rtt_result_t, ftm_buff);
533 len = sizeof(rtt_result_t);
535 /* check whether the results is already reported or not */
536 list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) {
537 if (!memcmp(&entry->peer_mac, &evp->peer_mac, ETHER_ADDR_LEN)) {
539 mutex_unlock(&rtt_status->rtt_mutex);
544 rtt_result = kzalloc(len + sizeof(ftm_sample_t) * ftm_cnt, kflags);
547 mutex_unlock(&rtt_status->rtt_mutex);
552 /* point to target_info in status struct and increase pointer */
553 rtt_result->target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
554 /* find next target to trigger RTT */
555 for (idx = (rtt_status->cur_idx + 1);
556 idx < rtt_status->rtt_config.rtt_target_cnt; idx++) {
557 /* skip the disabled device */
558 if (rtt_status->rtt_config.target_info[idx].disable) {
561 /* set the idx to cur_idx */
562 rtt_status->cur_idx = idx;
566 /* convert the event results to host format */
567 dhd_rtt_convert_to_host(rtt_result, evp);
568 list_add_tail(&rtt_result->list, &rtt_status->rtt_results_cache);
569 if (idx < rtt_status->rtt_config.rtt_target_cnt) {
570 /* restart to measure RTT from next device */
571 schedule_work(&rtt_status->work);
573 DHD_RTT(("RTT_STOPPED\n"));
574 rtt_status->status = RTT_STOPPED;
575 /* to turn on mpc mode */
576 schedule_work(&rtt_status->work);
577 /* notify the completed information to others */
578 list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
579 iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache);
581 /* remove the rtt results in cache */
582 list_for_each_entry_safe(rtt_result, next,
583 &rtt_status->rtt_results_cache, list) {
584 list_del(&rtt_result->list);
587 /* reinit the HEAD */
588 INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
589 /* clear information for rtt_config */
590 bzero(&rtt_status->rtt_config, sizeof(rtt_status->rtt_config));
591 rtt_status->cur_idx = 0;
594 mutex_unlock(&rtt_status->rtt_mutex);
598 case WLC_E_PROXD_GONE:
599 DHD_RTT(("WLC_E_PROXD_GONE\n"));
601 case WLC_E_PROXD_START:
602 /* event for targets / accesspoints */
603 DHD_RTT(("WLC_E_PROXD_START\n"));
605 case WLC_E_PROXD_COLLECT_START:
606 DHD_RTT(("WLC_E_PROXD_COLLECT_START\n"));
608 case WLC_E_PROXD_COLLECT_STOP:
609 DHD_RTT(("WLC_E_PROXD_COLLECT_STOP\n"));
611 case WLC_E_PROXD_COLLECT_COMPLETED:
612 DHD_RTT(("WLC_E_PROXD_COLLECT_COMPLETED\n"));
614 case WLC_E_PROXD_COLLECT_ERROR:
615 DHD_RTT(("WLC_E_PROXD_COLLECT_ERROR; "));
618 DHD_ERROR(("WLC_E_PROXD: supported EVENT reason code:%d\n", reason));
627 dhd_rtt_work(struct work_struct *work)
629 rtt_status_info_t *rtt_status;
631 rtt_status = container_of(work, rtt_status_info_t, work);
632 if (rtt_status == NULL) {
633 DHD_ERROR(("%s : rtt_status is NULL\n", __FUNCTION__));
636 dhd = rtt_status->dhd;
638 DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__));
641 (void) dhd_rtt_start(dhd);
645 dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa)
647 rtt_status_info_t *rtt_status;
649 NULL_CHECK(dhd, "dhd is NULL", err);
650 rtt_status = GET_RTTSTATE(dhd);
651 NULL_CHECK(rtt_status, "rtt_status is NULL", err);
652 NULL_CHECK(capa, "capa is NULL", err);
653 bzero(capa, sizeof(rtt_capabilities_t));
655 if (rtt_status->capability & RTT_CAP_ONE_WAY) {
656 capa->rtt_one_sided_supported = 1;
658 if (rtt_status->capability & RTT_CAP_11V_WAY) {
659 capa->rtt_11v_supported = 1;
661 if (rtt_status->capability & RTT_CAP_11MC_WAY) {
662 capa->rtt_ftm_supported = 1;
664 if (rtt_status->capability & RTT_CAP_VS_WAY) {
665 capa->rtt_vs_supported = 1;
672 dhd_rtt_init(dhd_pub_t *dhd)
675 rtt_status_info_t *rtt_status;
676 NULL_CHECK(dhd, "dhd is NULL", err);
677 if (dhd->rtt_state) {
680 dhd->rtt_state = MALLOC(dhd->osh, sizeof(rtt_status_info_t));
681 if (dhd->rtt_state == NULL) {
682 DHD_ERROR(("failed to create rtt_state\n"));
685 bzero(dhd->rtt_state, sizeof(rtt_status_info_t));
686 rtt_status = GET_RTTSTATE(dhd);
687 rtt_status->dhd = dhd;
688 err = dhd_iovar(dhd, 0, "proxd_params", NULL, 0, 1);
689 if (err != BCME_UNSUPPORTED) {
690 rtt_status->capability |= RTT_CAP_ONE_WAY;
691 rtt_status->capability |= RTT_CAP_VS_WAY;
692 DHD_ERROR(("%s: Support RTT Service\n", __FUNCTION__));
694 mutex_init(&rtt_status->rtt_mutex);
695 INIT_LIST_HEAD(&rtt_status->noti_fn_list);
696 INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
697 INIT_WORK(&rtt_status->work, dhd_rtt_work);
703 dhd_rtt_deinit(dhd_pub_t *dhd)
706 rtt_status_info_t *rtt_status;
707 rtt_result_t *rtt_result, *next;
708 struct rtt_noti_callback *iter, *iter2;
709 NULL_CHECK(dhd, "dhd is NULL", err);
710 rtt_status = GET_RTTSTATE(dhd);
711 NULL_CHECK(rtt_status, "rtt_status is NULL", err);
712 rtt_status->status = RTT_STOPPED;
713 /* clear evt callback list */
714 if (!list_empty(&rtt_status->noti_fn_list)) {
715 list_for_each_entry_safe(iter, iter2, &rtt_status->noti_fn_list, list) {
716 list_del(&iter->list);
720 /* remove the rtt results */
721 if (!list_empty(&rtt_status->rtt_results_cache)) {
722 list_for_each_entry_safe(rtt_result, next, &rtt_status->rtt_results_cache, list) {
723 list_del(&rtt_result->list);
727 MFREE(dhd->osh, dhd->rtt_state, sizeof(rtt_status_info_t));
728 dhd->rtt_state = NULL;
731 #endif /* RTT_SUPPORT */