gscan.cpp revision 27a89dc4e3256ded710cf7bea77aed3b8cd168e2
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>
17642bfbe829f5438db3d99ce4678bcb770359a632Vinit Deshpande#include <netlink/handlers.h>
181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include "sync.h"
201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#define LOG_TAG  "WifiHAL"
221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include <utils/Log.h>
241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include "wifi_hal.h"
261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include "common.h"
271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde#include "cpp_bindings.h"
281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndetypedef enum {
301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SET_CONFIG,                            /* 0x1001 */
341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SET_SCAN_CONFIG,                       /* 0x1002 */
361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_ENABLE_GSCAN,                          /* 0x1003 */
371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_GET_SCAN_RESULTS,                      /* 0x1004 */
381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SCAN_RESULTS,                          /* 0x1005 */
391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SET_HOTLIST,                           /* 0x1006 */
411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG,         /* 0x1007 */
43922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS,              /* 0x1008 */
4427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    GSCAN_SUBCMD_GET_CHANNEL_LIST,                       /* 0x1009 */
451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* Add more sub commands here */
471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    GSCAN_SUBCMD_MAX                                    /* 0x100A */
491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde} GSCAN_SUB_COMMAND;
511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndetypedef enum {
531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BASE_PERIOD,
56922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_ATTRIBUTE_BUCKETS_BAND,
571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BUCKET_ID,
581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BUCKET_PERIOD,
591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
6427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,              /* indicates no more results */
681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_FLUSH_FEATURE,                      /* Flush all the configs */
69922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_ENABLE_FULL_SCAN_RESULTS,
70922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    GSCAN_ATTRIBUTE_REPORT_EVENTS,
711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* remaining reserved for additional attributes */
731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_FLUSH_RESULTS,
751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SCAN_RESULTS,                       /* flat array of wifi_scan_result */
761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SCAN_ID,                            /* indicates scan number */
771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SCAN_FLAGS,                         /* indicates if scan was aborted */
781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_AP_FLAGS,                           /* flags on significant change event */
7927a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    GSCAN_ATTRIBUTE_NUM_CHANNELS,
8027a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    GSCAN_ATTRIBUTE_CHANNEL_LIST,
811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* remaining reserved for additional attributes */
831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SSID = 40,
851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_BSSID,
861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_CHANNEL,
871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RSSI,
881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_TIMESTAMP,
891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RTT,
901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RTTSD,
911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* remaining reserved for additional attributes */
931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,
951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RSSI_LOW,
961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RSSI_HIGH,
971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_HOTLIST_ELEM,
981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    /* remaining reserved for additional attributes */
1011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
1021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
1031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_MIN_BREACHING,
1041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
1051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH,
1061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GSCAN_ATTRIBUTE_MAX
1081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde} GSCAN_ATTRIBUTE;
1101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
111922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
112922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde// helper methods
113922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndewifi_error wifi_enable_full_scan_results(wifi_request_id id, wifi_interface_handle iface,
114922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde         wifi_scan_result_handler handler);
115922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndewifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface);
116922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
117922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
1181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
1191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass GetCapabilitiesCommand : public WifiCommand
1211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
1221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_gscan_capabilities *mCapabilities;
1231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
1241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites)
1251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        : WifiCommand(iface, 0), mCapabilities(capabitlites)
1261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    {
1271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        memset(mCapabilities, 0, sizeof(*mCapabilities));
1281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
1291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int create() {
1311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);
1321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CAPABILITIES);
1341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (ret < 0) {
1351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return ret;
1361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
1371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return ret;
1391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
1401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeprotected:
1421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
1431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("In GetCapabilities::handleResponse");
1451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
1471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
1481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
1491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
1501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int id = reply.get_vendor_id();
1521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int subcmd = reply.get_vendor_subcmd();
1531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        void *data = reply.get_vendor_data();
1551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = reply.get_vendor_data_len();
1561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
157e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
158e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande                    sizeof(*mCapabilities));
159e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande
160e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
1611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_OK;
1631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
1641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
1651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
1681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_gscan_capabilities *capabilities)
1691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
1701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GetCapabilitiesCommand command(handle, capabilities);
1711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error) command.requestResponse();
1721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
1731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
17427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwinclass GetChannelListCommand : public WifiCommand
17527a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin{
17627a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    wifi_channel *channels;
17727a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    int max_channels;
17827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    int *num_channels;
17927a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    int band;
18027a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwinpublic:
18127a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num,
18227a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        int num_max_ch, int band)
18327a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        : WifiCommand(iface, 0), channels(channel_buf), max_channels(num_max_ch), num_channels(ch_num),
18427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        band(band)
18527a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    {
18627a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        memset(channels, 0, sizeof(wifi_channel) * max_channels);
18727a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    }
18827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    virtual int create() {
18927a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        ALOGD("Creating message to get channel list; iface = %d", mIfaceInfo->id);
19027a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
19127a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CHANNEL_LIST);
19227a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        if (ret < 0) {
19327a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            return ret;
19427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        }
19527a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
19627a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
19727a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band);
19827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        if (ret < 0) {
19927a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            return ret;
20027a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        }
20127a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
20227a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        mMsg.attr_end(data);
20327a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
20427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        return ret;
20527a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    }
20627a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
20727a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwinprotected:
20827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    virtual int handleResponse(WifiEvent& reply) {
20927a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
21027a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        ALOGD("In GetChannelList::handleResponse");
21127a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
21227a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
21327a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
21427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            return NL_SKIP;
21527a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        }
21627a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
21727a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        int id = reply.get_vendor_id();
21827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        int subcmd = reply.get_vendor_subcmd();
21927a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        int num_channels_to_copy = 0;
22027a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
22127a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
22227a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        int len = reply.get_vendor_data_len();
22327a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
22427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
22527a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        if (vendor_data == NULL || len == 0) {
22627a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            ALOGE("no vendor data in GetChannelList response; ignoring it");
22727a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            return NL_SKIP;
22827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        }
22927a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
23027a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
23127a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            if (it.get_type() == GSCAN_ATTRIBUTE_NUM_CHANNELS) {
23227a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin                num_channels_to_copy = it.get_u32();
23327a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin                ALOGI("Got channel list with %d channels", num_channels_to_copy);
23427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin                if(num_channels_to_copy > max_channels)
23527a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin                    num_channels_to_copy = max_channels;
23627a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin                *num_channels = num_channels_to_copy;
23727a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) {
23827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin                memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy);
23927a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            } else {
24027a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin                ALOGW("Ignoring invalid attribute type = %d, size = %d",
24127a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin                        it.get_type(), it.get_len());
24227a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            }
24327a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        }
24427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
24527a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        return NL_OK;
24627a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    }
24727a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin};
24827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
24927a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwinwifi_error wifi_get_valid_channels(wifi_interface_handle handle,
25027a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        int band, int max_channels, wifi_channel *channels, int *num_channels)
25127a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin{
25227a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    GetChannelListCommand command(handle, channels, num_channels,
25327a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin                                        max_channels, band);
25427a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin    return (wifi_error) command.requestResponse();
25527a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin}
2561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
2571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/* helper functions */
2591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndestatic int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)
2611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
2621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    memset(results, 0, sizeof(wifi_scan_result) * num);
2631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int i = 0;
2651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {
2661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int index = it.get_type();
2681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("retrieved scan result %d", index);
2691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *sc_data = (nlattr *) it.get_data();
2701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_scan_result *result = results + i;
2711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) {
2731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            int type = it2.get_type();
2741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (type == GSCAN_ATTRIBUTE_SSID) {
2751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                strncpy(result->ssid, (char *) it2.get_data(), it2.get_len());
2761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->ssid[it2.get_len()] = 0;
2771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_BSSID) {
2781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr));
2791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) {
2801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->ts = it2.get_u64();
2811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_CHANNEL) {
2821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->ts = it2.get_u16();
2831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_RSSI) {
2841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->rssi = it2.get_u8();
2851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_RTT) {
2861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->rtt = it2.get_u64();
2871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (type == GSCAN_ATTRIBUTE_RTTSD) {
2881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                result->rtt_sd = it2.get_u64();
2891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
2901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
2911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
2931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (i >= num) {
2951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGE("Got too many results; skipping some");
2961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
2971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
2981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return i;
2991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
3001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeint createFeatureRequest(WifiRequest& request, int subcmd, int enable) {
3021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int result = request.create(GOOGLE_OUI, subcmd);
3041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (result < 0) {
3051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
3061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
3071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
3091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable);
3101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (result < 0) {
3111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
3121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
3131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    request.attr_end(data);
3151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return WIFI_SUCCESS;
3161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
3171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
3181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
319922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndeclass FullScanResultsCommand : public WifiCommand
320922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde{
321922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int *mParams;
322922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    wifi_scan_result_handler mHandler;
323922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndepublic:
324922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    FullScanResultsCommand(wifi_interface_handle iface, int id, int *params,
325922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                wifi_scan_result_handler handler)
326922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        : WifiCommand(iface, id), mParams(params), mHandler(handler)
327922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    { }
328922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
329922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int createRequest(WifiRequest& request, int subcmd, int enable) {
330922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int result = request.create(GOOGLE_OUI, subcmd);
331922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result < 0) {
332922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return result;
333922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
334922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
335922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
336922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        result = request.put_u32(GSCAN_ENABLE_FULL_SCAN_RESULTS, enable);
337922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result < 0) {
338922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return result;
339922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
340922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
341922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        request.attr_end(data);
342922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
343922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
344922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
345922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
346922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int start() {
347922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGD("Enabling Full scan results");
348922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        WifiRequest request(familyId(), ifaceId());
349922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 1);
350922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result != WIFI_SUCCESS) {
351922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGE("failed to create request; result = %d", result);
352922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return result;
353922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
354922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
355922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
356922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
357922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        result = requestResponse(request);
358922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result != WIFI_SUCCESS) {
359922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGE("failed to enable full scan results; result = %d", result);
360922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
361922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return result;
362922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
363922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
364922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return result;
365922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
366922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
367922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    virtual int cancel() {
368922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGD("Disabling Full scan results");
369922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
370922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        WifiRequest request(familyId(), ifaceId());
371922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 0);
372922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (result != WIFI_SUCCESS) {
373922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGE("failed to create request; result = %d", result);
374922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        } else {
375922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            result = requestResponse(request);
376922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result != WIFI_SUCCESS) {
377922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGE("failed to disable full scan results;result = %d", result);
378922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
379922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
380922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
381922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
382922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
383922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
384922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
385922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
386922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde         ALOGD("Request complete!");
387922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        /* Nothing to do on response! */
388922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return NL_SKIP;
389922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
390922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
391922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    virtual int handleEvent(WifiEvent& event) {
392922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("Full scan results:  Got an event");
393922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
394922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        event.log();
395922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
396922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
397922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        unsigned int len = event.get_vendor_data_len();
398922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
399922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {
400922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGI("No scan results found");
401922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return NL_SKIP;
402922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
403922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
404922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data();
405922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
40627a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin        if(*mHandler.on_full_scan_result)
40727a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin            (*mHandler.on_full_scan_result)(id(), result);
40827a89dc4e3256ded710cf7bea77aed3b8cd168e2Ashwin
409922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%-32s\t", result->ssid);
410922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
411922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%02x:%02x:%02x:%02x:%02x:%02x ", result->bssid[0], result->bssid[1],
412922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5]);
413922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
414922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%d\t", result->rssi);
415922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%d\t", result->channel);
416922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%lld\t", result->ts);
417922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%lld\t", result->rtt);
418922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("%lld\n", result->rtt_sd);
419922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
420922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
421922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return NL_SKIP;
422922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
423922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
424922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde};
425922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde/////////////////////////////////////////////////////////////////////////////
4261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass ScanCommand : public WifiCommand
4281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
4291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_scan_cmd_params *mParams;
4301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_scan_result_handler mHandler;
431922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    static unsigned mGlobalFullScanBuckets;
432922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    bool mLocalFullScanBuckets;
4331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
4341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
4351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                wifi_scan_result_handler handler)
436922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        : WifiCommand(iface, id), mParams(params), mHandler(handler),
437922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde          mLocalFullScanBuckets(0)
4381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    { }
4391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createSetupRequest(WifiRequest& request) {
4411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG);
4421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
4431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
4441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
4451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
4471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);
4481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
4491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
4501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
4511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
4531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
4541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
4551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
4561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (int i = 0; i < mParams->num_buckets; i++) {
4581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            nlattr * bucket = request.attr_start(i);    // next bucket
4591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
4601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
4611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
4621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
4631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
4641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
4651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
4661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
467922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND,
468922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    mParams->buckets[i].band);
469922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result < 0) {
470922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                return result;
471922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
472922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
473922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS,
474922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    mParams->buckets[i].report_events);
475922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result < 0) {
476922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                return result;
477922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
478922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
4791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
4801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    mParams->buckets[i].num_channels);
4811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
4821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
4831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
4841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
485922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (mParams->buckets[i].num_channels) {
486922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
487922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
488922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
489922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    if (result < 0) {
490922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                        return result;
491922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                    }
4921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                }
493922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                request.attr_end(channels);
4941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
4951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            request.attr_end(bucket);
4971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
4981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
4991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
5001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
5011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
5021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createScanConfigRequest(WifiRequest& request) {
5041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG);
5051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
5061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
5101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);
5111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
5121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold);
5161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
5171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
520e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        int num_scans = 20;
52109f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        for (int i = 0; i < mParams->num_buckets; i++) {
522922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (mParams->buckets[i].report_events == 1) {
523e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande                ALOGD("Setting num_scans to 1");
52409f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                num_scans = 1;
52509f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                break;
52609f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde            }
52709f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        }
52809f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde
52909f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, num_scans);
5301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
5311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
5321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
5331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
5351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
5361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
5371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createStartRequest(WifiRequest& request) {
5391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
5401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
5411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
5421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createStopRequest(WifiRequest& request) {
5431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0);
5441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
5451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
546922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int enableFullScanResultsIfRequired() {
547922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        /* temporary workaround till we have full support for per bucket scans */
548922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
549922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ALOGI("enabling full scan results if needed");
550922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int nBuckets = 0;
551922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        for (int i = 0; i < mParams->num_buckets; i++) {
552922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (mParams->buckets[i].report_events == 2) {
553922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                nBuckets++;
554922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
555922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
556922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
557922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (mGlobalFullScanBuckets == 0 && nBuckets != 0) {
558922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            int result = wifi_enable_full_scan_results(0x1000, ifaceHandle(), mHandler);
559922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result != WIFI_SUCCESS) {
560922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGI("failed to enable full scan results");
561922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                return result;
562922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            } else {
563922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGI("successfully enabled full scan results");
564922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
565922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        } else {
566922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            ALOGI("mGlobalFullScanBuckets = %d, nBuckets = %d", mGlobalFullScanBuckets, nBuckets);
567922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
568922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
569922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        mLocalFullScanBuckets = nBuckets;
570922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        mGlobalFullScanBuckets += nBuckets;
571922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
572922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
573922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
574922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int disableFullScanResultsIfRequired() {
575922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        /* temporary workaround till we have full support for per bucket scans */
576922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
577922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (mLocalFullScanBuckets == 0) {
578922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            return WIFI_SUCCESS;
579922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
580922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
581922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        mGlobalFullScanBuckets -= mLocalFullScanBuckets;
582922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        if (mGlobalFullScanBuckets == 0) {
583922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            int result = wifi_disable_full_scan_results(0x1000, ifaceHandle());
584922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            if (result != WIFI_SUCCESS) {
585922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGI("failed to disable full scan results");
586922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            } else {
587922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde                ALOGI("successfully disable full scan results");
588922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde            }
589922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        }
590922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
591922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
592922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
593922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
5941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int start() {
5951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Setting configuration");
5961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
5971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createSetupRequest(request);
5981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
5991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to create setup request; result = %d", result);
6001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
6011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
6021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
6041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
6051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to configure setup; result = %d", result);
6061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
6071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
6081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.destroy();
6101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = createScanConfigRequest(request);
6121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
6131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to create scan config request; result = %d", result);
6141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
6151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
6161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
6181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
6191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to configure scan; result = %d", result);
6201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
6211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
6221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Starting scan");
6241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = createStartRequest(request);
6261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
6271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to create start request; result = %d", result);
6281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
6291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
6301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
6321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
6341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
6351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to start scan; result = %d", result);
6361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
6371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
6381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
6391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
640922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        result = enableFullScanResultsIfRequired();
6411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
6421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
6431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int cancel() {
6451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Stopping scan");
6461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
6481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createStopRequest(request);
6491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result != WIFI_SUCCESS) {
6501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("failed to create stop request; result = %d", result);
6511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        } else {
6521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = requestResponse(request);
6531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result != WIFI_SUCCESS) {
6541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGE("failed to stop scan; result = %d", result);
6551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
6561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
6571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
659922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        disableFullScanResultsIfRequired();
660922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
6611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
6621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
6631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
6651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* Nothing to do on response! */
6661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
6671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
6681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleEvent(WifiEvent& event) {
6701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Got a scan results event");
6711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
67209f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        // event.log();
6731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
6751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = event.get_vendor_data_len();
6761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (vendor_data == NULL || len != 4) {
6781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("No scan results found");
6791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
6801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
6811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int num = event.get_u32(NL80211_ATTR_VENDOR_DATA);
6831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Found %d scan results", num);
6841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        (*mHandler.on_scan_results_available)(id(), num);
6851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
6861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
6871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
6881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
689922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndeunsigned ScanCommand::mGlobalFullScanBuckets = 0;
690922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
6911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_start_gscan(
6921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_request_id id,
6931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_interface_handle iface,
6941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_scan_cmd_params params,
6951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_scan_result_handler handler)
6961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
6971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
6981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
6991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ALOGD("Starting GScan, halHandle = %p", handle);
7001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ScanCommand *cmd = new ScanCommand(iface, id, &params, handler);
7021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_register_cmd(handle, id, cmd);
7031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error)cmd->start();
7041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
7051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
7071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
7081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ALOGD("Stopping GScan");
7091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
7101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
711922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    if(id == -1) {
712922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_result_handler handler;
713922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_cmd_params dummy_params;
714922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_handle handle = getWifiHandle(iface);
715922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        memset(&handler, 0, sizeof(handler));
716922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
717922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
718922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        cmd->cancel();
719922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        delete cmd;
720922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
721922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
722922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
723922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
7241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
7251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (cmd) {
7261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        cmd->cancel();
7271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        delete cmd;
7281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
7291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
7301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return WIFI_ERROR_INVALID_ARGS;
7321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
7331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
734922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
735922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndewifi_error wifi_enable_full_scan_results(
736922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_request_id id,
737922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_interface_handle iface,
738922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_result_handler handler)
739922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde{
740922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
741922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    int params_dummy;
742922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    ALOGD("Enabling full scan results, halHandle = %p", handle);
743922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
744922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, id, &params_dummy, handler);
745922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    wifi_register_cmd(handle, id, cmd);
746922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
747922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    return (wifi_error)cmd->start();
748922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde}
749922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
750922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapndewifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface)
751922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde{
752922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    ALOGD("Disabling full scan results");
753922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
754922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
755922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    if(id == -1) {
756922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_scan_result_handler handler;
757922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        wifi_handle handle = getWifiHandle(iface);
758922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        int params_dummy;
759922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
760922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        memset(&handler, 0, sizeof(handler));
761922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, 0, &params_dummy, handler);
762922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        cmd->cancel();
763922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        delete cmd;
764922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
765922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
766922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
767922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
768922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    if (cmd) {
769922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        cmd->cancel();
770922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        delete cmd;
771922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde        return WIFI_SUCCESS;
772922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    }
773922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
774922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde    return WIFI_ERROR_INVALID_ARGS;
775922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde}
776922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
777922bc148ebc612b6ecf7233b028099aab78feae4Vinit Deshapnde
7781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
7791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass GetScanResultsCommand : public WifiCommand {
7811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_scan_result *mResults;
782e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande    int mMax;
7831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int *mNum;
7841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int mRetrieved;
7851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    byte mFlush;
7861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int mCompleted;
7871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
7881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    GetScanResultsCommand(wifi_interface_handle iface, byte flush,
789e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            wifi_scan_result *results, int max, int *num)
790e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        : WifiCommand(iface, -1), mResults(results), mMax(max), mNum(num),
7911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                mRetrieved(0), mFlush(flush), mCompleted(0)
7921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    { }
7931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
7941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createRequest(WifiRequest& request, int num, byte flush) {
7951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS);
7961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
7971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
7981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
7991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
8011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
8021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
8031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
8041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush);
8071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
8081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
8091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
8121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
8131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
8141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int execute() {
8161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
817e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        ALOGI("retrieving %d scan results", mMax);
8181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
819e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        for (int i = 0; i < 10 && mRetrieved < mMax; i++) {
820e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            int result = createRequest(request, (mMax - mRetrieved), mFlush);
8211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
8221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGE("failed to create request");
8231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
8241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
8251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            int prev_retrieved = mRetrieved;
8271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            result = requestResponse(request);
8291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result != WIFI_SUCCESS) {
8311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGE("failed to retrieve scan results; result = %d", result);
8321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
8331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
8341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (mRetrieved == prev_retrieved || mCompleted) {
8361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                /* no more items left to retrieve */
8371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                break;
8381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
8391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            request.destroy();
8411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGE("GetScanResults read %d results", mRetrieved);
8441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        *mNum = mRetrieved;
8451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
8461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
8471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
8491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("In GetScanResultsCommand::handleResponse");
8501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
8521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
8531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
8541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int id = reply.get_vendor_id();
8571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int subcmd = reply.get_vendor_subcmd();
8581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGD("Id = %0x, subcmd = %d", id, subcmd);
8601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /*
8621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) {
8631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("Invalid response to GetScanResultsCommand; ignoring it");
8641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
8651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        */
8671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
8691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = reply.get_vendor_data_len();
8701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (vendor_data == NULL || len == 0) {
8721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGE("no vendor data in GetScanResults response; ignoring it");
8731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
8741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
8751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
8761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
8771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) {
8781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                mCompleted = it.get_u8();
8791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGI("retrieved mCompleted flag : %d", mCompleted);
8801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {
8811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
8821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    int scan_id = 0, flags = 0, num = 0;
8831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) {
8841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        scan_id = it.get_u32();
8851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
8861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        flags = it.get_u8();
8871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
8881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        num = it2.get_u32();
8891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
8901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        num = it2.get_len() / sizeof(wifi_scan_result);
8911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        num = min(*mNum - mRetrieved, num);
8921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        memcpy(mResults + mRetrieved, it2.get_data(),
8931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                                sizeof(wifi_scan_result) * num);
8941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        ALOGI("Retrieved %d scan results", num);
8951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        wifi_scan_result *results = (wifi_scan_result *)it2.get_data();
8961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        for (int i = 0; i < num; i++) {
8971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                            wifi_scan_result *result = results + i;
89809f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                            ALOGI("%02d  %-32s  %02x:%02x:%02x:%02x:%02x:%02x  %04d", i,
8991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                                result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
90009f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                                result->bssid[3], result->bssid[4], result->bssid[5],
90109f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde                                result->rssi);
9021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        }
9031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        mRetrieved += num;
9041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    } else {
9051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        ALOGW("Ignoring invalid attribute type = %d, size = %d",
9061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                                it.get_type(), it.get_len());
9071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                    }
9081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                }
9091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            } else {
9101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                ALOGW("Ignoring invalid attribute type = %d, size = %d",
9111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                        it.get_type(), it.get_len());
9121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
9131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_OK;
9161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
9171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
9181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
920e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        int max, wifi_scan_result *results, int *num) {
9211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    ALOGD("Getting cached scan results, iface handle = %p, num = %d", iface, *num);
9231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
924e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande    GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num);
9251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error)cmd->execute();
9261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
9271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
9291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass BssidHotlistCommand : public WifiCommand
9311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
9321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeprivate:
9331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_bssid_hotlist_params mParams;
9341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_hotlist_ap_found_handler mHandler;
9351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    static const int MAX_RESULTS = 64;
9361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_scan_result mResults[MAX_RESULTS];
9371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
9381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    BssidHotlistCommand(wifi_interface_handle handle, int id,
9391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
9401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        : WifiCommand(handle, id), mParams(params), mHandler(handler)
9411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    { }
9421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createSetupRequest(WifiRequest& request) {
9441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
9451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
9501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
9511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
956e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        for (int i = 0; i < mParams.num_ap; i++) {
9571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM);
9581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (attr2 == NULL) {
9591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return WIFI_ERROR_OUT_OF_MEMORY;
9601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
961e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
9621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
9631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
9641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
965e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
9661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
9671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
9681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
969e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
9701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
9711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
9721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
9731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            request.attr_end(attr2);
9741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(attr);
9771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
9781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
9791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
9801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createTeardownRequest(WifiRequest& request) {
9821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
9831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
9881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
9891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
9901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
9911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
9921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
9941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(attr);
9951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
9961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
9971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
9981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
9991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int start() {
1000e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        ALOGI("Executing hotlist setup request, num = %d", mParams.num_ap);
10011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
10021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createSetupRequest(request);
10031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
10081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("Failed to execute hotlist setup request, result = %d", result);
10101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
10111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1014e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        ALOGI("Successfully set %d APs in the hotlist", mParams.num_ap);
10151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
10161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
10211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
10231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
10251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("successfully restarted the scan");
10291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
10301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
10311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int cancel() {
10331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* unregister event handler */
10341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
10351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* create set hotlist message with empty hotlist */
10371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
10381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createTeardownRequest(request);
10391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
10441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
10451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
10461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Successfully reset APs in current hotlist");
10491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
10501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
10511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
10531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* Nothing to do on response! */
10541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
10551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
10561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleEvent(WifiEvent& event) {
10581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Got a hotlist ap found event");
10591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
106009f45268753c6021b621e0be82a6808cebbaa37dVinit Deshapnde        // event.log();
10611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
10631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = event.get_vendor_data_len();
10641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (vendor_data == NULL || len == 0) {
10661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("No scan results found");
10671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
10681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
10691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS);
10711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int num = len / sizeof(wifi_scan_result);
10731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        num = min(MAX_RESULTS, num);
10741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result));
10751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Retrieved %d hot APs", num);
10761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        (*mHandler.on_hotlist_ap_found)(id(), num, mResults);
10781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
10791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
10801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
10811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
10831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
10841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
10851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
10861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler);
10881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_register_cmd(handle, id, cmd);
10891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error)cmd->start();
10901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
10911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
10931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
10941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
10951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
10961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
10971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (cmd) {
10981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        cmd->cancel();
10991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        delete cmd;
11001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
11011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
11021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return WIFI_ERROR_INVALID_ARGS;
11041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
11051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde/////////////////////////////////////////////////////////////////////////////
11081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeclass SignificantWifiChangeCommand : public WifiCommand
11101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
1111e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande    typedef struct {
1112e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        mac_addr bssid;                     // BSSID
1113e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        wifi_channel channel;               // channel frequency in MHz
1114e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        int num_rssi;                       // number of rssi samples
1115e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        wifi_rssi rssi[8];                   // RSSI history in db
1116e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande    } wifi_significant_change_result_internal;
1117e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande
11181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndeprivate:
11191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_significant_change_params mParams;
11201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_significant_change_handler mHandler;
11211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    static const int MAX_RESULTS = 64;
1122e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande    wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS];
1123e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande    wifi_significant_change_result *mResults[MAX_RESULTS];
11241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndepublic:
11251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    SignificantWifiChangeCommand(wifi_interface_handle handle, int id,
11261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            wifi_significant_change_params params, wifi_significant_change_handler handler)
11271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        : WifiCommand(handle, id), mParams(params), mHandler(handler)
11281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    { }
11291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createSetupRequest(WifiRequest& request) {
11311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
11321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
11371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
11381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);
11421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
11461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);
11501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
11551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
1156e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande        for (int i = 0; i < mParams.num_ap; i++) {
11571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            nlattr *attr2 = request.attr_start(i);
11591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (attr2 == NULL) {
11601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return WIFI_ERROR_OUT_OF_MEMORY;
11611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
1162e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
11631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
11641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
11651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
1166e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
11671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
11681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
11691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
1170e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
11711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            if (result < 0) {
11721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde                return result;
11731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            }
11741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            request.attr_end(attr2);
11751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(attr);
11781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
11791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
11811a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
11821a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11831a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int createTeardownRequest(WifiRequest& request) {
11841a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
11851a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
11901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
11911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
11921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
11931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
11941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        request.attr_end(data);
11961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
11971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
11981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
11991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    int start() {
12001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Set significant wifi change config");
12011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
12021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createSetupRequest(request);
12041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
12051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
12061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
12091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
12101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("failed to set significant wifi change config %d", result);
12111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
12121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("successfully set significant wifi change config");
12151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
12171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
12181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
12191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
12221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
12241a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
12251a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
12261a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
12271a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12281a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12291a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("successfully restarted the scan");
12301a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
12311a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
12321a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12331a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int cancel() {
12341a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* unregister event handler */
12351a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
12361a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12371a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* create set significant change monitor message with empty hotlist */
12381a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        WifiRequest request(familyId(), ifaceId());
12391a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12401a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int result = createTeardownRequest(request);
12411a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
12421a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
12431a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12441a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12451a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        result = requestResponse(request);
12461a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (result < 0) {
12471a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return result;
12481a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12491a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12501a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("successfully reset significant wifi change config");
12511a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return result;
12521a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
12531a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12541a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleResponse(WifiEvent& reply) {
12551a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        /* Nothing to do on response! */
12561a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
12571a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
12581a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12591a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    virtual int handleEvent(WifiEvent& event) {
12601a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Got a significant wifi change event");
12611a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12621a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
12631a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int len = event.get_vendor_data_len();
12641a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12651a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (vendor_data == NULL || len == 0) {
12661a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGI("No scan results found");
12671a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            return NL_SKIP;
12681a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12691a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12701a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        typedef struct {
12711a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            uint16_t flags;
12721a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            uint16_t channel;
12731a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            mac_addr bssid;
12741a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            byte rssi_history[8];
12751a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        } ChangeInfo;
12761a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12771a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        int num = min(len / sizeof(ChangeInfo), MAX_RESULTS);
12781a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data();
12791a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12801a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        for (int i = 0; i < num; i++) {
1281e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr));
1282e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            mResultsBuffer[i].channel = ci[i].channel;
1283e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            mResultsBuffer[i].num_rssi = 8;
1284e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            memcpy(mResultsBuffer[i].rssi, ci[i].rssi_history, 8);
1285e165f3a9d7d77eed0ae55bebf885d9a879a9349cVinit Deshpande            mResults[i] = reinterpret_cast<wifi_significant_change_result *>(&(mResultsBuffer[i]));
12861a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12871a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12881a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        ALOGI("Retrieved %d scan results", num);
12891a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12901a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        if (num != 0) {
12911a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            (*mHandler.on_significant_change)(id(), num, mResults);
12921a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        } else {
12931a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            ALOGW("No significant change reported");
12941a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        }
12951a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
12961a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return NL_SKIP;
12971a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
12981a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde};
12991a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
13001a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
13011a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        wifi_significant_change_params params, wifi_significant_change_handler handler)
13021a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
13031a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
13041a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
13051a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand(
13061a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde            iface, id, params, handler);
13071a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_register_cmd(handle, id, cmd);
13081a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return (wifi_error)cmd->start();
13091a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
13101a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
13111a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapndewifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
13121a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde{
13131a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    wifi_handle handle = getWifiHandle(iface);
13141a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
13151a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
13161a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    if (cmd) {
13171a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        cmd->cancel();
13181a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        delete cmd;
13191a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde        return WIFI_SUCCESS;
13201a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    }
13211a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde
13221a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde    return WIFI_ERROR_INVALID_ARGS;
13231a526434ae215b48970501ccb463d4e77af39c9eVinit Deshapnde}
1324