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