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