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