Home | History | Annotate | Download | only in wifi_hal
      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 
    684