gscan.cpp revision 9a23388d5a9f58f106169700bb179de0a4af7840
1 2#include <stdint.h> 3#include <fcntl.h> 4#include <sys/socket.h> 5#include <netlink/genl/genl.h> 6#include <netlink/genl/family.h> 7#include <netlink/genl/ctrl.h> 8#include <linux/rtnetlink.h> 9#include <netpacket/packet.h> 10#include <linux/filter.h> 11#include <linux/errqueue.h> 12 13#include <linux/pkt_sched.h> 14#include <netlink/object-api.h> 15#include <netlink/netlink.h> 16#include <netlink/socket.h> 17#include <netlink/handlers.h> 18 19#include "sync.h" 20 21#define LOG_TAG "WifiHAL" 22 23#include <utils/Log.h> 24 25#include "wifi_hal.h" 26#include "common.h" 27#include "cpp_bindings.h" 28 29typedef enum { 30 31 GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, 32 GSCAN_ATTRIBUTE_BASE_PERIOD, 33 GSCAN_ATTRIBUTE_BUCKETS_BAND, 34 GSCAN_ATTRIBUTE_BUCKET_ID, 35 GSCAN_ATTRIBUTE_BUCKET_PERIOD, 36 GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, 37 GSCAN_ATTRIBUTE_BUCKET_CHANNELS, 38 GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, 39 GSCAN_ATTRIBUTE_REPORT_THRESHOLD, 40 GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, 41 GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND, 42 43 GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, 44 GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */ 45 GSCAN_ATTRIBUTE_FLUSH_FEATURE, /* Flush all the configs */ 46 GSCAN_ENABLE_FULL_SCAN_RESULTS, 47 GSCAN_ATTRIBUTE_REPORT_EVENTS, 48 49 /* remaining reserved for additional attributes */ 50 GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, 51 GSCAN_ATTRIBUTE_FLUSH_RESULTS, 52 GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ 53 GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ 54 GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ 55 GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ 56 GSCAN_ATTRIBUTE_NUM_CHANNELS, 57 GSCAN_ATTRIBUTE_CHANNEL_LIST, 58 59 /* remaining reserved for additional attributes */ 60 61 GSCAN_ATTRIBUTE_SSID = 40, 62 GSCAN_ATTRIBUTE_BSSID, 63 GSCAN_ATTRIBUTE_CHANNEL, 64 GSCAN_ATTRIBUTE_RSSI, 65 GSCAN_ATTRIBUTE_TIMESTAMP, 66 GSCAN_ATTRIBUTE_RTT, 67 GSCAN_ATTRIBUTE_RTTSD, 68 69 /* remaining reserved for additional attributes */ 70 71 GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, 72 GSCAN_ATTRIBUTE_RSSI_LOW, 73 GSCAN_ATTRIBUTE_RSSI_HIGH, 74 GSCAN_ATTRIBUTE_HOTLIST_ELEM, 75 GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 76 77 /* remaining reserved for additional attributes */ 78 GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, 79 GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, 80 GSCAN_ATTRIBUTE_MIN_BREACHING, 81 GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, 82 GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 83 84 GSCAN_ATTRIBUTE_MAX 85 86} GSCAN_ATTRIBUTE; 87 88 89// helper methods 90wifi_error wifi_enable_full_scan_results(wifi_request_id id, wifi_interface_handle iface, 91 wifi_scan_result_handler handler); 92wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface); 93 94 95///////////////////////////////////////////////////////////////////////////// 96 97class GetCapabilitiesCommand : public WifiCommand 98{ 99 wifi_gscan_capabilities *mCapabilities; 100public: 101 GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites) 102 : WifiCommand(iface, 0), mCapabilities(capabitlites) 103 { 104 memset(mCapabilities, 0, sizeof(*mCapabilities)); 105 } 106 107 virtual int create() { 108 ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id); 109 110 int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CAPABILITIES); 111 if (ret < 0) { 112 return ret; 113 } 114 115 return ret; 116 } 117 118protected: 119 virtual int handleResponse(WifiEvent& reply) { 120 121 ALOGD("In GetCapabilities::handleResponse"); 122 123 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 124 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 125 return NL_SKIP; 126 } 127 128 int id = reply.get_vendor_id(); 129 int subcmd = reply.get_vendor_subcmd(); 130 131 void *data = reply.get_vendor_data(); 132 int len = reply.get_vendor_data_len(); 133 134 ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, 135 sizeof(*mCapabilities)); 136 137 memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities))); 138 139 return NL_OK; 140 } 141}; 142 143 144wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle, 145 wifi_gscan_capabilities *capabilities) 146{ 147 GetCapabilitiesCommand command(handle, capabilities); 148 return (wifi_error) command.requestResponse(); 149} 150 151class GetChannelListCommand : public WifiCommand 152{ 153 wifi_channel *channels; 154 int max_channels; 155 int *num_channels; 156 int band; 157public: 158 GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num, 159 int num_max_ch, int band) 160 : WifiCommand(iface, 0), channels(channel_buf), max_channels(num_max_ch), num_channels(ch_num), 161 band(band) 162 { 163 memset(channels, 0, sizeof(wifi_channel) * max_channels); 164 } 165 virtual int create() { 166 ALOGD("Creating message to get channel list; iface = %d", mIfaceInfo->id); 167 168 int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CHANNEL_LIST); 169 if (ret < 0) { 170 return ret; 171 } 172 173 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); 174 ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band); 175 if (ret < 0) { 176 return ret; 177 } 178 179 mMsg.attr_end(data); 180 181 return ret; 182 } 183 184protected: 185 virtual int handleResponse(WifiEvent& reply) { 186 187 ALOGD("In GetChannelList::handleResponse"); 188 189 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 190 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 191 return NL_SKIP; 192 } 193 194 int id = reply.get_vendor_id(); 195 int subcmd = reply.get_vendor_subcmd(); 196 int num_channels_to_copy = 0; 197 198 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 199 int len = reply.get_vendor_data_len(); 200 201 ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); 202 if (vendor_data == NULL || len == 0) { 203 ALOGE("no vendor data in GetChannelList response; ignoring it"); 204 return NL_SKIP; 205 } 206 207 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 208 if (it.get_type() == GSCAN_ATTRIBUTE_NUM_CHANNELS) { 209 num_channels_to_copy = it.get_u32(); 210 ALOGI("Got channel list with %d channels", num_channels_to_copy); 211 if(num_channels_to_copy > max_channels) 212 num_channels_to_copy = max_channels; 213 *num_channels = num_channels_to_copy; 214 } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) { 215 memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy); 216 } else { 217 ALOGW("Ignoring invalid attribute type = %d, size = %d", 218 it.get_type(), it.get_len()); 219 } 220 } 221 222 return NL_OK; 223 } 224}; 225 226wifi_error wifi_get_valid_channels(wifi_interface_handle handle, 227 int band, int max_channels, wifi_channel *channels, int *num_channels) 228{ 229 GetChannelListCommand command(handle, channels, num_channels, 230 max_channels, band); 231 return (wifi_error) command.requestResponse(); 232} 233///////////////////////////////////////////////////////////////////////////// 234 235/* helper functions */ 236 237static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr) 238{ 239 memset(results, 0, sizeof(wifi_scan_result) * num); 240 241 int i = 0; 242 for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) { 243 244 int index = it.get_type(); 245 ALOGI("retrieved scan result %d", index); 246 nlattr *sc_data = (nlattr *) it.get_data(); 247 wifi_scan_result *result = results + i; 248 249 for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) { 250 int type = it2.get_type(); 251 if (type == GSCAN_ATTRIBUTE_SSID) { 252 strncpy(result->ssid, (char *) it2.get_data(), it2.get_len()); 253 result->ssid[it2.get_len()] = 0; 254 } else if (type == GSCAN_ATTRIBUTE_BSSID) { 255 memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr)); 256 } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) { 257 result->ts = it2.get_u64(); 258 } else if (type == GSCAN_ATTRIBUTE_CHANNEL) { 259 result->ts = it2.get_u16(); 260 } else if (type == GSCAN_ATTRIBUTE_RSSI) { 261 result->rssi = it2.get_u8(); 262 } else if (type == GSCAN_ATTRIBUTE_RTT) { 263 result->rtt = it2.get_u64(); 264 } else if (type == GSCAN_ATTRIBUTE_RTTSD) { 265 result->rtt_sd = it2.get_u64(); 266 } 267 } 268 269 } 270 271 if (i >= num) { 272 ALOGE("Got too many results; skipping some"); 273 } 274 275 return i; 276} 277 278int createFeatureRequest(WifiRequest& request, int subcmd, int enable) { 279 280 int result = request.create(GOOGLE_OUI, subcmd); 281 if (result < 0) { 282 return result; 283 } 284 285 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 286 result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable); 287 if (result < 0) { 288 return result; 289 } 290 291 request.attr_end(data); 292 return WIFI_SUCCESS; 293} 294 295///////////////////////////////////////////////////////////////////////////// 296class FullScanResultsCommand : public WifiCommand 297{ 298 int *mParams; 299 wifi_scan_result_handler mHandler; 300public: 301 FullScanResultsCommand(wifi_interface_handle iface, int id, int *params, 302 wifi_scan_result_handler handler) 303 : WifiCommand(iface, id), mParams(params), mHandler(handler) 304 { } 305 306 int createRequest(WifiRequest& request, int subcmd, int enable) { 307 int result = request.create(GOOGLE_OUI, subcmd); 308 if (result < 0) { 309 return result; 310 } 311 312 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 313 result = request.put_u32(GSCAN_ENABLE_FULL_SCAN_RESULTS, enable); 314 if (result < 0) { 315 return result; 316 } 317 318 request.attr_end(data); 319 return WIFI_SUCCESS; 320 321 } 322 323 int start() { 324 ALOGD("Enabling Full scan results"); 325 WifiRequest request(familyId(), ifaceId()); 326 int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 1); 327 if (result != WIFI_SUCCESS) { 328 ALOGE("failed to create request; result = %d", result); 329 return result; 330 } 331 332 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); 333 334 result = requestResponse(request); 335 if (result != WIFI_SUCCESS) { 336 ALOGE("failed to enable full scan results; result = %d", result); 337 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); 338 return result; 339 } 340 341 return result; 342 } 343 344 virtual int cancel() { 345 ALOGD("Disabling Full scan results"); 346 347 WifiRequest request(familyId(), ifaceId()); 348 int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 0); 349 if (result != WIFI_SUCCESS) { 350 ALOGE("failed to create request; result = %d", result); 351 } else { 352 result = requestResponse(request); 353 if (result != WIFI_SUCCESS) { 354 ALOGE("failed to disable full scan results;result = %d", result); 355 } 356 } 357 358 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS); 359 return WIFI_SUCCESS; 360 } 361 362 virtual int handleResponse(WifiEvent& reply) { 363 ALOGD("Request complete!"); 364 /* Nothing to do on response! */ 365 return NL_SKIP; 366 } 367 368 virtual int handleEvent(WifiEvent& event) { 369 ALOGI("Full scan results: Got an event"); 370 371 event.log(); 372 373 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 374 unsigned int len = event.get_vendor_data_len(); 375 376 if (vendor_data == NULL || len < sizeof(wifi_scan_result)) { 377 ALOGI("No scan results found"); 378 return NL_SKIP; 379 } 380 381 wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data(); 382 383 if(*mHandler.on_full_scan_result) 384 (*mHandler.on_full_scan_result)(id(), result); 385 386 ALOGI("%-32s\t", result->ssid); 387 388 ALOGI("%02x:%02x:%02x:%02x:%02x:%02x ", result->bssid[0], result->bssid[1], 389 result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5]); 390 391 ALOGI("%d\t", result->rssi); 392 ALOGI("%d\t", result->channel); 393 ALOGI("%lld\t", result->ts); 394 ALOGI("%lld\t", result->rtt); 395 ALOGI("%lld\n", result->rtt_sd); 396 397 398 return NL_SKIP; 399 } 400 401}; 402///////////////////////////////////////////////////////////////////////////// 403 404class ScanCommand : public WifiCommand 405{ 406 wifi_scan_cmd_params *mParams; 407 wifi_scan_result_handler mHandler; 408 static unsigned mGlobalFullScanBuckets; 409 bool mLocalFullScanBuckets; 410public: 411 ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params, 412 wifi_scan_result_handler handler) 413 : WifiCommand(iface, id), mParams(params), mHandler(handler), 414 mLocalFullScanBuckets(0) 415 { } 416 417 int createSetupRequest(WifiRequest& request) { 418 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG); 419 if (result < 0) { 420 return result; 421 } 422 423 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 424 result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period); 425 if (result < 0) { 426 return result; 427 } 428 429 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets); 430 if (result < 0) { 431 return result; 432 } 433 434 for (int i = 0; i < mParams->num_buckets; i++) { 435 nlattr * bucket = request.attr_start(i); // next bucket 436 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket); 437 if (result < 0) { 438 return result; 439 } 440 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period); 441 if (result < 0) { 442 return result; 443 } 444 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND, 445 mParams->buckets[i].band); 446 if (result < 0) { 447 return result; 448 } 449 450 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS, 451 mParams->buckets[i].report_events); 452 if (result < 0) { 453 return result; 454 } 455 456 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, 457 mParams->buckets[i].num_channels); 458 if (result < 0) { 459 return result; 460 } 461 462 if (mParams->buckets[i].num_channels) { 463 nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS); 464 for (int j = 0; j < mParams->buckets[i].num_channels; j++) { 465 result = request.put_u32(j, mParams->buckets[i].channels[j].channel); 466 if (result < 0) { 467 return result; 468 } 469 } 470 request.attr_end(channels); 471 } 472 473 request.attr_end(bucket); 474 } 475 476 request.attr_end(data); 477 return WIFI_SUCCESS; 478 } 479 480 int createScanConfigRequest(WifiRequest& request) { 481 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG); 482 if (result < 0) { 483 return result; 484 } 485 486 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 487 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan); 488 if (result < 0) { 489 return result; 490 } 491 492 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold); 493 if (result < 0) { 494 return result; 495 } 496 497 int num_scans = 20; 498 499 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, num_scans); 500 if (result < 0) { 501 return result; 502 } 503 504 request.attr_end(data); 505 return WIFI_SUCCESS; 506 } 507 508 int createStartRequest(WifiRequest& request) { 509 return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); 510 } 511 512 int createStopRequest(WifiRequest& request) { 513 return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0); 514 } 515 516 int enableFullScanResultsIfRequired() { 517 /* temporary workaround till we have full support for per bucket scans */ 518 519 ALOGI("enabling full scan results if needed"); 520 int nBuckets = 0; 521 for (int i = 0; i < mParams->num_buckets; i++) { 522 if (mParams->buckets[i].report_events == 2) { 523 nBuckets++; 524 } 525 } 526 527 if (mGlobalFullScanBuckets == 0 && nBuckets != 0) { 528 int result = wifi_enable_full_scan_results(0x1000, ifaceHandle(), mHandler); 529 if (result != WIFI_SUCCESS) { 530 ALOGI("failed to enable full scan results"); 531 return result; 532 } else { 533 ALOGI("successfully enabled full scan results"); 534 } 535 } else { 536 ALOGI("mGlobalFullScanBuckets = %d, nBuckets = %d", mGlobalFullScanBuckets, nBuckets); 537 } 538 539 mLocalFullScanBuckets = nBuckets; 540 mGlobalFullScanBuckets += nBuckets; 541 return WIFI_SUCCESS; 542 } 543 544 int disableFullScanResultsIfRequired() { 545 /* temporary workaround till we have full support for per bucket scans */ 546 547 if (mLocalFullScanBuckets == 0) { 548 return WIFI_SUCCESS; 549 } 550 551 mGlobalFullScanBuckets -= mLocalFullScanBuckets; 552 if (mGlobalFullScanBuckets == 0) { 553 int result = wifi_disable_full_scan_results(0x1000, ifaceHandle()); 554 if (result != WIFI_SUCCESS) { 555 ALOGI("failed to disable full scan results"); 556 } else { 557 ALOGI("successfully disable full scan results"); 558 } 559 } 560 561 return WIFI_SUCCESS; 562 } 563 564 int start() { 565 ALOGD("Setting configuration"); 566 WifiRequest request(familyId(), ifaceId()); 567 int result = createSetupRequest(request); 568 if (result != WIFI_SUCCESS) { 569 ALOGE("failed to create setup request; result = %d", result); 570 return result; 571 } 572 573 result = requestResponse(request); 574 if (result != WIFI_SUCCESS) { 575 ALOGE("failed to configure setup; result = %d", result); 576 return result; 577 } 578 579 request.destroy(); 580 581 result = createScanConfigRequest(request); 582 if (result != WIFI_SUCCESS) { 583 ALOGE("failed to create scan config request; result = %d", result); 584 return result; 585 } 586 587 result = requestResponse(request); 588 if (result != WIFI_SUCCESS) { 589 ALOGE("failed to configure scan; result = %d", result); 590 return result; 591 } 592 593 ALOGD("Starting scan"); 594 595 result = createStartRequest(request); 596 if (result != WIFI_SUCCESS) { 597 ALOGE("failed to create start request; result = %d", result); 598 return result; 599 } 600 601 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); 602 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); 603 604 605 result = requestResponse(request); 606 if (result != WIFI_SUCCESS) { 607 ALOGE("failed to start scan; result = %d", result); 608 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); 609 return result; 610 } 611 612 result = enableFullScanResultsIfRequired(); 613 return result; 614 } 615 616 virtual int cancel() { 617 ALOGD("Stopping scan"); 618 619 WifiRequest request(familyId(), ifaceId()); 620 int result = createStopRequest(request); 621 if (result != WIFI_SUCCESS) { 622 ALOGE("failed to create stop request; result = %d", result); 623 } else { 624 result = requestResponse(request); 625 if (result != WIFI_SUCCESS) { 626 ALOGE("failed to stop scan; result = %d", result); 627 } 628 } 629 630 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); 631 disableFullScanResultsIfRequired(); 632 633 return WIFI_SUCCESS; 634 } 635 636 virtual int handleResponse(WifiEvent& reply) { 637 /* Nothing to do on response! */ 638 return NL_SKIP; 639 } 640 641 virtual int handleEvent(WifiEvent& event) { 642 ALOGI("Got a scan results event"); 643 644 // event.log(); 645 646 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 647 int len = event.get_vendor_data_len(); 648 int event_id = event.get_vendor_subcmd(); 649 650 if(event_id == GSCAN_EVENT_COMPLETE_SCAN) { 651 if (vendor_data == NULL || len != 4) { 652 ALOGI("Scan complete type not mentioned!"); 653 return NL_SKIP; 654 } 655 wifi_scan_event evt_type; 656 657 evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA); 658 ALOGI("Scan complete: Received event type %d", evt_type); 659 if(*mHandler.on_scan_event) 660 (*mHandler.on_scan_event)(evt_type, evt_type); 661 } else { 662 663 if (vendor_data == NULL || len != 4) { 664 ALOGI("No scan results found"); 665 return NL_SKIP; 666 } 667 668 int num = event.get_u32(NL80211_ATTR_VENDOR_DATA); 669 ALOGI("Found %d scan results", num); 670 if(*mHandler.on_scan_results_available) 671 (*mHandler.on_scan_results_available)(id(), num); 672 } 673 return NL_SKIP; 674 } 675}; 676 677unsigned ScanCommand::mGlobalFullScanBuckets = 0; 678 679wifi_error wifi_start_gscan( 680 wifi_request_id id, 681 wifi_interface_handle iface, 682 wifi_scan_cmd_params params, 683 wifi_scan_result_handler handler) 684{ 685 wifi_handle handle = getWifiHandle(iface); 686 687 ALOGD("Starting GScan, halHandle = %p", handle); 688 689 ScanCommand *cmd = new ScanCommand(iface, id, ¶ms, handler); 690 wifi_register_cmd(handle, id, cmd); 691 return (wifi_error)cmd->start(); 692} 693 694wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface) 695{ 696 ALOGD("Stopping GScan"); 697 wifi_handle handle = getWifiHandle(iface); 698 699 if(id == -1) { 700 wifi_scan_result_handler handler; 701 wifi_scan_cmd_params dummy_params; 702 wifi_handle handle = getWifiHandle(iface); 703 memset(&handler, 0, sizeof(handler)); 704 705 ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler); 706 cmd->cancel(); 707 delete cmd; 708 return WIFI_SUCCESS; 709 } 710 711 712 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 713 if (cmd) { 714 cmd->cancel(); 715 delete cmd; 716 return WIFI_SUCCESS; 717 } 718 719 return WIFI_ERROR_INVALID_ARGS; 720} 721 722 723wifi_error wifi_enable_full_scan_results( 724 wifi_request_id id, 725 wifi_interface_handle iface, 726 wifi_scan_result_handler handler) 727{ 728 wifi_handle handle = getWifiHandle(iface); 729 int params_dummy; 730 ALOGD("Enabling full scan results, halHandle = %p", handle); 731 732 FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, id, ¶ms_dummy, handler); 733 wifi_register_cmd(handle, id, cmd); 734 735 return (wifi_error)cmd->start(); 736} 737 738wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface) 739{ 740 ALOGD("Disabling full scan results"); 741 wifi_handle handle = getWifiHandle(iface); 742 743 if(id == -1) { 744 wifi_scan_result_handler handler; 745 wifi_handle handle = getWifiHandle(iface); 746 int params_dummy; 747 748 memset(&handler, 0, sizeof(handler)); 749 FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, 0, ¶ms_dummy, handler); 750 cmd->cancel(); 751 delete cmd; 752 return WIFI_SUCCESS; 753 } 754 755 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 756 if (cmd) { 757 cmd->cancel(); 758 delete cmd; 759 return WIFI_SUCCESS; 760 } 761 762 return WIFI_ERROR_INVALID_ARGS; 763} 764 765 766///////////////////////////////////////////////////////////////////////////// 767 768class GetScanResultsCommand : public WifiCommand { 769 wifi_scan_result *mResults; 770 int mMax; 771 int *mNum; 772 int mRetrieved; 773 byte mFlush; 774 int mCompleted; 775public: 776 GetScanResultsCommand(wifi_interface_handle iface, byte flush, 777 wifi_scan_result *results, int max, int *num) 778 : WifiCommand(iface, -1), mResults(results), mMax(max), mNum(num), 779 mRetrieved(0), mFlush(flush), mCompleted(0) 780 { } 781 782 int createRequest(WifiRequest& request, int num, byte flush) { 783 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS); 784 if (result < 0) { 785 return result; 786 } 787 788 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 789 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num); 790 if (result < 0) { 791 return result; 792 } 793 794 result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush); 795 if (result < 0) { 796 return result; 797 } 798 799 request.attr_end(data); 800 return WIFI_SUCCESS; 801 } 802 803 int execute() { 804 WifiRequest request(familyId(), ifaceId()); 805 ALOGI("retrieving %d scan results", mMax); 806 807 for (int i = 0; i < 10 && mRetrieved < mMax; i++) { 808 int result = createRequest(request, (mMax - mRetrieved), mFlush); 809 if (result < 0) { 810 ALOGE("failed to create request"); 811 return result; 812 } 813 814 int prev_retrieved = mRetrieved; 815 816 result = requestResponse(request); 817 818 if (result != WIFI_SUCCESS) { 819 ALOGE("failed to retrieve scan results; result = %d", result); 820 return result; 821 } 822 823 if (mRetrieved == prev_retrieved || mCompleted) { 824 /* no more items left to retrieve */ 825 break; 826 } 827 828 request.destroy(); 829 } 830 831 ALOGE("GetScanResults read %d results", mRetrieved); 832 *mNum = mRetrieved; 833 return WIFI_SUCCESS; 834 } 835 836 virtual int handleResponse(WifiEvent& reply) { 837 ALOGD("In GetScanResultsCommand::handleResponse"); 838 839 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 840 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 841 return NL_SKIP; 842 } 843 844 int id = reply.get_vendor_id(); 845 int subcmd = reply.get_vendor_subcmd(); 846 847 ALOGD("Id = %0x, subcmd = %d", id, subcmd); 848 849 /* 850 if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) { 851 ALOGE("Invalid response to GetScanResultsCommand; ignoring it"); 852 return NL_SKIP; 853 } 854 */ 855 856 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 857 int len = reply.get_vendor_data_len(); 858 859 if (vendor_data == NULL || len == 0) { 860 ALOGE("no vendor data in GetScanResults response; ignoring it"); 861 return NL_SKIP; 862 } 863 864 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 865 if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) { 866 mCompleted = it.get_u8(); 867 ALOGI("retrieved mCompleted flag : %d", mCompleted); 868 } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) { 869 for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) { 870 int scan_id = 0, flags = 0, num = 0; 871 if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) { 872 scan_id = it.get_u32(); 873 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) { 874 flags = it.get_u8(); 875 } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) { 876 num = it2.get_u32(); 877 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) { 878 num = it2.get_len() / sizeof(wifi_scan_result); 879 num = min(*mNum - mRetrieved, num); 880 memcpy(mResults + mRetrieved, it2.get_data(), 881 sizeof(wifi_scan_result) * num); 882 ALOGI("Retrieved %d scan results", num); 883 wifi_scan_result *results = (wifi_scan_result *)it2.get_data(); 884 for (int i = 0; i < num; i++) { 885 wifi_scan_result *result = results + i; 886 ALOGI("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x %04d", i, 887 result->ssid, result->bssid[0], result->bssid[1], result->bssid[2], 888 result->bssid[3], result->bssid[4], result->bssid[5], 889 result->rssi); 890 } 891 mRetrieved += num; 892 } else { 893 ALOGW("Ignoring invalid attribute type = %d, size = %d", 894 it.get_type(), it.get_len()); 895 } 896 } 897 } else { 898 ALOGW("Ignoring invalid attribute type = %d, size = %d", 899 it.get_type(), it.get_len()); 900 } 901 } 902 903 return NL_OK; 904 } 905}; 906 907wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush, 908 int max, wifi_scan_result *results, int *num) { 909 910 ALOGD("Getting cached scan results, iface handle = %p, num = %d", iface, *num); 911 912 GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num); 913 return (wifi_error)cmd->execute(); 914} 915 916///////////////////////////////////////////////////////////////////////////// 917 918class BssidHotlistCommand : public WifiCommand 919{ 920private: 921 wifi_bssid_hotlist_params mParams; 922 wifi_hotlist_ap_found_handler mHandler; 923 static const int MAX_RESULTS = 64; 924 wifi_scan_result mResults[MAX_RESULTS]; 925public: 926 BssidHotlistCommand(wifi_interface_handle handle, int id, 927 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) 928 : WifiCommand(handle, id), mParams(params), mHandler(handler) 929 { } 930 931 int createSetupRequest(WifiRequest& request) { 932 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); 933 if (result < 0) { 934 return result; 935 } 936 937 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 938 result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); 939 if (result < 0) { 940 return result; 941 } 942 943 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); 944 for (int i = 0; i < mParams.num_ap; i++) { 945 nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM); 946 if (attr2 == NULL) { 947 return WIFI_ERROR_OUT_OF_MEMORY; 948 } 949 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid); 950 if (result < 0) { 951 return result; 952 } 953 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high); 954 if (result < 0) { 955 return result; 956 } 957 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low); 958 if (result < 0) { 959 return result; 960 } 961 request.attr_end(attr2); 962 } 963 964 request.attr_end(attr); 965 request.attr_end(data); 966 return result; 967 } 968 969 int createTeardownRequest(WifiRequest& request) { 970 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); 971 if (result < 0) { 972 return result; 973 } 974 975 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 976 result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); 977 if (result < 0) { 978 return result; 979 } 980 981 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); 982 request.attr_end(attr); 983 request.attr_end(data); 984 return result; 985 } 986 987 int start() { 988 ALOGI("Executing hotlist setup request, num = %d", mParams.num_ap); 989 WifiRequest request(familyId(), ifaceId()); 990 int result = createSetupRequest(request); 991 if (result < 0) { 992 return result; 993 } 994 995 result = requestResponse(request); 996 if (result < 0) { 997 ALOGI("Failed to execute hotlist setup request, result = %d", result); 998 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 999 return result; 1000 } 1001 1002 ALOGI("Successfully set %d APs in the hotlist", mParams.num_ap); 1003 result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); 1004 if (result < 0) { 1005 return result; 1006 } 1007 1008 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 1009 1010 result = requestResponse(request); 1011 if (result < 0) { 1012 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 1013 return result; 1014 } 1015 1016 ALOGI("successfully restarted the scan"); 1017 return result; 1018 } 1019 1020 virtual int cancel() { 1021 /* unregister event handler */ 1022 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 1023 1024 /* create set hotlist message with empty hotlist */ 1025 WifiRequest request(familyId(), ifaceId()); 1026 int result = createTeardownRequest(request); 1027 if (result < 0) { 1028 return result; 1029 } 1030 1031 result = requestResponse(request); 1032 if (result < 0) { 1033 return result; 1034 } 1035 1036 ALOGI("Successfully reset APs in current hotlist"); 1037 return result; 1038 } 1039 1040 virtual int handleResponse(WifiEvent& reply) { 1041 /* Nothing to do on response! */ 1042 return NL_SKIP; 1043 } 1044 1045 virtual int handleEvent(WifiEvent& event) { 1046 ALOGI("Got a hotlist ap found event"); 1047 1048 // event.log(); 1049 1050 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 1051 int len = event.get_vendor_data_len(); 1052 1053 if (vendor_data == NULL || len == 0) { 1054 ALOGI("No scan results found"); 1055 return NL_SKIP; 1056 } 1057 1058 memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS); 1059 1060 int num = len / sizeof(wifi_scan_result); 1061 num = min(MAX_RESULTS, num); 1062 memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result)); 1063 ALOGI("Retrieved %d hot APs", num); 1064 1065 (*mHandler.on_hotlist_ap_found)(id(), num, mResults); 1066 return NL_SKIP; 1067 } 1068}; 1069 1070wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface, 1071 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) 1072{ 1073 wifi_handle handle = getWifiHandle(iface); 1074 1075 BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler); 1076 wifi_register_cmd(handle, id, cmd); 1077 return (wifi_error)cmd->start(); 1078} 1079 1080wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface) 1081{ 1082 wifi_handle handle = getWifiHandle(iface); 1083 1084 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 1085 if (cmd) { 1086 cmd->cancel(); 1087 delete cmd; 1088 return WIFI_SUCCESS; 1089 } 1090 1091 return WIFI_ERROR_INVALID_ARGS; 1092} 1093 1094 1095///////////////////////////////////////////////////////////////////////////// 1096 1097class SignificantWifiChangeCommand : public WifiCommand 1098{ 1099 typedef struct { 1100 mac_addr bssid; // BSSID 1101 wifi_channel channel; // channel frequency in MHz 1102 int num_rssi; // number of rssi samples 1103 wifi_rssi rssi[8]; // RSSI history in db 1104 } wifi_significant_change_result_internal; 1105 1106private: 1107 wifi_significant_change_params mParams; 1108 wifi_significant_change_handler mHandler; 1109 static const int MAX_RESULTS = 64; 1110 wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS]; 1111 wifi_significant_change_result *mResults[MAX_RESULTS]; 1112public: 1113 SignificantWifiChangeCommand(wifi_interface_handle handle, int id, 1114 wifi_significant_change_params params, wifi_significant_change_handler handler) 1115 : WifiCommand(handle, id), mParams(params), mHandler(handler) 1116 { } 1117 1118 int createSetupRequest(WifiRequest& request) { 1119 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); 1120 if (result < 0) { 1121 return result; 1122 } 1123 1124 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 1125 result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); 1126 if (result < 0) { 1127 return result; 1128 } 1129 result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size); 1130 if (result < 0) { 1131 return result; 1132 } 1133 result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size); 1134 if (result < 0) { 1135 return result; 1136 } 1137 result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching); 1138 if (result < 0) { 1139 return result; 1140 } 1141 1142 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS); 1143 1144 for (int i = 0; i < mParams.num_ap; i++) { 1145 1146 nlattr *attr2 = request.attr_start(i); 1147 if (attr2 == NULL) { 1148 return WIFI_ERROR_OUT_OF_MEMORY; 1149 } 1150 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid); 1151 if (result < 0) { 1152 return result; 1153 } 1154 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high); 1155 if (result < 0) { 1156 return result; 1157 } 1158 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low); 1159 if (result < 0) { 1160 return result; 1161 } 1162 request.attr_end(attr2); 1163 } 1164 1165 request.attr_end(attr); 1166 request.attr_end(data); 1167 1168 return result; 1169 } 1170 1171 int createTeardownRequest(WifiRequest& request) { 1172 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); 1173 if (result < 0) { 1174 return result; 1175 } 1176 1177 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 1178 result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); 1179 if (result < 0) { 1180 return result; 1181 } 1182 1183 request.attr_end(data); 1184 return result; 1185 } 1186 1187 int start() { 1188 ALOGI("Set significant wifi change config"); 1189 WifiRequest request(familyId(), ifaceId()); 1190 1191 int result = createSetupRequest(request); 1192 if (result < 0) { 1193 return result; 1194 } 1195 1196 result = requestResponse(request); 1197 if (result < 0) { 1198 ALOGI("failed to set significant wifi change config %d", result); 1199 return result; 1200 } 1201 1202 ALOGI("successfully set significant wifi change config"); 1203 1204 result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); 1205 if (result < 0) { 1206 return result; 1207 } 1208 1209 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); 1210 1211 result = requestResponse(request); 1212 if (result < 0) { 1213 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); 1214 return result; 1215 } 1216 1217 ALOGI("successfully restarted the scan"); 1218 return result; 1219 } 1220 1221 virtual int cancel() { 1222 /* unregister event handler */ 1223 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); 1224 1225 /* create set significant change monitor message with empty hotlist */ 1226 WifiRequest request(familyId(), ifaceId()); 1227 1228 int result = createTeardownRequest(request); 1229 if (result < 0) { 1230 return result; 1231 } 1232 1233 result = requestResponse(request); 1234 if (result < 0) { 1235 return result; 1236 } 1237 1238 ALOGI("successfully reset significant wifi change config"); 1239 return result; 1240 } 1241 1242 virtual int handleResponse(WifiEvent& reply) { 1243 /* Nothing to do on response! */ 1244 return NL_SKIP; 1245 } 1246 1247 virtual int handleEvent(WifiEvent& event) { 1248 ALOGI("Got a significant wifi change event"); 1249 1250 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 1251 int len = event.get_vendor_data_len(); 1252 1253 if (vendor_data == NULL || len == 0) { 1254 ALOGI("No scan results found"); 1255 return NL_SKIP; 1256 } 1257 1258 typedef struct { 1259 uint16_t flags; 1260 uint16_t channel; 1261 mac_addr bssid; 1262 s8 rssi_history[8]; 1263 } ChangeInfo; 1264 1265 int num = min(len / sizeof(ChangeInfo), MAX_RESULTS); 1266 ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data(); 1267 1268 for (int i = 0; i < num; i++) { 1269 memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr)); 1270 mResultsBuffer[i].channel = ci[i].channel; 1271 mResultsBuffer[i].num_rssi = 8; 1272 for (int j = 0; j < mResultsBuffer[i].num_rssi; j++) 1273 mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j]; 1274 mResults[i] = reinterpret_cast<wifi_significant_change_result *>(&(mResultsBuffer[i])); 1275 } 1276 1277 ALOGI("Retrieved %d scan results", num); 1278 1279 if (num != 0) { 1280 (*mHandler.on_significant_change)(id(), num, mResults); 1281 } else { 1282 ALOGW("No significant change reported"); 1283 } 1284 1285 return NL_SKIP; 1286 } 1287}; 1288 1289wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface, 1290 wifi_significant_change_params params, wifi_significant_change_handler handler) 1291{ 1292 wifi_handle handle = getWifiHandle(iface); 1293 1294 SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand( 1295 iface, id, params, handler); 1296 wifi_register_cmd(handle, id, cmd); 1297 return (wifi_error)cmd->start(); 1298} 1299 1300wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface) 1301{ 1302 wifi_handle handle = getWifiHandle(iface); 1303 1304 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 1305 if (cmd) { 1306 cmd->cancel(); 1307 delete cmd; 1308 return WIFI_SUCCESS; 1309 } 1310 1311 return WIFI_ERROR_INVALID_ARGS; 1312} 1313