Home | History | Annotate | Download | only in wifi_hal
      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, &params, 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, &params_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, &params_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