gscan.cpp revision 28237f92de2634ec1d529c63b2d61d80e7485c83
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 for (int i = 0; i < mParams->num_buckets; i++) { 499 if (mParams->buckets[i].report_events == 1) { 500 ALOGD("Setting num_scans to 1"); 501 num_scans = 1; 502 break; 503 } 504 } 505 506 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, num_scans); 507 if (result < 0) { 508 return result; 509 } 510 511 request.attr_end(data); 512 return WIFI_SUCCESS; 513 } 514 515 int createStartRequest(WifiRequest& request) { 516 return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); 517 } 518 519 int createStopRequest(WifiRequest& request) { 520 return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0); 521 } 522 523 int enableFullScanResultsIfRequired() { 524 /* temporary workaround till we have full support for per bucket scans */ 525 526 ALOGI("enabling full scan results if needed"); 527 int nBuckets = 0; 528 for (int i = 0; i < mParams->num_buckets; i++) { 529 if (mParams->buckets[i].report_events == 2) { 530 nBuckets++; 531 } 532 } 533 534 if (mGlobalFullScanBuckets == 0 && nBuckets != 0) { 535 int result = wifi_enable_full_scan_results(0x1000, ifaceHandle(), mHandler); 536 if (result != WIFI_SUCCESS) { 537 ALOGI("failed to enable full scan results"); 538 return result; 539 } else { 540 ALOGI("successfully enabled full scan results"); 541 } 542 } else { 543 ALOGI("mGlobalFullScanBuckets = %d, nBuckets = %d", mGlobalFullScanBuckets, nBuckets); 544 } 545 546 mLocalFullScanBuckets = nBuckets; 547 mGlobalFullScanBuckets += nBuckets; 548 return WIFI_SUCCESS; 549 } 550 551 int disableFullScanResultsIfRequired() { 552 /* temporary workaround till we have full support for per bucket scans */ 553 554 if (mLocalFullScanBuckets == 0) { 555 return WIFI_SUCCESS; 556 } 557 558 mGlobalFullScanBuckets -= mLocalFullScanBuckets; 559 if (mGlobalFullScanBuckets == 0) { 560 int result = wifi_disable_full_scan_results(0x1000, ifaceHandle()); 561 if (result != WIFI_SUCCESS) { 562 ALOGI("failed to disable full scan results"); 563 } else { 564 ALOGI("successfully disable full scan results"); 565 } 566 } 567 568 return WIFI_SUCCESS; 569 } 570 571 int start() { 572 ALOGD("Setting configuration"); 573 WifiRequest request(familyId(), ifaceId()); 574 int result = createSetupRequest(request); 575 if (result != WIFI_SUCCESS) { 576 ALOGE("failed to create setup request; result = %d", result); 577 return result; 578 } 579 580 result = requestResponse(request); 581 if (result != WIFI_SUCCESS) { 582 ALOGE("failed to configure setup; result = %d", result); 583 return result; 584 } 585 586 request.destroy(); 587 588 result = createScanConfigRequest(request); 589 if (result != WIFI_SUCCESS) { 590 ALOGE("failed to create scan config request; result = %d", result); 591 return result; 592 } 593 594 result = requestResponse(request); 595 if (result != WIFI_SUCCESS) { 596 ALOGE("failed to configure scan; result = %d", result); 597 return result; 598 } 599 600 ALOGD("Starting scan"); 601 602 result = createStartRequest(request); 603 if (result != WIFI_SUCCESS) { 604 ALOGE("failed to create start request; result = %d", result); 605 return result; 606 } 607 608 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); 609 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN); 610 611 612 result = requestResponse(request); 613 if (result != WIFI_SUCCESS) { 614 ALOGE("failed to start scan; result = %d", result); 615 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); 616 return result; 617 } 618 619 result = enableFullScanResultsIfRequired(); 620 return result; 621 } 622 623 virtual int cancel() { 624 ALOGD("Stopping scan"); 625 626 WifiRequest request(familyId(), ifaceId()); 627 int result = createStopRequest(request); 628 if (result != WIFI_SUCCESS) { 629 ALOGE("failed to create stop request; result = %d", result); 630 } else { 631 result = requestResponse(request); 632 if (result != WIFI_SUCCESS) { 633 ALOGE("failed to stop scan; result = %d", result); 634 } 635 } 636 637 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); 638 disableFullScanResultsIfRequired(); 639 640 return WIFI_SUCCESS; 641 } 642 643 virtual int handleResponse(WifiEvent& reply) { 644 /* Nothing to do on response! */ 645 return NL_SKIP; 646 } 647 648 virtual int handleEvent(WifiEvent& event) { 649 ALOGI("Got a scan results event"); 650 651 // event.log(); 652 653 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 654 int len = event.get_vendor_data_len(); 655 int event_id = event.get_vendor_subcmd(); 656 657 if(event_id == GSCAN_EVENT_COMPLETE_SCAN) { 658 if (vendor_data == NULL || len != 4) { 659 ALOGI("Scan complete type not mentioned!"); 660 return NL_SKIP; 661 } 662 wifi_scan_event evt_type; 663 664 evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA); 665 ALOGI("Scan complete: Received event type %d", evt_type); 666 if(*mHandler.on_scan_event) 667 (*mHandler.on_scan_event)(evt_type, evt_type); 668 } else { 669 670 if (vendor_data == NULL || len != 4) { 671 ALOGI("No scan results found"); 672 return NL_SKIP; 673 } 674 675 int num = event.get_u32(NL80211_ATTR_VENDOR_DATA); 676 ALOGI("Found %d scan results", num); 677 if(*mHandler.on_scan_results_available) 678 (*mHandler.on_scan_results_available)(id(), num); 679 } 680 return NL_SKIP; 681 } 682}; 683 684unsigned ScanCommand::mGlobalFullScanBuckets = 0; 685 686wifi_error wifi_start_gscan( 687 wifi_request_id id, 688 wifi_interface_handle iface, 689 wifi_scan_cmd_params params, 690 wifi_scan_result_handler handler) 691{ 692 wifi_handle handle = getWifiHandle(iface); 693 694 ALOGD("Starting GScan, halHandle = %p", handle); 695 696 ScanCommand *cmd = new ScanCommand(iface, id, ¶ms, handler); 697 wifi_register_cmd(handle, id, cmd); 698 return (wifi_error)cmd->start(); 699} 700 701wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface) 702{ 703 ALOGD("Stopping GScan"); 704 wifi_handle handle = getWifiHandle(iface); 705 706 if(id == -1) { 707 wifi_scan_result_handler handler; 708 wifi_scan_cmd_params dummy_params; 709 wifi_handle handle = getWifiHandle(iface); 710 memset(&handler, 0, sizeof(handler)); 711 712 ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler); 713 cmd->cancel(); 714 cmd->releaseRef(); 715 return WIFI_SUCCESS; 716 } 717 718 719 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 720 if (cmd) { 721 cmd->cancel(); 722 cmd->releaseRef(); 723 return WIFI_SUCCESS; 724 } 725 726 return WIFI_ERROR_INVALID_ARGS; 727} 728 729 730wifi_error wifi_enable_full_scan_results( 731 wifi_request_id id, 732 wifi_interface_handle iface, 733 wifi_scan_result_handler handler) 734{ 735 wifi_handle handle = getWifiHandle(iface); 736 int params_dummy; 737 ALOGD("Enabling full scan results, halHandle = %p", handle); 738 739 FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, id, ¶ms_dummy, handler); 740 wifi_register_cmd(handle, id, cmd); 741 742 return (wifi_error)cmd->start(); 743} 744 745wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface) 746{ 747 ALOGD("Disabling full scan results"); 748 wifi_handle handle = getWifiHandle(iface); 749 750 if(id == -1) { 751 wifi_scan_result_handler handler; 752 wifi_handle handle = getWifiHandle(iface); 753 int params_dummy; 754 755 memset(&handler, 0, sizeof(handler)); 756 FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, 0, ¶ms_dummy, handler); 757 cmd->cancel(); 758 cmd->releaseRef(); 759 return WIFI_SUCCESS; 760 } 761 762 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 763 if (cmd) { 764 cmd->cancel(); 765 cmd->releaseRef(); 766 return WIFI_SUCCESS; 767 } 768 769 return WIFI_ERROR_INVALID_ARGS; 770} 771 772 773///////////////////////////////////////////////////////////////////////////// 774 775class GetScanResultsCommand : public WifiCommand { 776 wifi_scan_result *mResults; 777 int mMax; 778 int *mNum; 779 int mRetrieved; 780 byte mFlush; 781 int mCompleted; 782public: 783 GetScanResultsCommand(wifi_interface_handle iface, byte flush, 784 wifi_scan_result *results, int max, int *num) 785 : WifiCommand(iface, -1), mResults(results), mMax(max), mNum(num), 786 mRetrieved(0), mFlush(flush), mCompleted(0) 787 { } 788 789 int createRequest(WifiRequest& request, int num, byte flush) { 790 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS); 791 if (result < 0) { 792 return result; 793 } 794 795 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 796 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num); 797 if (result < 0) { 798 return result; 799 } 800 801 result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush); 802 if (result < 0) { 803 return result; 804 } 805 806 request.attr_end(data); 807 return WIFI_SUCCESS; 808 } 809 810 int execute() { 811 WifiRequest request(familyId(), ifaceId()); 812 ALOGI("retrieving %d scan results", mMax); 813 814 for (int i = 0; i < 10 && mRetrieved < mMax; i++) { 815 int result = createRequest(request, (mMax - mRetrieved), mFlush); 816 if (result < 0) { 817 ALOGE("failed to create request"); 818 return result; 819 } 820 821 int prev_retrieved = mRetrieved; 822 823 result = requestResponse(request); 824 825 if (result != WIFI_SUCCESS) { 826 ALOGE("failed to retrieve scan results; result = %d", result); 827 return result; 828 } 829 830 if (mRetrieved == prev_retrieved || mCompleted) { 831 /* no more items left to retrieve */ 832 break; 833 } 834 835 request.destroy(); 836 } 837 838 ALOGE("GetScanResults read %d results", mRetrieved); 839 *mNum = mRetrieved; 840 return WIFI_SUCCESS; 841 } 842 843 virtual int handleResponse(WifiEvent& reply) { 844 ALOGD("In GetScanResultsCommand::handleResponse"); 845 846 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 847 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 848 return NL_SKIP; 849 } 850 851 int id = reply.get_vendor_id(); 852 int subcmd = reply.get_vendor_subcmd(); 853 854 ALOGD("Id = %0x, subcmd = %d", id, subcmd); 855 856 /* 857 if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) { 858 ALOGE("Invalid response to GetScanResultsCommand; ignoring it"); 859 return NL_SKIP; 860 } 861 */ 862 863 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 864 int len = reply.get_vendor_data_len(); 865 866 if (vendor_data == NULL || len == 0) { 867 ALOGE("no vendor data in GetScanResults response; ignoring it"); 868 return NL_SKIP; 869 } 870 871 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 872 if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) { 873 mCompleted = it.get_u8(); 874 ALOGI("retrieved mCompleted flag : %d", mCompleted); 875 } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) { 876 for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) { 877 int scan_id = 0, flags = 0, num = 0; 878 if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) { 879 scan_id = it.get_u32(); 880 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) { 881 flags = it.get_u8(); 882 } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) { 883 num = it2.get_u32(); 884 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) { 885 num = it2.get_len() / sizeof(wifi_scan_result); 886 num = min(*mNum - mRetrieved, num); 887 memcpy(mResults + mRetrieved, it2.get_data(), 888 sizeof(wifi_scan_result) * num); 889 ALOGI("Retrieved %d scan results", num); 890 wifi_scan_result *results = (wifi_scan_result *)it2.get_data(); 891 for (int i = 0; i < num; i++) { 892 wifi_scan_result *result = results + i; 893 ALOGI("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x %04d", i, 894 result->ssid, result->bssid[0], result->bssid[1], result->bssid[2], 895 result->bssid[3], result->bssid[4], result->bssid[5], 896 result->rssi); 897 } 898 mRetrieved += num; 899 } else { 900 ALOGW("Ignoring invalid attribute type = %d, size = %d", 901 it.get_type(), it.get_len()); 902 } 903 } 904 } else { 905 ALOGW("Ignoring invalid attribute type = %d, size = %d", 906 it.get_type(), it.get_len()); 907 } 908 } 909 910 return NL_OK; 911 } 912}; 913 914wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush, 915 int max, wifi_scan_result *results, int *num) { 916 917 ALOGD("Getting cached scan results, iface handle = %p, num = %d", iface, *num); 918 919 GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num); 920 return (wifi_error)cmd->execute(); 921} 922 923///////////////////////////////////////////////////////////////////////////// 924 925class BssidHotlistCommand : public WifiCommand 926{ 927private: 928 wifi_bssid_hotlist_params mParams; 929 wifi_hotlist_ap_found_handler mHandler; 930 static const int MAX_RESULTS = 64; 931 wifi_scan_result mResults[MAX_RESULTS]; 932public: 933 BssidHotlistCommand(wifi_interface_handle handle, int id, 934 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) 935 : WifiCommand(handle, id), mParams(params), mHandler(handler) 936 { } 937 938 int createSetupRequest(WifiRequest& request) { 939 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); 940 if (result < 0) { 941 return result; 942 } 943 944 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 945 result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); 946 if (result < 0) { 947 return result; 948 } 949 950 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); 951 for (int i = 0; i < mParams.num_ap; i++) { 952 nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM); 953 if (attr2 == NULL) { 954 return WIFI_ERROR_OUT_OF_MEMORY; 955 } 956 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid); 957 if (result < 0) { 958 return result; 959 } 960 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high); 961 if (result < 0) { 962 return result; 963 } 964 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low); 965 if (result < 0) { 966 return result; 967 } 968 request.attr_end(attr2); 969 } 970 971 request.attr_end(attr); 972 request.attr_end(data); 973 return result; 974 } 975 976 int createTeardownRequest(WifiRequest& request) { 977 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); 978 if (result < 0) { 979 return result; 980 } 981 982 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 983 result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); 984 if (result < 0) { 985 return result; 986 } 987 988 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); 989 request.attr_end(attr); 990 request.attr_end(data); 991 return result; 992 } 993 994 int start() { 995 ALOGI("Executing hotlist setup request, num = %d", mParams.num_ap); 996 WifiRequest request(familyId(), ifaceId()); 997 int result = createSetupRequest(request); 998 if (result < 0) { 999 return result; 1000 } 1001 1002 result = requestResponse(request); 1003 if (result < 0) { 1004 ALOGI("Failed to execute hotlist setup request, result = %d", result); 1005 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 1006 return result; 1007 } 1008 1009 ALOGI("Successfully set %d APs in the hotlist", mParams.num_ap); 1010 result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); 1011 if (result < 0) { 1012 return result; 1013 } 1014 1015 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 1016 1017 result = requestResponse(request); 1018 if (result < 0) { 1019 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 1020 return result; 1021 } 1022 1023 ALOGI("successfully restarted the scan"); 1024 return result; 1025 } 1026 1027 virtual int cancel() { 1028 /* unregister event handler */ 1029 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 1030 1031 /* create set hotlist message with empty hotlist */ 1032 WifiRequest request(familyId(), ifaceId()); 1033 int result = createTeardownRequest(request); 1034 if (result < 0) { 1035 return result; 1036 } 1037 1038 result = requestResponse(request); 1039 if (result < 0) { 1040 return result; 1041 } 1042 1043 ALOGI("Successfully reset APs in current hotlist"); 1044 return result; 1045 } 1046 1047 virtual int handleResponse(WifiEvent& reply) { 1048 /* Nothing to do on response! */ 1049 return NL_SKIP; 1050 } 1051 1052 virtual int handleEvent(WifiEvent& event) { 1053 ALOGI("Got a hotlist ap found event"); 1054 1055 // event.log(); 1056 1057 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 1058 int len = event.get_vendor_data_len(); 1059 1060 if (vendor_data == NULL || len == 0) { 1061 ALOGI("No scan results found"); 1062 return NL_SKIP; 1063 } 1064 1065 memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS); 1066 1067 int num = len / sizeof(wifi_scan_result); 1068 num = min(MAX_RESULTS, num); 1069 memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result)); 1070 ALOGI("Retrieved %d hot APs", num); 1071 1072 (*mHandler.on_hotlist_ap_found)(id(), num, mResults); 1073 return NL_SKIP; 1074 } 1075}; 1076 1077wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface, 1078 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) 1079{ 1080 wifi_handle handle = getWifiHandle(iface); 1081 1082 BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler); 1083 wifi_register_cmd(handle, id, cmd); 1084 return (wifi_error)cmd->start(); 1085} 1086 1087wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface) 1088{ 1089 wifi_handle handle = getWifiHandle(iface); 1090 1091 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 1092 if (cmd) { 1093 cmd->cancel(); 1094 cmd->releaseRef(); 1095 return WIFI_SUCCESS; 1096 } 1097 1098 return WIFI_ERROR_INVALID_ARGS; 1099} 1100 1101 1102///////////////////////////////////////////////////////////////////////////// 1103 1104class SignificantWifiChangeCommand : public WifiCommand 1105{ 1106 typedef struct { 1107 mac_addr bssid; // BSSID 1108 wifi_channel channel; // channel frequency in MHz 1109 int num_rssi; // number of rssi samples 1110 wifi_rssi rssi[8]; // RSSI history in db 1111 } wifi_significant_change_result_internal; 1112 1113private: 1114 wifi_significant_change_params mParams; 1115 wifi_significant_change_handler mHandler; 1116 static const int MAX_RESULTS = 64; 1117 wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS]; 1118 wifi_significant_change_result *mResults[MAX_RESULTS]; 1119public: 1120 SignificantWifiChangeCommand(wifi_interface_handle handle, int id, 1121 wifi_significant_change_params params, wifi_significant_change_handler handler) 1122 : WifiCommand(handle, id), mParams(params), mHandler(handler) 1123 { } 1124 1125 int createSetupRequest(WifiRequest& request) { 1126 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); 1127 if (result < 0) { 1128 return result; 1129 } 1130 1131 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 1132 result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); 1133 if (result < 0) { 1134 return result; 1135 } 1136 result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size); 1137 if (result < 0) { 1138 return result; 1139 } 1140 result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size); 1141 if (result < 0) { 1142 return result; 1143 } 1144 result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching); 1145 if (result < 0) { 1146 return result; 1147 } 1148 1149 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS); 1150 1151 for (int i = 0; i < mParams.num_ap; i++) { 1152 1153 nlattr *attr2 = request.attr_start(i); 1154 if (attr2 == NULL) { 1155 return WIFI_ERROR_OUT_OF_MEMORY; 1156 } 1157 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid); 1158 if (result < 0) { 1159 return result; 1160 } 1161 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high); 1162 if (result < 0) { 1163 return result; 1164 } 1165 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low); 1166 if (result < 0) { 1167 return result; 1168 } 1169 request.attr_end(attr2); 1170 } 1171 1172 request.attr_end(attr); 1173 request.attr_end(data); 1174 1175 return result; 1176 } 1177 1178 int createTeardownRequest(WifiRequest& request) { 1179 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); 1180 if (result < 0) { 1181 return result; 1182 } 1183 1184 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 1185 result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); 1186 if (result < 0) { 1187 return result; 1188 } 1189 1190 request.attr_end(data); 1191 return result; 1192 } 1193 1194 int start() { 1195 ALOGI("Set significant wifi change config"); 1196 WifiRequest request(familyId(), ifaceId()); 1197 1198 int result = createSetupRequest(request); 1199 if (result < 0) { 1200 return result; 1201 } 1202 1203 result = requestResponse(request); 1204 if (result < 0) { 1205 ALOGI("failed to set significant wifi change config %d", result); 1206 return result; 1207 } 1208 1209 ALOGI("successfully set significant wifi change config"); 1210 1211 result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); 1212 if (result < 0) { 1213 return result; 1214 } 1215 1216 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); 1217 1218 result = requestResponse(request); 1219 if (result < 0) { 1220 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); 1221 return result; 1222 } 1223 1224 ALOGI("successfully restarted the scan"); 1225 return result; 1226 } 1227 1228 virtual int cancel() { 1229 /* unregister event handler */ 1230 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); 1231 1232 /* create set significant change monitor message with empty hotlist */ 1233 WifiRequest request(familyId(), ifaceId()); 1234 1235 int result = createTeardownRequest(request); 1236 if (result < 0) { 1237 return result; 1238 } 1239 1240 result = requestResponse(request); 1241 if (result < 0) { 1242 return result; 1243 } 1244 1245 ALOGI("successfully reset significant wifi change config"); 1246 return result; 1247 } 1248 1249 virtual int handleResponse(WifiEvent& reply) { 1250 /* Nothing to do on response! */ 1251 return NL_SKIP; 1252 } 1253 1254 virtual int handleEvent(WifiEvent& event) { 1255 ALOGI("Got a significant wifi change event"); 1256 1257 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 1258 int len = event.get_vendor_data_len(); 1259 1260 if (vendor_data == NULL || len == 0) { 1261 ALOGI("No scan results found"); 1262 return NL_SKIP; 1263 } 1264 1265 typedef struct { 1266 uint16_t flags; 1267 uint16_t channel; 1268 mac_addr bssid; 1269 s8 rssi_history[8]; 1270 } ChangeInfo; 1271 1272 int num = min(len / sizeof(ChangeInfo), MAX_RESULTS); 1273 ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data(); 1274 1275 for (int i = 0; i < num; i++) { 1276 memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr)); 1277 mResultsBuffer[i].channel = ci[i].channel; 1278 mResultsBuffer[i].num_rssi = 8; 1279 for (int j = 0; j < mResultsBuffer[i].num_rssi; j++) 1280 mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j]; 1281 mResults[i] = reinterpret_cast<wifi_significant_change_result *>(&(mResultsBuffer[i])); 1282 } 1283 1284 ALOGI("Retrieved %d scan results", num); 1285 1286 if (num != 0) { 1287 (*mHandler.on_significant_change)(id(), num, mResults); 1288 } else { 1289 ALOGW("No significant change reported"); 1290 } 1291 1292 return NL_SKIP; 1293 } 1294}; 1295 1296wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface, 1297 wifi_significant_change_params params, wifi_significant_change_handler handler) 1298{ 1299 wifi_handle handle = getWifiHandle(iface); 1300 1301 SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand( 1302 iface, id, params, handler); 1303 wifi_register_cmd(handle, id, cmd); 1304 return (wifi_error)cmd->start(); 1305} 1306 1307wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface) 1308{ 1309 wifi_handle handle = getWifiHandle(iface); 1310 1311 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 1312 if (cmd) { 1313 cmd->cancel(); 1314 cmd->releaseRef(); 1315 return WIFI_SUCCESS; 1316 } 1317 1318 return WIFI_ERROR_INVALID_ARGS; 1319} 1320