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