net: wireless: bcmdhd: update bcm4358 FW (7.112.201.3) am: 38cfc377c2 am: 0c97e9a22b
[android/platform/hardware/broadcom/wlan.git] / bcmdhd / wifi_hal / rtt.cpp
1 #include <stdint.h>
2 #include <fcntl.h>
3 #include <sys/socket.h>
4 #include <netlink/genl/genl.h>
5 #include <netlink/genl/family.h>
6 #include <netlink/genl/ctrl.h>
7 #include <linux/rtnetlink.h>
8 #include <netpacket/packet.h>
9 #include <linux/filter.h>
10 #include <linux/errqueue.h>
11
12 #include <linux/pkt_sched.h>
13 #include <netlink/object-api.h>
14 #include <netlink/netlink.h>
15 #include <netlink/socket.h>
16 #include <netlink-private/object-api.h>
17 #include <netlink-private/types.h>
18
19 #include "nl80211_copy.h"
20
21 #include "sync.h"
22
23 #define LOG_TAG  "WifiHAL"
24
25 #include <utils/Log.h>
26 #include <utils/String8.h>
27
28 #include "wifi_hal.h"
29 #include "common.h"
30 #include "cpp_bindings.h"
31
32 using namespace android;
33 #define RTT_RESULT_SIZE (sizeof(wifi_rtt_result));
34 typedef enum {
35
36     RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
37     RTT_SUBCMD_CANCEL_CONFIG,
38     RTT_SUBCMD_GETCAPABILITY,
39     RTT_SUBCMD_GETAVAILCHANNEL,
40     RTT_SUBCMD_SET_RESPONDER,
41     RTT_SUBCMD_CANCEL_RESPONDER,
42 } RTT_SUB_COMMAND;
43
44 typedef enum {
45     RTT_ATTRIBUTE_TARGET_CNT = 0,
46     RTT_ATTRIBUTE_TARGET_INFO,
47     RTT_ATTRIBUTE_TARGET_MAC,
48     RTT_ATTRIBUTE_TARGET_TYPE,
49     RTT_ATTRIBUTE_TARGET_PEER,
50     RTT_ATTRIBUTE_TARGET_CHAN,
51     RTT_ATTRIBUTE_TARGET_PERIOD,
52     RTT_ATTRIBUTE_TARGET_NUM_BURST,
53     RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
54     RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
55     RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
56     RTT_ATTRIBUTE_TARGET_LCI,
57     RTT_ATTRIBUTE_TARGET_LCR,
58     RTT_ATTRIBUTE_TARGET_BURST_DURATION,
59     RTT_ATTRIBUTE_TARGET_PREAMBLE,
60     RTT_ATTRIBUTE_TARGET_BW,
61     RTT_ATTRIBUTE_RESULTS_COMPLETE = 30,
62     RTT_ATTRIBUTE_RESULTS_PER_TARGET,
63     RTT_ATTRIBUTE_RESULT_CNT,
64     RTT_ATTRIBUTE_RESULT
65 } RTT_ATTRIBUTE;
66 typedef struct strmap_entry {
67     int                 id;
68     String8             text;
69 } strmap_entry_t;
70 struct dot11_rm_ie {
71     u8 id;
72     u8 len;
73     u8 token;
74     u8 mode;
75     u8 type;
76 } __attribute__ ((packed));
77 typedef struct dot11_rm_ie dot11_rm_ie_t;
78 #define DOT11_HDR_LEN 2
79 #define DOT11_RM_IE_LEN       5
80 #define DOT11_MNG_MEASURE_REQUEST_ID            38      /* 11H MeasurementRequest */
81 #define DOT11_MEASURE_TYPE_LCI          8   /* d11 measurement LCI type */
82 #define DOT11_MEASURE_TYPE_CIVICLOC     11  /* d11 measurement location civic */
83
84 static const strmap_entry_t err_info[] = {
85     {RTT_STATUS_SUCCESS, String8("Success")},
86     {RTT_STATUS_FAILURE, String8("Failure")},
87     {RTT_STATUS_FAIL_NO_RSP, String8("No reponse")},
88     {RTT_STATUS_FAIL_INVALID_TS, String8("Invalid Timestamp")},
89     {RTT_STATUS_FAIL_PROTOCOL, String8("Protocol error")},
90     {RTT_STATUS_FAIL_REJECTED, String8("Rejected")},
91     {RTT_STATUS_FAIL_NOT_SCHEDULED_YET, String8("not scheduled")},
92     {RTT_STATUS_FAIL_SCHEDULE,  String8("schedule failed")},
93     {RTT_STATUS_FAIL_TM_TIMEOUT, String8("timeout")},
94     {RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, String8("AP is on difference channel")},
95     {RTT_STATUS_FAIL_NO_CAPABILITY, String8("no capability")},
96     {RTT_STATUS_FAIL_BUSY_TRY_LATER, String8("busy and try later")},
97     {RTT_STATUS_ABORTED, String8("aborted")}
98 };
99
100     static const char*
101 get_err_info(int status)
102 {
103     int i;
104     const strmap_entry_t *p_entry;
105     int num_entries = sizeof(err_info)/ sizeof(err_info[0]);
106     /* scan thru the table till end */
107     p_entry = err_info;
108     for (i = 0; i < (int) num_entries; i++)
109     {
110         if (p_entry->id == status)
111             return p_entry->text;
112         p_entry++;              /* next entry */
113     }
114     return "unknown error";                     /* not found */
115 }
116
117 class GetRttCapabilitiesCommand : public WifiCommand
118 {
119     wifi_rtt_capabilities *mCapabilities;
120 public:
121     GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites)
122         : WifiCommand("GetRttCapabilitiesCommand", iface, 0), mCapabilities(capabitlites)
123     {
124         memset(mCapabilities, 0, sizeof(*mCapabilities));
125     }
126
127     virtual int create() {
128         ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);
129
130         int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETCAPABILITY);
131         if (ret < 0) {
132             return ret;
133         }
134
135         return ret;
136     }
137
138 protected:
139     virtual int handleResponse(WifiEvent& reply) {
140
141         ALOGD("In GetRttCapabilitiesCommand::handleResponse");
142
143         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
144             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
145             return NL_SKIP;
146         }
147
148         int id = reply.get_vendor_id();
149         int subcmd = reply.get_vendor_subcmd();
150
151         void *data = reply.get_vendor_data();
152         int len = reply.get_vendor_data_len();
153
154         ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
155                 sizeof(*mCapabilities));
156
157         memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
158
159         return NL_OK;
160     }
161 };
162
163
164 class GetRttResponderInfoCommand : public WifiCommand
165 {
166     wifi_rtt_responder* mResponderInfo;
167 public:
168     GetRttResponderInfoCommand(wifi_interface_handle iface, wifi_rtt_responder *responderInfo)
169         : WifiCommand("GetRttResponderInfoCommand", iface, 0), mResponderInfo(responderInfo)
170     {
171         memset(mResponderInfo, 0 , sizeof(*mResponderInfo));
172
173     }
174
175     virtual int create() {
176         ALOGD("Creating message to get responder info ; iface = %d", mIfaceInfo->id);
177
178         int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETAVAILCHANNEL);
179         if (ret < 0) {
180             return ret;
181         }
182
183         return ret;
184     }
185
186 protected:
187     virtual int handleResponse(WifiEvent& reply) {
188
189         ALOGD("In GetRttResponderInfoCommand::handleResponse");
190
191         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
192             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
193             return NL_SKIP;
194         }
195
196         int id = reply.get_vendor_id();
197         int subcmd = reply.get_vendor_subcmd();
198
199         void *data = reply.get_vendor_data();
200         int len = reply.get_vendor_data_len();
201
202         ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
203                 sizeof(*mResponderInfo));
204
205         memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
206
207         return NL_OK;
208     }
209 };
210
211
212 class EnableResponderCommand : public WifiCommand
213 {
214     wifi_channel_info  mChannelInfo;
215     wifi_rtt_responder* mResponderInfo;
216     unsigned m_max_duration_sec;
217 public:
218     EnableResponderCommand(wifi_interface_handle iface, int id, wifi_channel_info channel_hint,
219             unsigned max_duration_seconds, wifi_rtt_responder *responderInfo)
220             : WifiCommand("EnableResponderCommand", iface, 0), mChannelInfo(channel_hint),
221             m_max_duration_sec(max_duration_seconds), mResponderInfo(responderInfo)
222     {
223         memset(mResponderInfo, 0, sizeof(*mResponderInfo));
224     }
225
226     virtual int create() {
227         ALOGD("Creating message to set responder ; iface = %d", mIfaceInfo->id);
228
229         int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_SET_RESPONDER);
230         if (ret < 0) {
231             return ret;
232         }
233
234         return ret;
235     }
236
237 protected:
238     virtual int handleResponse(WifiEvent& reply) {
239
240         ALOGD("In EnableResponderCommand::handleResponse");
241
242         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
243             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
244             return NL_SKIP;
245         }
246
247         int id = reply.get_vendor_id();
248         int subcmd = reply.get_vendor_subcmd();
249
250         void *data = reply.get_vendor_data();
251         int len = reply.get_vendor_data_len();
252
253         ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
254                 sizeof(*mResponderInfo));
255
256         memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
257
258         return NL_OK;
259     }
260 };
261
262
263 class CancelResponderCommand : public WifiCommand
264 {
265
266 public:
267     CancelResponderCommand(wifi_interface_handle iface, int id)
268         : WifiCommand("CancelResponderCommand", iface, 0)/*, mChannelInfo(channel)*/
269     {
270
271     }
272
273     virtual int create() {
274         ALOGD("Creating message to cancel responder ; iface = %d", mIfaceInfo->id);
275
276         int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_RESPONDER);
277         if (ret < 0) {
278             return ret;
279         }
280
281         return ret;
282     }
283
284 protected:
285     virtual int handleResponse(WifiEvent& reply) {
286         /* Nothing to do on response! */
287         return NL_SKIP;
288     }
289
290 };
291
292
293 class RttCommand : public WifiCommand
294 {
295     unsigned numRttParams;
296     int mCompleted;
297     int currentIdx;
298     int totalCnt;
299     static const int MAX_RESULTS = 1024;
300     wifi_rtt_result *rttResults[MAX_RESULTS];
301     wifi_rtt_config *rttParams;
302     wifi_rtt_event_handler rttHandler;
303 public:
304     RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config,
305             wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
306         : WifiCommand("RttCommand", iface, id), numRttParams(num_rtt_config), rttParams(rtt_config),
307         rttHandler(handler)
308     {
309         memset(rttResults, 0, sizeof(rttResults));
310         currentIdx = 0;
311         mCompleted = 0;
312         totalCnt = 0;
313     }
314
315     RttCommand(wifi_interface_handle iface, int id)
316         : WifiCommand("RttCommand", iface, id)
317     {
318         currentIdx = 0;
319         mCompleted = 0;
320         totalCnt = 0;
321         numRttParams = 0;
322     }
323
324     int createSetupRequest(WifiRequest& request) {
325         int result = request.create(GOOGLE_OUI, RTT_SUBCMD_SET_CONFIG);
326         if (result < 0) {
327             return result;
328         }
329
330         nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
331         result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, numRttParams);
332         if (result < 0) {
333             return result;
334         }
335         nlattr *rtt_config = request.attr_start(RTT_ATTRIBUTE_TARGET_INFO);
336         for (unsigned i = 0; i < numRttParams; i++) {
337             nlattr *attr2 = request.attr_start(i);
338             if (attr2 == NULL) {
339                 return WIFI_ERROR_OUT_OF_MEMORY;
340             }
341
342             result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr);
343             if (result < 0) {
344                 return result;
345             }
346
347             result = request.put_u8(RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type);
348             if (result < 0) {
349                 return result;
350             }
351
352             result = request.put_u8(RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer);
353             if (result < 0) {
354                 return result;
355             }
356
357             result = request.put(RTT_ATTRIBUTE_TARGET_CHAN, &rttParams[i].channel,
358                     sizeof(wifi_channel_info));
359             if (result < 0) {
360                 return result;
361             }
362
363             result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_BURST, rttParams[i].num_burst);
364             if (result < 0) {
365                 return result;
366             }
367
368             result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
369                     rttParams[i].num_frames_per_burst);
370             if (result < 0) {
371                 return result;
372             }
373
374             result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
375                     rttParams[i].num_retries_per_rtt_frame);
376             if (result < 0) {
377                 return result;
378             }
379
380             result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
381                     rttParams[i].num_retries_per_ftmr);
382             if (result < 0) {
383                 return result;
384             }
385
386             result = request.put_u32(RTT_ATTRIBUTE_TARGET_PERIOD,
387                     rttParams[i].burst_period);
388             if (result < 0) {
389                 return result;
390             }
391
392             result = request.put_u32(RTT_ATTRIBUTE_TARGET_BURST_DURATION,
393                     rttParams[i].burst_duration);
394             if (result < 0) {
395                 return result;
396             }
397
398             result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCI,
399                     rttParams[i].LCI_request);
400             if (result < 0) {
401                 return result;
402             }
403
404             result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCR,
405                     rttParams[i].LCR_request);
406             if (result < 0) {
407                 return result;
408             }
409
410             result = request.put_u8(RTT_ATTRIBUTE_TARGET_BW,
411                     rttParams[i].bw);
412             if (result < 0) {
413                 return result;
414             }
415
416             result = request.put_u8(RTT_ATTRIBUTE_TARGET_PREAMBLE,
417                     rttParams[i].preamble);
418             if (result < 0) {
419                 return result;
420             }
421             request.attr_end(attr2);
422         }
423
424         request.attr_end(rtt_config);
425         request.attr_end(data);
426         return WIFI_SUCCESS;
427     }
428
429     int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) {
430         int result = request.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_CONFIG);
431         if (result < 0) {
432             return result;
433         }
434
435         nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
436         request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices);
437         for(unsigned i = 0; i < num_devices; i++) {
438             result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]);
439             if (result < 0) {
440                 return result;
441             }
442         }
443         request.attr_end(data);
444         return result;
445     }
446     int start() {
447         ALOGD("Setting RTT configuration");
448         WifiRequest request(familyId(), ifaceId());
449         int result = createSetupRequest(request);
450         if (result != WIFI_SUCCESS) {
451             ALOGE("failed to create setup request; result = %d", result);
452             return result;
453         }
454
455         result = requestResponse(request);
456         if (result != WIFI_SUCCESS) {
457             ALOGE("failed to configure RTT setup; result = %d", result);
458             return result;
459         }
460
461         registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
462         ALOGI("Successfully started RTT operation");
463         return result;
464     }
465
466     virtual int cancel() {
467         ALOGD("Stopping RTT");
468
469         WifiRequest request(familyId(), ifaceId());
470         int result = createTeardownRequest(request, 0, NULL);
471         if (result != WIFI_SUCCESS) {
472             ALOGE("failed to create stop request; result = %d", result);
473         } else {
474             result = requestResponse(request);
475             if (result != WIFI_SUCCESS) {
476                 ALOGE("failed to stop scan; result = %d", result);
477             }
478         }
479
480         unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
481         return WIFI_SUCCESS;
482     }
483
484     int cancel_specific(unsigned num_devices, mac_addr addr[]) {
485         ALOGE("Stopping RTT");
486
487         WifiRequest request(familyId(), ifaceId());
488         int result = createTeardownRequest(request, num_devices, addr);
489         if (result != WIFI_SUCCESS) {
490             ALOGE("failed to create stop request; result = %d", result);
491         } else {
492             result = requestResponse(request);
493             if (result != WIFI_SUCCESS) {
494                 ALOGE("failed to stop RTT; result = %d", result);
495             }
496         }
497
498         unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
499         return WIFI_SUCCESS;
500     }
501
502     virtual int handleResponse(WifiEvent& reply) {
503         /* Nothing to do on response! */
504         return NL_SKIP;
505     }
506
507     virtual int handleEvent(WifiEvent& event) {
508         ALOGI("Got an RTT event");
509         nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
510         int len = event.get_vendor_data_len();
511         if (vendor_data == NULL || len == 0) {
512             ALOGI("No rtt results found");
513         }
514         for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
515             if (it.get_type() == RTT_ATTRIBUTE_RESULTS_COMPLETE) {
516                 mCompleted = it.get_u32();
517                 ALOGI("retrieved completed flag : %d\n", mCompleted);
518             } else if (it.get_type() == RTT_ATTRIBUTE_RESULTS_PER_TARGET) {
519                 int result_cnt = 0;
520                 mac_addr bssid;
521                 for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
522                     if (it2.get_type() == RTT_ATTRIBUTE_TARGET_MAC) {
523                         memcpy(bssid, it2.get_data(), sizeof(mac_addr));
524                         ALOGI("retrived target mac : %02x:%02x:%02x:%02x:%02x:%02x\n",
525                                 bssid[0],
526                                 bssid[1],
527                                 bssid[2],
528                                 bssid[3],
529                                 bssid[4],
530                                 bssid[5]);
531                     } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT_CNT) {
532                         result_cnt = it2.get_u32();
533                         ALOGI("retrieved result_cnt : %d\n", result_cnt);
534                     } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT) {
535                         int result_len = it2.get_len();
536                         rttResults[currentIdx] =  (wifi_rtt_result *)malloc(it2.get_len());
537                         wifi_rtt_result *rtt_result = rttResults[currentIdx];
538                         if (rtt_result == NULL) {
539                             mCompleted = 1;
540                             ALOGE("failed to allocate the wifi_rtt_result\n");
541                             break;
542                         }
543                         memcpy(rtt_result, it2.get_data(), it2.get_len());
544                         result_len -= sizeof(wifi_rtt_result);
545                         if (result_len > 0) {
546                             result_len -= sizeof(wifi_rtt_result);
547                             dot11_rm_ie_t *ele_1;
548                             dot11_rm_ie_t *ele_2;
549                             /* The result has LCI or LCR element */
550                             ele_1 = (dot11_rm_ie_t *)(rtt_result + 1);
551                             if (ele_1->id == DOT11_MNG_MEASURE_REQUEST_ID) {
552                                 if (ele_1->type == DOT11_MEASURE_TYPE_LCI) {
553                                     rtt_result->LCI = (wifi_information_element *)ele_1;
554                                     result_len -= (ele_1->len + DOT11_HDR_LEN);
555                                     /* get a next rm ie */
556                                     if (result_len > 0) {
557                                         ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
558                                         if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
559                                                 (ele_2->type == DOT11_MEASURE_TYPE_CIVICLOC)) {
560                                             rtt_result->LCR = (wifi_information_element *)ele_2;
561                                         }
562                                     }
563                                 } else if (ele_1->type == DOT11_MEASURE_TYPE_CIVICLOC){
564                                     rtt_result->LCR = (wifi_information_element *)ele_1;
565                                     result_len -= (ele_1->len + DOT11_HDR_LEN);
566                                     /* get a next rm ie */
567                                     if (result_len > 0) {
568                                         ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
569                                         if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
570                                                 (ele_2->type == DOT11_MEASURE_TYPE_LCI)) {
571                                             rtt_result->LCI = (wifi_information_element *)ele_2;
572                                         }
573                                     }
574                                 }
575                             }
576                         }
577                         totalCnt++;
578                         ALOGI("retrived rtt_result : \n\tburst_num :%d, measurement_number : %d, success_number : %d\n"
579                                 "\tnumber_per_burst_peer : %d, status : %s, retry_after_duration : %d s\n"
580                                 "\trssi : %d dbm, rx_rate : %d Kbps, rtt : %llu ns, rtt_sd : %llu\n"
581                                 "\tdistance : %d, burst_duration : %d ms, negotiated_burst_num : %d\n",
582                                 rtt_result->burst_num, rtt_result->measurement_number,
583                                 rtt_result->success_number, rtt_result->number_per_burst_peer,
584                                 get_err_info(rtt_result->status), rtt_result->retry_after_duration,
585                                 rtt_result->rssi, rtt_result->rx_rate.bitrate * 100,
586                                 rtt_result->rtt/10, rtt_result->rtt_sd, rtt_result->distance_mm / 10,
587                                 rtt_result->burst_duration, rtt_result->negotiated_burst_num);
588                         currentIdx++;
589                     }
590                 }
591             }
592
593         }
594         if (mCompleted) {
595             unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
596             (*rttHandler.on_rtt_results)(id(), totalCnt, rttResults);
597             for (int i = 0; i < currentIdx; i++) {
598                 free(rttResults[i]);
599                 rttResults[i] = NULL;
600             }
601             totalCnt = currentIdx = 0;
602             WifiCommand *cmd = wifi_unregister_cmd(wifiHandle(), id());
603             if (cmd)
604                 cmd->releaseRef();
605         }
606         return NL_SKIP;
607     }
608 };
609
610
611 /* API to request RTT measurement */
612 wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
613         unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
614 {
615     wifi_handle handle = getWifiHandle(iface);
616     RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler);
617     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
618     wifi_error result = wifi_register_cmd(handle, id, cmd);
619     if (result != WIFI_SUCCESS) {
620         cmd->releaseRef();
621         return result;
622     }
623     result = (wifi_error)cmd->start();
624     if (result != WIFI_SUCCESS) {
625         wifi_unregister_cmd(handle, id);
626         cmd->releaseRef();
627         return result;
628     }
629     return result;
630 }
631
632 /* API to cancel RTT measurements */
633 wifi_error wifi_rtt_range_cancel(wifi_request_id id,  wifi_interface_handle iface,
634         unsigned num_devices, mac_addr addr[])
635 {
636     wifi_handle handle = getWifiHandle(iface);
637     RttCommand *cmd = new RttCommand(iface, id);
638     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
639     cmd->cancel_specific(num_devices, addr);
640     cmd->releaseRef();
641     return WIFI_SUCCESS;
642 }
643
644 /* API to get RTT capability */
645 wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
646         wifi_rtt_capabilities *capabilities)
647 {
648     GetRttCapabilitiesCommand command(iface, capabilities);
649     return (wifi_error) command.requestResponse();
650 }
651
652 /* API to get the responder information */
653 wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
654         wifi_rtt_responder* responderInfo)
655 {
656     GetRttResponderInfoCommand command(iface, responderInfo);
657     return (wifi_error) command.requestResponse();
658
659 }
660
661 /**
662  * Enable RTT responder mode.
663  * channel_hint - hint of the channel information where RTT responder should be enabled on.
664  * max_duration_seconds - timeout of responder mode.
665  * wifi_rtt_responder - information for RTT responder e.g. channel used and preamble supported.
666  */
667 wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface,
668                                 wifi_channel_info channel_hint, unsigned max_duration_seconds,
669                                 wifi_rtt_responder* responderInfo)
670 {
671     EnableResponderCommand command(iface, id, channel_hint, max_duration_seconds, responderInfo);
672     return (wifi_error) command.requestResponse();
673 }
674
675 /**
676  * Disable RTT responder mode.
677  */
678 wifi_error wifi_disable_responder(wifi_request_id id, wifi_interface_handle iface)
679 {
680     CancelResponderCommand command(iface, id);
681     return (wifi_error) command.requestResponse();
682 }
683