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