gscan.cpp revision 1a526434ae215b48970501ccb463d4e77af39c9e
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-types.h> 18 19#include "nl80211_copy.h" 20 21#include "sync.h" 22 23#define LOG_TAG "WifiHAL" 24 25#include <utils/Log.h> 26 27#include "wifi_hal.h" 28#include "common.h" 29#include "cpp_bindings.h" 30 31typedef enum { 32 BRCM_RESERVED1, 33 BRCM_RESERVED2, 34 GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS , 35 GSCAN_EVENT_HOTLIST_RESULTS, 36 GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, 37 38} GSCAN_EVENT; 39 40typedef enum { 41 42 GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START, 43 44 GSCAN_SUBCMD_SET_CONFIG, /* 0x1001 */ 45 46 GSCAN_SUBCMD_SET_SCAN_CONFIG, /* 0x1002 */ 47 GSCAN_SUBCMD_ENABLE_GSCAN, /* 0x1003 */ 48 GSCAN_SUBCMD_GET_SCAN_RESULTS, /* 0x1004 */ 49 GSCAN_SUBCMD_SCAN_RESULTS, /* 0x1005 */ 50 51 GSCAN_SUBCMD_SET_HOTLIST, /* 0x1006 */ 52 53 GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, /* 0x1007 */ 54 55 /* Add more sub commands here */ 56 57 GSCAN_SUBCMD_MAX /* 0x1008 */ 58 59} GSCAN_SUB_COMMAND; 60 61typedef enum { 62 63 GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, 64 GSCAN_ATTRIBUTE_BASE_PERIOD, 65 GSCAN_ATTRIBUTE_BUCKETS, 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 78 /* remaining reserved for additional attributes */ 79 GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, 80 GSCAN_ATTRIBUTE_FLUSH_RESULTS, 81 GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ 82 GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ 83 GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ 84 GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ 85 86 /* remaining reserved for additional attributes */ 87 88 GSCAN_ATTRIBUTE_SSID = 40, 89 GSCAN_ATTRIBUTE_BSSID, 90 GSCAN_ATTRIBUTE_CHANNEL, 91 GSCAN_ATTRIBUTE_RSSI, 92 GSCAN_ATTRIBUTE_TIMESTAMP, 93 GSCAN_ATTRIBUTE_RTT, 94 GSCAN_ATTRIBUTE_RTTSD, 95 96 /* remaining reserved for additional attributes */ 97 98 GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, 99 GSCAN_ATTRIBUTE_RSSI_LOW, 100 GSCAN_ATTRIBUTE_RSSI_HIGH, 101 GSCAN_ATTRIBUTE_HOTLIST_ELEM, 102 GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 103 104 /* remaining reserved for additional attributes */ 105 GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, 106 GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, 107 GSCAN_ATTRIBUTE_MIN_BREACHING, 108 GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, 109 GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 110 111 GSCAN_ATTRIBUTE_MAX 112 113} GSCAN_ATTRIBUTE; 114 115///////////////////////////////////////////////////////////////////////////// 116 117class GetCapabilitiesCommand : public WifiCommand 118{ 119 wifi_gscan_capabilities *mCapabilities; 120public: 121 GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites) 122 : WifiCommand(iface, 0), mCapabilities(capabitlites) 123 { 124 memset(mCapabilities, 0, sizeof(*mCapabilities)); 125 } 126 127 virtual int create() { 128 ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id); 129 130 int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CAPABILITIES); 131 if (ret < 0) { 132 return ret; 133 } 134 135 return ret; 136 } 137 138protected: 139 virtual int handleResponse(WifiEvent& reply) { 140 141 ALOGD("In GetCapabilities::handleResponse"); 142 143 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 144 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 145 return NL_SKIP; 146 } 147 148 int id = reply.get_vendor_id(); 149 int subcmd = reply.get_vendor_subcmd(); 150 151 ALOGD("Id = %0x, subcmd = %d", id, subcmd); 152 153 void *data = reply.get_vendor_data(); 154 int len = reply.get_vendor_data_len(); 155 156 if (len == sizeof(*mCapabilities)) { 157 ALOGE("Invalid reply length"); 158 memcpy(mCapabilities, data, len); 159 } else { 160 ALOGE("Invalid reply length: %d", len); 161 } 162 163 return NL_OK; 164 } 165}; 166 167 168wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle, 169 wifi_gscan_capabilities *capabilities) 170{ 171 GetCapabilitiesCommand command(handle, capabilities); 172 return (wifi_error) command.requestResponse(); 173} 174 175///////////////////////////////////////////////////////////////////////////// 176 177/* helper functions */ 178 179static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr) 180{ 181 memset(results, 0, sizeof(wifi_scan_result) * num); 182 183 int i = 0; 184 for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) { 185 186 int index = it.get_type(); 187 ALOGI("retrieved scan result %d", index); 188 nlattr *sc_data = (nlattr *) it.get_data(); 189 wifi_scan_result *result = results + i; 190 191 for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) { 192 int type = it2.get_type(); 193 if (type == GSCAN_ATTRIBUTE_SSID) { 194 strncpy(result->ssid, (char *) it2.get_data(), it2.get_len()); 195 result->ssid[it2.get_len()] = 0; 196 } else if (type == GSCAN_ATTRIBUTE_BSSID) { 197 memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr)); 198 } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) { 199 result->ts = it2.get_u64(); 200 } else if (type == GSCAN_ATTRIBUTE_CHANNEL) { 201 result->ts = it2.get_u16(); 202 } else if (type == GSCAN_ATTRIBUTE_RSSI) { 203 result->rssi = it2.get_u8(); 204 } else if (type == GSCAN_ATTRIBUTE_RTT) { 205 result->rtt = it2.get_u64(); 206 } else if (type == GSCAN_ATTRIBUTE_RTTSD) { 207 result->rtt_sd = it2.get_u64(); 208 } 209 } 210 211 } 212 213 if (i >= num) { 214 ALOGE("Got too many results; skipping some"); 215 } 216 217 return i; 218} 219 220int createFeatureRequest(WifiRequest& request, int subcmd, int enable) { 221 222 int result = request.create(GOOGLE_OUI, subcmd); 223 if (result < 0) { 224 return result; 225 } 226 227 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 228 result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable); 229 if (result < 0) { 230 return result; 231 } 232 233 request.attr_end(data); 234 return WIFI_SUCCESS; 235} 236 237///////////////////////////////////////////////////////////////////////////// 238 239class ScanCommand : public WifiCommand 240{ 241 wifi_scan_cmd_params *mParams; 242 wifi_scan_result_handler mHandler; 243public: 244 ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params, 245 wifi_scan_result_handler handler) 246 : WifiCommand(iface, id), mParams(params), mHandler(handler) 247 { } 248 249 int createSetupRequest(WifiRequest& request) { 250 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG); 251 if (result < 0) { 252 return result; 253 } 254 255 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 256 result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period); 257 if (result < 0) { 258 return result; 259 } 260 261 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets); 262 if (result < 0) { 263 return result; 264 } 265 266 for (int i = 0; i < mParams->num_buckets; i++) { 267 nlattr * bucket = request.attr_start(i); // next bucket 268 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket); 269 if (result < 0) { 270 return result; 271 } 272 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period); 273 if (result < 0) { 274 return result; 275 } 276 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, 277 mParams->buckets[i].num_channels); 278 if (result < 0) { 279 return result; 280 } 281 282 nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS); 283 for (int j = 0; j < mParams->buckets[i].num_channels; j++) { 284 result = request.put_u32(j, mParams->buckets[i].channels[j].channel); 285 if (result < 0) { 286 return result; 287 } 288 } 289 290 request.attr_end(channels); 291 request.attr_end(bucket); 292 } 293 294 request.attr_end(data); 295 return WIFI_SUCCESS; 296 } 297 298 int createScanConfigRequest(WifiRequest& request) { 299 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG); 300 if (result < 0) { 301 return result; 302 } 303 304 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 305 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan); 306 if (result < 0) { 307 return result; 308 } 309 310 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold); 311 if (result < 0) { 312 return result; 313 } 314 315 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, 3); 316 if (result < 0) { 317 return result; 318 } 319 320 request.attr_end(data); 321 return WIFI_SUCCESS; 322 } 323 324 int createStartRequest(WifiRequest& request) { 325 return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); 326 } 327 328 int createStopRequest(WifiRequest& request) { 329 return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0); 330 } 331 332 int start() { 333 ALOGD("Setting configuration"); 334 WifiRequest request(familyId(), ifaceId()); 335 int result = createSetupRequest(request); 336 if (result != WIFI_SUCCESS) { 337 ALOGE("failed to create setup request; result = %d", result); 338 return result; 339 } 340 341 result = requestResponse(request); 342 if (result != WIFI_SUCCESS) { 343 ALOGE("failed to configure setup; result = %d", result); 344 return result; 345 } 346 347 request.destroy(); 348 349 result = createScanConfigRequest(request); 350 if (result != WIFI_SUCCESS) { 351 ALOGE("failed to create scan config request; result = %d", result); 352 return result; 353 } 354 355 result = requestResponse(request); 356 if (result != WIFI_SUCCESS) { 357 ALOGE("failed to configure scan; result = %d", result); 358 return result; 359 } 360 361 ALOGD("Starting scan"); 362 363 result = createStartRequest(request); 364 if (result != WIFI_SUCCESS) { 365 ALOGE("failed to create start request; result = %d", result); 366 return result; 367 } 368 369 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); 370 371 result = requestResponse(request); 372 if (result != WIFI_SUCCESS) { 373 ALOGE("failed to start scan; result = %d", result); 374 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); 375 return result; 376 } 377 378 return result; 379 } 380 381 virtual int cancel() { 382 ALOGD("Stopping scan"); 383 384 WifiRequest request(familyId(), ifaceId()); 385 int result = createStopRequest(request); 386 if (result != WIFI_SUCCESS) { 387 ALOGE("failed to create stop request; result = %d", result); 388 } else { 389 result = requestResponse(request); 390 if (result != WIFI_SUCCESS) { 391 ALOGE("failed to stop scan; result = %d", result); 392 } 393 } 394 395 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE); 396 return WIFI_SUCCESS; 397 } 398 399 virtual int handleResponse(WifiEvent& reply) { 400 /* Nothing to do on response! */ 401 return NL_SKIP; 402 } 403 404 virtual int handleEvent(WifiEvent& event) { 405 ALOGI("Got a scan results event"); 406 407 event.log(); 408 409 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 410 int len = event.get_vendor_data_len(); 411 412 if (vendor_data == NULL || len != 4) { 413 ALOGI("No scan results found"); 414 return NL_SKIP; 415 } 416 417 int num = event.get_u32(NL80211_ATTR_VENDOR_DATA); 418 ALOGI("Found %d scan results", num); 419 (*mHandler.on_scan_results_available)(id(), num); 420 return NL_SKIP; 421 } 422}; 423 424wifi_error wifi_start_gscan( 425 wifi_request_id id, 426 wifi_interface_handle iface, 427 wifi_scan_cmd_params params, 428 wifi_scan_result_handler handler) 429{ 430 wifi_handle handle = getWifiHandle(iface); 431 432 ALOGD("Starting GScan, halHandle = %p", handle); 433 434 ScanCommand *cmd = new ScanCommand(iface, id, ¶ms, handler); 435 wifi_register_cmd(handle, id, cmd); 436 return (wifi_error)cmd->start(); 437} 438 439wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface) 440{ 441 ALOGD("Stopping GScan"); 442 wifi_handle handle = getWifiHandle(iface); 443 444 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 445 if (cmd) { 446 cmd->cancel(); 447 delete cmd; 448 return WIFI_SUCCESS; 449 } 450 451 return WIFI_ERROR_INVALID_ARGS; 452} 453 454///////////////////////////////////////////////////////////////////////////// 455 456class GetScanResultsCommand : public WifiCommand { 457 wifi_scan_result *mResults; 458 int *mNum; 459 int mRetrieved; 460 byte mFlush; 461 int mCompleted; 462public: 463 GetScanResultsCommand(wifi_interface_handle iface, byte flush, 464 wifi_scan_result *results, int *num) 465 : WifiCommand(iface, -1), mResults(results), mNum(num), 466 mRetrieved(0), mFlush(flush), mCompleted(0) 467 { } 468 469 int createRequest(WifiRequest& request, int num, byte flush) { 470 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS); 471 if (result < 0) { 472 return result; 473 } 474 475 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 476 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num); 477 if (result < 0) { 478 return result; 479 } 480 481 result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush); 482 if (result < 0) { 483 return result; 484 } 485 486 request.attr_end(data); 487 return WIFI_SUCCESS; 488 } 489 490 int execute() { 491 WifiRequest request(familyId(), ifaceId()); 492 ALOGI("retrieving %d scan results", *mNum); 493 494 for (int i = 0; i < 10 && mRetrieved < *mNum; i++) { 495 int result = createRequest(request, (*mNum - mRetrieved), mFlush); 496 if (result < 0) { 497 ALOGE("failed to create request"); 498 return result; 499 } 500 501 int prev_retrieved = mRetrieved; 502 503 result = requestResponse(request); 504 505 if (result != WIFI_SUCCESS) { 506 ALOGE("failed to retrieve scan results; result = %d", result); 507 return result; 508 } 509 510 if (mRetrieved == prev_retrieved || mCompleted) { 511 /* no more items left to retrieve */ 512 break; 513 } 514 515 request.destroy(); 516 } 517 518 ALOGE("GetScanResults read %d results", mRetrieved); 519 *mNum = mRetrieved; 520 return WIFI_SUCCESS; 521 } 522 523 virtual int handleResponse(WifiEvent& reply) { 524 ALOGD("In GetScanResultsCommand::handleResponse"); 525 526 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 527 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 528 return NL_SKIP; 529 } 530 531 int id = reply.get_vendor_id(); 532 int subcmd = reply.get_vendor_subcmd(); 533 534 ALOGD("Id = %0x, subcmd = %d", id, subcmd); 535 536 /* 537 if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) { 538 ALOGE("Invalid response to GetScanResultsCommand; ignoring it"); 539 return NL_SKIP; 540 } 541 */ 542 543 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 544 int len = reply.get_vendor_data_len(); 545 546 if (vendor_data == NULL || len == 0) { 547 ALOGE("no vendor data in GetScanResults response; ignoring it"); 548 return NL_SKIP; 549 } 550 551 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 552 if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) { 553 mCompleted = it.get_u8(); 554 ALOGI("retrieved mCompleted flag : %d", mCompleted); 555 } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) { 556 for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) { 557 int scan_id = 0, flags = 0, num = 0; 558 if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) { 559 scan_id = it.get_u32(); 560 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) { 561 flags = it.get_u8(); 562 } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) { 563 num = it2.get_u32(); 564 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) { 565 num = it2.get_len() / sizeof(wifi_scan_result); 566 num = min(*mNum - mRetrieved, num); 567 memcpy(mResults + mRetrieved, it2.get_data(), 568 sizeof(wifi_scan_result) * num); 569 ALOGI("Retrieved %d scan results", num); 570 wifi_scan_result *results = (wifi_scan_result *)it2.get_data(); 571 for (int i = 0; i < num; i++) { 572 wifi_scan_result *result = results + i; 573 ALOGI("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x", i, 574 result->ssid, result->bssid[0], result->bssid[1], result->bssid[2], 575 result->bssid[3], result->bssid[4], result->bssid[5]); 576 } 577 mRetrieved += num; 578 } else { 579 ALOGW("Ignoring invalid attribute type = %d, size = %d", 580 it.get_type(), it.get_len()); 581 } 582 } 583 } else { 584 ALOGW("Ignoring invalid attribute type = %d, size = %d", 585 it.get_type(), it.get_len()); 586 } 587 } 588 589 return NL_OK; 590 } 591}; 592 593wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush, 594 wifi_scan_result *results, int *num) { 595 596 ALOGD("Getting cached scan results, iface handle = %p, num = %d", iface, *num); 597 598 GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, num); 599 return (wifi_error)cmd->execute(); 600} 601 602///////////////////////////////////////////////////////////////////////////// 603 604class BssidHotlistCommand : public WifiCommand 605{ 606private: 607 wifi_bssid_hotlist_params mParams; 608 wifi_hotlist_ap_found_handler mHandler; 609 static const int MAX_RESULTS = 64; 610 wifi_scan_result mResults[MAX_RESULTS]; 611public: 612 BssidHotlistCommand(wifi_interface_handle handle, int id, 613 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) 614 : WifiCommand(handle, id), mParams(params), mHandler(handler) 615 { } 616 617 int createSetupRequest(WifiRequest& request) { 618 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); 619 if (result < 0) { 620 return result; 621 } 622 623 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 624 result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); 625 if (result < 0) { 626 return result; 627 } 628 629 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); 630 for (int i = 0; i < mParams.num; i++) { 631 nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM); 632 if (attr2 == NULL) { 633 return WIFI_ERROR_OUT_OF_MEMORY; 634 } 635 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.bssids[i].bssid); 636 if (result < 0) { 637 return result; 638 } 639 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.bssids[i].high); 640 if (result < 0) { 641 return result; 642 } 643 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.bssids[i].low); 644 if (result < 0) { 645 return result; 646 } 647 request.attr_end(attr2); 648 } 649 650 request.attr_end(attr); 651 request.attr_end(data); 652 return result; 653 } 654 655 int createTeardownRequest(WifiRequest& request) { 656 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST); 657 if (result < 0) { 658 return result; 659 } 660 661 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 662 result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1); 663 if (result < 0) { 664 return result; 665 } 666 667 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS); 668 request.attr_end(attr); 669 request.attr_end(data); 670 return result; 671 } 672 673 int start() { 674 ALOGI("Executing hotlist setup request, num = %d", mParams.num); 675 WifiRequest request(familyId(), ifaceId()); 676 int result = createSetupRequest(request); 677 if (result < 0) { 678 return result; 679 } 680 681 result = requestResponse(request); 682 if (result < 0) { 683 ALOGI("Failed to execute hotlist setup request, result = %d", result); 684 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 685 return result; 686 } 687 688 ALOGI("Successfully set %d APs in the hotlist", mParams.num); 689 result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); 690 if (result < 0) { 691 return result; 692 } 693 694 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 695 696 result = requestResponse(request); 697 if (result < 0) { 698 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 699 return result; 700 } 701 702 ALOGI("successfully restarted the scan"); 703 return result; 704 } 705 706 virtual int cancel() { 707 /* unregister event handler */ 708 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS); 709 710 /* create set hotlist message with empty hotlist */ 711 WifiRequest request(familyId(), ifaceId()); 712 int result = createTeardownRequest(request); 713 if (result < 0) { 714 return result; 715 } 716 717 result = requestResponse(request); 718 if (result < 0) { 719 return result; 720 } 721 722 ALOGI("Successfully reset APs in current hotlist"); 723 return result; 724 } 725 726 virtual int handleResponse(WifiEvent& reply) { 727 /* Nothing to do on response! */ 728 return NL_SKIP; 729 } 730 731 virtual int handleEvent(WifiEvent& event) { 732 ALOGI("Got a hotlist ap found event"); 733 734 event.log(); 735 736 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 737 int len = event.get_vendor_data_len(); 738 739 if (vendor_data == NULL || len == 0) { 740 ALOGI("No scan results found"); 741 return NL_SKIP; 742 } 743 744 memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS); 745 746 int num = len / sizeof(wifi_scan_result); 747 num = min(MAX_RESULTS, num); 748 memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result)); 749 ALOGI("Retrieved %d hot APs", num); 750 751 (*mHandler.on_hotlist_ap_found)(id(), num, mResults); 752 return NL_SKIP; 753 } 754}; 755 756wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface, 757 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler) 758{ 759 wifi_handle handle = getWifiHandle(iface); 760 761 BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler); 762 wifi_register_cmd(handle, id, cmd); 763 return (wifi_error)cmd->start(); 764} 765 766wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface) 767{ 768 wifi_handle handle = getWifiHandle(iface); 769 770 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 771 if (cmd) { 772 cmd->cancel(); 773 delete cmd; 774 return WIFI_SUCCESS; 775 } 776 777 return WIFI_ERROR_INVALID_ARGS; 778} 779 780 781///////////////////////////////////////////////////////////////////////////// 782 783class SignificantWifiChangeCommand : public WifiCommand 784{ 785private: 786 wifi_significant_change_params mParams; 787 wifi_significant_change_handler mHandler; 788 static const int MAX_RESULTS = 64; 789 wifi_scan_result mResults[MAX_RESULTS]; 790public: 791 SignificantWifiChangeCommand(wifi_interface_handle handle, int id, 792 wifi_significant_change_params params, wifi_significant_change_handler handler) 793 : WifiCommand(handle, id), mParams(params), mHandler(handler) 794 { } 795 796 int createSetupRequest(WifiRequest& request) { 797 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); 798 if (result < 0) { 799 return result; 800 } 801 802 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 803 result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); 804 if (result < 0) { 805 return result; 806 } 807 result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size); 808 if (result < 0) { 809 return result; 810 } 811 result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size); 812 if (result < 0) { 813 return result; 814 } 815 result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching); 816 if (result < 0) { 817 return result; 818 } 819 820 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS); 821 822 for (int i = 0; i < mParams.num; i++) { 823 824 nlattr *attr2 = request.attr_start(i); 825 if (attr2 == NULL) { 826 return WIFI_ERROR_OUT_OF_MEMORY; 827 } 828 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.bssids[i].bssid); 829 if (result < 0) { 830 return result; 831 } 832 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.bssids[i].high); 833 if (result < 0) { 834 return result; 835 } 836 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.bssids[i].low); 837 if (result < 0) { 838 return result; 839 } 840 request.attr_end(attr2); 841 } 842 843 request.attr_end(attr); 844 request.attr_end(data); 845 846 return result; 847 } 848 849 int createTeardownRequest(WifiRequest& request) { 850 int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG); 851 if (result < 0) { 852 return result; 853 } 854 855 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 856 result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1); 857 if (result < 0) { 858 return result; 859 } 860 861 request.attr_end(data); 862 return result; 863 } 864 865 int start() { 866 ALOGI("Set significant wifi change config"); 867 WifiRequest request(familyId(), ifaceId()); 868 869 int result = createSetupRequest(request); 870 if (result < 0) { 871 return result; 872 } 873 874 WifiEvent e(request.getMessage()); 875 e.log(); 876 877 result = requestResponse(request); 878 if (result < 0) { 879 ALOGI("failed to set significant wifi change config %d", result); 880 return result; 881 } 882 883 ALOGI("successfully set significant wifi change config"); 884 885 result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1); 886 if (result < 0) { 887 return result; 888 } 889 890 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); 891 892 result = requestResponse(request); 893 if (result < 0) { 894 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); 895 return result; 896 } 897 898 ALOGI("successfully restarted the scan"); 899 return result; 900 } 901 902 virtual int cancel() { 903 /* unregister event handler */ 904 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS); 905 906 /* create set significant change monitor message with empty hotlist */ 907 WifiRequest request(familyId(), ifaceId()); 908 909 int result = createTeardownRequest(request); 910 if (result < 0) { 911 return result; 912 } 913 914 result = requestResponse(request); 915 if (result < 0) { 916 return result; 917 } 918 919 ALOGI("successfully reset significant wifi change config"); 920 return result; 921 } 922 923 virtual int handleResponse(WifiEvent& reply) { 924 /* Nothing to do on response! */ 925 return NL_SKIP; 926 } 927 928 virtual int handleEvent(WifiEvent& event) { 929 ALOGI("Got a significant wifi change event"); 930 931 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 932 int len = event.get_vendor_data_len(); 933 934 if (vendor_data == NULL || len == 0) { 935 ALOGI("No scan results found"); 936 return NL_SKIP; 937 } 938 939 typedef struct { 940 uint16_t flags; 941 uint16_t channel; 942 mac_addr bssid; 943 byte rssi_history[8]; 944 } ChangeInfo; 945 946 int num = min(len / sizeof(ChangeInfo), MAX_RESULTS); 947 ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data(); 948 949 for (int i = 0; i < num; i++) { 950 memcpy(mResults[i].bssid, ci[i].bssid, sizeof(mac_addr)); 951 mResults[i].rssi = ci[i].rssi_history[7]; 952 mResults[i].channel = ci[i].channel; 953 } 954 955 ALOGI("Retrieved %d scan results", num); 956 957 if (num != 0) { 958 (*mHandler.on_significant_change)(id(), num, mResults); 959 } else { 960 ALOGW("No significant change reported"); 961 } 962 963 return NL_SKIP; 964 } 965}; 966 967wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface, 968 wifi_significant_change_params params, wifi_significant_change_handler handler) 969{ 970 wifi_handle handle = getWifiHandle(iface); 971 972 SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand( 973 iface, id, params, handler); 974 wifi_register_cmd(handle, id, cmd); 975 return (wifi_error)cmd->start(); 976} 977 978wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface) 979{ 980 wifi_handle handle = getWifiHandle(iface); 981 982 WifiCommand *cmd = wifi_unregister_cmd(handle, id); 983 if (cmd) { 984 cmd->cancel(); 985 delete cmd; 986 return WIFI_SUCCESS; 987 } 988 989 return WIFI_ERROR_INVALID_ARGS; 990} 991