gscan.cpp revision 922bc148ebc612b6ecf7233b028099aab78feae4
11a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
21a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <stdint.h>
31a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <fcntl.h>
41a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <sys/socket.h>
51a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <netlink/genl/genl.h>
61a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <netlink/genl/family.h>
71a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <netlink/genl/ctrl.h>
81a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <linux/rtnetlink.h>
91a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <netpacket/packet.h>
101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <linux/filter.h>
111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <linux/errqueue.h>
121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <linux/pkt_sched.h>
141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <netlink/object-api.h>
151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <netlink/netlink.h>
161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <netlink/socket.h>
171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <netlink-types.h>
181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include "nl80211_copy.h"
201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include "sync.h"
221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#define LOG_TAG  "WifiHAL"
241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <utils/Log.h>
261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include "wifi_hal.h"
281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include "common.h"
291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include "cpp_bindings.h"
301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndetypedef enum {
321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    BRCM_RESERVED1,
331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    BRCM_RESERVED2,
341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS ,
351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_EVENT_HOTLIST_RESULTS,
361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_EVENT_SCAN_RESULTS_AVAILABLE,
37922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_EVENT_FULL_SCAN_RESULTS
381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde} GSCAN_EVENT;
401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndetypedef enum {
421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SET_CONFIG,                            /* 0x1001 */
461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SET_SCAN_CONFIG,                       /* 0x1002 */
481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_ENABLE_GSCAN,                          /* 0x1003 */
491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_GET_SCAN_RESULTS,                      /* 0x1004 */
501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SCAN_RESULTS,                          /* 0x1005 */
511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SET_HOTLIST,                           /* 0x1006 */
531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG,         /* 0x1007 */
55922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS,              /* 0x1008 */
561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* Add more sub commands here */
581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
59922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_SUBCMD_MAX                                    /* 0x1009 */
601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde} GSCAN_SUB_COMMAND;
621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndetypedef enum {
641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BASE_PERIOD,
67922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_ATTRIBUTE_BUCKETS_BAND,
681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BUCKET_ID,
691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BUCKET_PERIOD,
701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,              /* indicates no more results */
781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_FLUSH_FEATURE,                      /* Flush all the configs */
79922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_ENABLE_FULL_SCAN_RESULTS,
80922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_ATTRIBUTE_REPORT_EVENTS,
811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* remaining reserved for additional attributes */
831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_FLUSH_RESULTS,
851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SCAN_RESULTS,                       /* flat array of wifi_scan_result */
861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SCAN_ID,                            /* indicates scan number */
871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SCAN_FLAGS,                         /* indicates if scan was aborted */
881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_AP_FLAGS,                           /* flags on significant change event */
891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* remaining reserved for additional attributes */
911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SSID = 40,
931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BSSID,
941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_CHANNEL,
951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RSSI,
961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_TIMESTAMP,
971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RTT,
981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RTTSD,
991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* remaining reserved for additional attributes */
1011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,
1031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RSSI_LOW,
1041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RSSI_HIGH,
1051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_HOTLIST_ELEM,
1061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
1071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* remaining reserved for additional attributes */
1091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
1101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
1111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_MIN_BREACHING,
1121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
1131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH,
1141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_MAX
1161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde} GSCAN_ATTRIBUTE;
1181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
119922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
120922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde// helper methods
121922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndewifi_error wifi_enable_full_scan_results(wifi_request_id id, wifi_interface_handle iface,
122922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde         wifi_scan_result_handler handler);
123922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndewifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface);
124922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
125922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
1261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
1271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass GetCapabilitiesCommand : public WifiCommand
1291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
1301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_gscan_capabilities *mCapabilities;
1311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
1321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites)
1331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        : WifiCommand(iface, 0), mCapabilities(capabitlites)
1341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    {
1351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        memset(mCapabilities, 0, sizeof(*mCapabilities));
1361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
1371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int create() {
1391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);
1401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CAPABILITIES);
1421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (ret < 0) {
1431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return ret;
1441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
1451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return ret;
1471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
1481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeprotected:
1501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
1511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("In GetCapabilities::handleResponse");
1531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
1551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
1561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
1571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
1581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int id = reply.get_vendor_id();
1601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int subcmd = reply.get_vendor_subcmd();
1611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Id = %0x, subcmd = %d", id, subcmd);
1631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        void *data = reply.get_vendor_data();
1651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = reply.get_vendor_data_len();
1661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (len == sizeof(*mCapabilities)) {
1681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("Invalid reply length");
1691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            memcpy(mCapabilities, data, len);
1701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        } else {
1711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("Invalid reply length: %d", len);
1721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
1731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_OK;
1751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
1761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
1771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
1801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_gscan_capabilities *capabilities)
1811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
1821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GetCapabilitiesCommand command(handle, capabilities);
1831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error) command.requestResponse();
1841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
1851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
1871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/* helper functions */
1891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndestatic int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)
1911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
1921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    memset(results, 0, sizeof(wifi_scan_result) * num);
1931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int i = 0;
1951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {
1961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int index = it.get_type();
1981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("retrieved scan result %d", index);
1991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *sc_data = (nlattr *) it.get_data();
2001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_scan_result *result = results + i;
2011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) {
2031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            int type = it2.get_type();
2041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (type == GSCAN_ATTRIBUTE_SSID) {
2051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                strncpy(result->ssid, (char *) it2.get_data(), it2.get_len());
2061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->ssid[it2.get_len()] = 0;
2071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_BSSID) {
2081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr));
2091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) {
2101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->ts = it2.get_u64();
2111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_CHANNEL) {
2121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->ts = it2.get_u16();
2131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_RSSI) {
2141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->rssi = it2.get_u8();
2151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_RTT) {
2161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->rtt = it2.get_u64();
2171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_RTTSD) {
2181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->rtt_sd = it2.get_u64();
2191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
2201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
2211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
2231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (i >= num) {
2251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGE("Got too many results; skipping some");
2261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
2271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return i;
2291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
2301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeint createFeatureRequest(WifiRequest& request, int subcmd, int enable) {
2321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int result = request.create(GOOGLE_OUI, subcmd);
2341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (result < 0) {
2351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
2361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
2371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
2391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable);
2401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (result < 0) {
2411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
2421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
2431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    request.attr_end(data);
2451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return WIFI_SUCCESS;
2461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
2471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
249922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndeclass FullScanResultsCommand : public WifiCommand
250922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde{
251922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int *mParams;
252922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    wifi_scan_result_handler mHandler;
253922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndepublic:
254922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    FullScanResultsCommand(wifi_interface_handle iface, int id, int *params,
255922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                wifi_scan_result_handler handler)
256922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        : WifiCommand(iface, id), mParams(params), mHandler(handler)
257922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    { }
258922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
259922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int createRequest(WifiRequest& request, int subcmd, int enable) {
260922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int result = request.create(GOOGLE_OUI, subcmd);
261922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result < 0) {
262922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return result;
263922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
264922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
265922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
266922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        result = request.put_u32(GSCAN_ENABLE_FULL_SCAN_RESULTS, enable);
267922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result < 0) {
268922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return result;
269922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
270922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
271922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        request.attr_end(data);
272922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
273922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
274922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
275922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
276922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int start() {
277922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGD("Enabling Full scan results");
278922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        WifiRequest request(familyId(), ifaceId());
279922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 1);
280922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result != WIFI_SUCCESS) {
281922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGE("failed to create request; result = %d", result);
282922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return result;
283922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
284922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
285922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
286922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
287922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        result = requestResponse(request);
288922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result != WIFI_SUCCESS) {
289922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGE("failed to enable full scan results; result = %d", result);
290922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
291922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return result;
292922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
293922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
294922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return result;
295922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
296922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
297922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    virtual int cancel() {
298922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGD("Disabling Full scan results");
299922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
300922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        WifiRequest request(familyId(), ifaceId());
301922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 0);
302922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result != WIFI_SUCCESS) {
303922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGE("failed to create request; result = %d", result);
304922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        } else {
305922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            result = requestResponse(request);
306922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result != WIFI_SUCCESS) {
307922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGE("failed to disable full scan results;result = %d", result);
308922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
309922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
310922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
311922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
312922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
313922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
314922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
315922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
316922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde         ALOGD("Request complete!");
317922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        /* Nothing to do on response! */
318922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return NL_SKIP;
319922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
320922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
321922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    virtual int handleEvent(WifiEvent& event) {
322922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("Full scan results:  Got an event");
323922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
324922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        event.log();
325922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
326922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
327922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        unsigned int len = event.get_vendor_data_len();
328922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
329922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {
330922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGI("No scan results found");
331922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return NL_SKIP;
332922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
333922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
334922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data();
335922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
336922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        (*mHandler.on_full_scan_result)(id(), result);
337922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%-32s\t", result->ssid);
338922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
339922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%02x:%02x:%02x:%02x:%02x:%02x ", result->bssid[0], result->bssid[1],
340922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5]);
341922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
342922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%d\t", result->rssi);
343922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%d\t", result->channel);
344922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%lld\t", result->ts);
345922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%lld\t", result->rtt);
346922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%lld\n", result->rtt_sd);
347922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
348922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
349922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return NL_SKIP;
350922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
351922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
352922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde};
353922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde/////////////////////////////////////////////////////////////////////////////
3541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass ScanCommand : public WifiCommand
3561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
3571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_scan_cmd_params *mParams;
3581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_scan_result_handler mHandler;
359922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    static unsigned mGlobalFullScanBuckets;
360922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    bool mLocalFullScanBuckets;
3611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
3621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
3631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                wifi_scan_result_handler handler)
364922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        : WifiCommand(iface, id), mParams(params), mHandler(handler),
365922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde          mLocalFullScanBuckets(0)
3661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    { }
3671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createSetupRequest(WifiRequest& request) {
3691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG);
3701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
3711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
3721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
3731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
3751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);
3761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
3771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
3781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
3791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
3811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
3821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
3831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
3841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (int i = 0; i < mParams->num_buckets; i++) {
3861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            nlattr * bucket = request.attr_start(i);    // next bucket
3871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
3881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
3891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
3901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
3911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
3921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
3931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
3941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
395922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND,
396922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    mParams->buckets[i].band);
397922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result < 0) {
398922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                return result;
399922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
400922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
401922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS,
402922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    mParams->buckets[i].report_events);
403922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result < 0) {
404922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                return result;
405922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
406922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
4071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
4081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    mParams->buckets[i].num_channels);
4091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
4101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
4111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
4121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
413922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (mParams->buckets[i].num_channels) {
414922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
415922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
416922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
417922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    if (result < 0) {
418922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                        return result;
419922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    }
4201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                }
421922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                request.attr_end(channels);
4221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
4231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            request.attr_end(bucket);
4251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
4261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
4281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
4291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
4301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createScanConfigRequest(WifiRequest& request) {
4321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG);
4331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
4341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
4351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
4361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
4381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);
4391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
4401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
4411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
4421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold);
4441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
4451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
4461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
4471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
44809f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        int num_scans = 10;
44909f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        for (int i = 0; i < mParams->num_buckets; i++) {
450922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (mParams->buckets[i].report_events == 1) {
45109f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                num_scans = 1;
45209f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                break;
45309f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde            }
45409f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        }
45509f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde
45609f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, num_scans);
4571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
4581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
4591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
4601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
4621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
4631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
4641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createStartRequest(WifiRequest& request) {
4661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
4671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
4681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createStopRequest(WifiRequest& request) {
4701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0);
4711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
4721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
473922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int enableFullScanResultsIfRequired() {
474922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        /* temporary workaround till we have full support for per bucket scans */
475922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
476922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("enabling full scan results if needed");
477922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int nBuckets = 0;
478922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        for (int i = 0; i < mParams->num_buckets; i++) {
479922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (mParams->buckets[i].report_events == 2) {
480922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                nBuckets++;
481922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
482922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
483922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
484922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (mGlobalFullScanBuckets == 0 && nBuckets != 0) {
485922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            int result = wifi_enable_full_scan_results(0x1000, ifaceHandle(), mHandler);
486922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result != WIFI_SUCCESS) {
487922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGI("failed to enable full scan results");
488922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                return result;
489922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            } else {
490922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGI("successfully enabled full scan results");
491922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
492922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        } else {
493922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGI("mGlobalFullScanBuckets = %d, nBuckets = %d", mGlobalFullScanBuckets, nBuckets);
494922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
495922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
496922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        mLocalFullScanBuckets = nBuckets;
497922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        mGlobalFullScanBuckets += nBuckets;
498922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
499922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
500922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
501922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int disableFullScanResultsIfRequired() {
502922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        /* temporary workaround till we have full support for per bucket scans */
503922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
504922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (mLocalFullScanBuckets == 0) {
505922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return WIFI_SUCCESS;
506922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
507922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
508922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        mGlobalFullScanBuckets -= mLocalFullScanBuckets;
509922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (mGlobalFullScanBuckets == 0) {
510922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            int result = wifi_disable_full_scan_results(0x1000, ifaceHandle());
511922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result != WIFI_SUCCESS) {
512922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGI("failed to disable full scan results");
513922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            } else {
514922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGI("successfully disable full scan results");
515922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
516922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
517922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
518922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
519922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
520922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
5211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int start() {
5221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Setting configuration");
5231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
5241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createSetupRequest(request);
5251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
5261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to create setup request; result = %d", result);
5271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
5311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
5321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to configure setup; result = %d", result);
5331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.destroy();
5371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = createScanConfigRequest(request);
5391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
5401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to create scan config request; result = %d", result);
5411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
5451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
5461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to configure scan; result = %d", result);
5471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Starting scan");
5511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = createStartRequest(request);
5531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
5541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to create start request; result = %d", result);
5551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
5591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
5611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
5621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to start scan; result = %d", result);
5631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
5641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
567922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        result = enableFullScanResultsIfRequired();
5681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
5691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
5701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int cancel() {
5721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Stopping scan");
5731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
5751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createStopRequest(request);
5761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
5771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to create stop request; result = %d", result);
5781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        } else {
5791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = requestResponse(request);
5801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result != WIFI_SUCCESS) {
5811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGE("failed to stop scan; result = %d", result);
5821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
5831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
586922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        disableFullScanResultsIfRequired();
587922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
5881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
5891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
5901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
5921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* Nothing to do on response! */
5931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
5941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
5951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleEvent(WifiEvent& event) {
5971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Got a scan results event");
5981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
59909f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        // event.log();
6001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
6021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = event.get_vendor_data_len();
6031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (vendor_data == NULL || len != 4) {
6051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("No scan results found");
6061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
6071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
6081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int num = event.get_u32(NL80211_ATTR_VENDOR_DATA);
6101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Found %d scan results", num);
6111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        (*mHandler.on_scan_results_available)(id(), num);
6121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
6131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
6141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
6151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
616922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndeunsigned ScanCommand::mGlobalFullScanBuckets = 0;
617922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
6181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_start_gscan(
6191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_request_id id,
6201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_interface_handle iface,
6211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_scan_cmd_params params,
6221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_scan_result_handler handler)
6231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
6241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
6251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ALOGD("Starting GScan, halHandle = %p", handle);
6271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ScanCommand *cmd = new ScanCommand(iface, id, &params, handler);
6291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_register_cmd(handle, id, cmd);
6301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error)cmd->start();
6311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
6321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
6341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
6351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ALOGD("Stopping GScan");
6361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
6371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
638922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    if(id == -1) {
639922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_result_handler handler;
640922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_cmd_params dummy_params;
641922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_handle handle = getWifiHandle(iface);
642922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        memset(&handler, 0, sizeof(handler));
643922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
644922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
645922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        cmd->cancel();
646922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        delete cmd;
647922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
648922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
649922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
650922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
6511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
6521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (cmd) {
6531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        cmd->cancel();
6541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        delete cmd;
6551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
6561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
6571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return WIFI_ERROR_INVALID_ARGS;
6591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
6601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
661922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
662922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndewifi_error wifi_enable_full_scan_results(
663922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_request_id id,
664922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_interface_handle iface,
665922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_result_handler handler)
666922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde{
667922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
668922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int params_dummy;
669922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    ALOGD("Enabling full scan results, halHandle = %p", handle);
670922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
671922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, id, &params_dummy, handler);
672922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    wifi_register_cmd(handle, id, cmd);
673922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
674922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    return (wifi_error)cmd->start();
675922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde}
676922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
677922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndewifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface)
678922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde{
679922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    ALOGD("Disabling full scan results");
680922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
681922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
682922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    if(id == -1) {
683922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_result_handler handler;
684922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_handle handle = getWifiHandle(iface);
685922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int params_dummy;
686922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
687922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        memset(&handler, 0, sizeof(handler));
688922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, 0, &params_dummy, handler);
689922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        cmd->cancel();
690922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        delete cmd;
691922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
692922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
693922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
694922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
695922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    if (cmd) {
696922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        cmd->cancel();
697922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        delete cmd;
698922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
699922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
700922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
701922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    return WIFI_ERROR_INVALID_ARGS;
702922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde}
703922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
704922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
7051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
7061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass GetScanResultsCommand : public WifiCommand {
7081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_scan_result *mResults;
7091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int *mNum;
7101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int mRetrieved;
7111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    byte mFlush;
7121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int mCompleted;
7131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
7141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GetScanResultsCommand(wifi_interface_handle iface, byte flush,
7151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            wifi_scan_result *results, int *num)
7161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        : WifiCommand(iface, -1), mResults(results), mNum(num),
7171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                mRetrieved(0), mFlush(flush), mCompleted(0)
7181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    { }
7191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createRequest(WifiRequest& request, int num, byte flush) {
7211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS);
7221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
7231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
7241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
7251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
7271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
7281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
7291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
7301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
7311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush);
7331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
7341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
7351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
7361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
7381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
7391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
7401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int execute() {
7421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
7431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("retrieving %d scan results", *mNum);
7441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (int i = 0; i < 10 && mRetrieved < *mNum; i++) {
7461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            int result = createRequest(request, (*mNum - mRetrieved), mFlush);
7471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
7481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGE("failed to create request");
7491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
7501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
7511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            int prev_retrieved = mRetrieved;
7531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = requestResponse(request);
7551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result != WIFI_SUCCESS) {
7571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGE("failed to retrieve scan results; result = %d", result);
7581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
7591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
7601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (mRetrieved == prev_retrieved || mCompleted) {
7621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                /* no more items left to retrieve */
7631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                break;
7641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
7651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            request.destroy();
7671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
7681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGE("GetScanResults read %d results", mRetrieved);
7701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        *mNum = mRetrieved;
7711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
7721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
7731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
7751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("In GetScanResultsCommand::handleResponse");
7761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
7781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
7791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
7801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
7811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int id = reply.get_vendor_id();
7831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int subcmd = reply.get_vendor_subcmd();
7841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Id = %0x, subcmd = %d", id, subcmd);
7861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /*
7881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) {
7891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("Invalid response to GetScanResultsCommand; ignoring it");
7901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
7911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
7921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        */
7931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
7951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = reply.get_vendor_data_len();
7961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (vendor_data == NULL || len == 0) {
7981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("no vendor data in GetScanResults response; ignoring it");
7991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
8001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
8031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) {
8041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                mCompleted = it.get_u8();
8051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGI("retrieved mCompleted flag : %d", mCompleted);
8061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {
8071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
8081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    int scan_id = 0, flags = 0, num = 0;
8091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) {
8101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        scan_id = it.get_u32();
8111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
8121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        flags = it.get_u8();
8131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
8141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        num = it2.get_u32();
8151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
8161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        num = it2.get_len() / sizeof(wifi_scan_result);
8171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        num = min(*mNum - mRetrieved, num);
8181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        memcpy(mResults + mRetrieved, it2.get_data(),
8191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                                sizeof(wifi_scan_result) * num);
8201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        ALOGI("Retrieved %d scan results", num);
8211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        wifi_scan_result *results = (wifi_scan_result *)it2.get_data();
8221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        for (int i = 0; i < num; i++) {
8231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                            wifi_scan_result *result = results + i;
82409f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                            ALOGI("%02d  %-32s  %02x:%02x:%02x:%02x:%02x:%02x  %04d", i,
8251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                                result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
82609f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                                result->bssid[3], result->bssid[4], result->bssid[5],
82709f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                                result->rssi);
8281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        }
8291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        mRetrieved += num;
8301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    } else {
8311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        ALOGW("Ignoring invalid attribute type = %d, size = %d",
8321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                                it.get_type(), it.get_len());
8331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    }
8341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                }
8351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else {
8361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGW("Ignoring invalid attribute type = %d, size = %d",
8371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        it.get_type(), it.get_len());
8381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
8391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_OK;
8421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
8431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
8441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
8461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_scan_result *results, int *num) {
8471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ALOGD("Getting cached scan results, iface handle = %p, num = %d", iface, *num);
8491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, num);
8511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error)cmd->execute();
8521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
8531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
8551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass BssidHotlistCommand : public WifiCommand
8571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
8581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeprivate:
8591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_bssid_hotlist_params mParams;
8601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_hotlist_ap_found_handler mHandler;
8611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    static const int MAX_RESULTS = 64;
8621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_scan_result mResults[MAX_RESULTS];
8631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
8641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    BssidHotlistCommand(wifi_interface_handle handle, int id,
8651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
8661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        : WifiCommand(handle, id), mParams(params), mHandler(handler)
8671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    { }
8681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createSetupRequest(WifiRequest& request) {
8701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
8711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
8721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
8731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
8761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
8771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
8781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
8791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
8821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (int i = 0; i < mParams.num; i++) {
8831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM);
8841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (attr2 == NULL) {
8851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return WIFI_ERROR_OUT_OF_MEMORY;
8861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
8871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.bssids[i].bssid);
8881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
8891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
8901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
8911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.bssids[i].high);
8921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
8931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
8941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
8951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.bssids[i].low);
8961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
8971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
8981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
8991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            request.attr_end(attr2);
9001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(attr);
9031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
9041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
9051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
9061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createTeardownRequest(WifiRequest& request) {
9081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
9091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
9141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
9151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
9201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(attr);
9211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
9221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
9231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
9241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int start() {
9261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Executing hotlist setup request, num = %d", mParams.num);
9271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
9281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createSetupRequest(request);
9291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
9341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("Failed to execute hotlist setup request, result = %d", result);
9361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
9371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Successfully set %d APs in the hotlist", mParams.num);
9411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
9421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
9471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
9491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
9511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("successfully restarted the scan");
9551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
9561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
9571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int cancel() {
9591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* unregister event handler */
9601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
9611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* create set hotlist message with empty hotlist */
9631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
9641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createTeardownRequest(request);
9651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
9701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Successfully reset APs in current hotlist");
9751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
9761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
9771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
9791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* Nothing to do on response! */
9801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
9811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
9821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleEvent(WifiEvent& event) {
9841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Got a hotlist ap found event");
9851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
98609f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        // event.log();
9871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
9891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = event.get_vendor_data_len();
9901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (vendor_data == NULL || len == 0) {
9921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("No scan results found");
9931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
9941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS);
9971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int num = len / sizeof(wifi_scan_result);
9991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        num = min(MAX_RESULTS, num);
10001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result));
10011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Retrieved %d hot APs", num);
10021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        (*mHandler.on_hotlist_ap_found)(id(), num, mResults);
10041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
10051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
10061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
10071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
10091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
10101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
10111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
10121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler);
10141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_register_cmd(handle, id, cmd);
10151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error)cmd->start();
10161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
10171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
10191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
10201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
10211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
10231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (cmd) {
10241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        cmd->cancel();
10251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        delete cmd;
10261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
10271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
10281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return WIFI_ERROR_INVALID_ARGS;
10301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
10311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
10341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass SignificantWifiChangeCommand : public WifiCommand
10361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
10371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeprivate:
10381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_significant_change_params mParams;
10391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_significant_change_handler mHandler;
10401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    static const int MAX_RESULTS = 64;
10411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_scan_result mResults[MAX_RESULTS];
10421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
10431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    SignificantWifiChangeCommand(wifi_interface_handle handle, int id,
10441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            wifi_significant_change_params params, wifi_significant_change_handler handler)
10451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        : WifiCommand(handle, id), mParams(params), mHandler(handler)
10461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    { }
10471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createSetupRequest(WifiRequest& request) {
10491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
10501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
10551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
10561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);
10601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
10641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);
10681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
10731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (int i = 0; i < mParams.num; i++) {
10751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            nlattr *attr2 = request.attr_start(i);
10771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (attr2 == NULL) {
10781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return WIFI_ERROR_OUT_OF_MEMORY;
10791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
10801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.bssids[i].bssid);
10811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
10821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
10831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
10841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.bssids[i].high);
10851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
10861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
10871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
10881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.bssids[i].low);
10891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
10901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
10911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
10921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            request.attr_end(attr2);
10931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(attr);
10961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
10971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
10991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
11001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createTeardownRequest(WifiRequest& request) {
11021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
11031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
11081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
11091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
11141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
11151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
11161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int start() {
11181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Set significant wifi change config");
11191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
11201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createSetupRequest(request);
11221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
11271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("failed to set significant wifi change config %d", result);
11291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("successfully set significant wifi change config");
11331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
11351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
11401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
11421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
11441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("successfully restarted the scan");
11481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
11491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
11501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int cancel() {
11521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* unregister event handler */
11531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
11541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* create set significant change monitor message with empty hotlist */
11561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
11571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createTeardownRequest(request);
11591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
11641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("successfully reset significant wifi change config");
11691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
11701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
11711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
11731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* Nothing to do on response! */
11741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
11751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
11761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleEvent(WifiEvent& event) {
11781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Got a significant wifi change event");
11791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
11811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = event.get_vendor_data_len();
11821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (vendor_data == NULL || len == 0) {
11841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("No scan results found");
11851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
11861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        typedef struct {
11891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            uint16_t flags;
11901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            uint16_t channel;
11911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            mac_addr bssid;
11921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            byte rssi_history[8];
11931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        } ChangeInfo;
11941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int num = min(len / sizeof(ChangeInfo), MAX_RESULTS);
11961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data();
11971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (int i = 0; i < num; i++) {
11991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            memcpy(mResults[i].bssid, ci[i].bssid, sizeof(mac_addr));
12001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            mResults[i].rssi = ci[i].rssi_history[7];
12011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            mResults[i].channel = ci[i].channel;
12021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Retrieved %d scan results", num);
12051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (num != 0) {
12071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            (*mHandler.on_significant_change)(id(), num, mResults);
12081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        } else {
12091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGW("No significant change reported");
12101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
12131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
12141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
12151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
12171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_significant_change_params params, wifi_significant_change_handler handler)
12181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
12191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
12201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand(
12221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            iface, id, params, handler);
12231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_register_cmd(handle, id, cmd);
12241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error)cmd->start();
12251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
12261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
12281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
12291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
12301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
12321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (cmd) {
12331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        cmd->cancel();
12341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        delete cmd;
12351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
12361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
12371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return WIFI_ERROR_INVALID_ARGS;
12391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
1240