gscan.cpp revision 922bc148ebc612b6ecf7233b028099aab78feae4
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    GSCAN_EVENT_FULL_SCAN_RESULTS
38
39} GSCAN_EVENT;
40
41typedef enum {
42
43    GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
44
45    GSCAN_SUBCMD_SET_CONFIG,                            /* 0x1001 */
46
47    GSCAN_SUBCMD_SET_SCAN_CONFIG,                       /* 0x1002 */
48    GSCAN_SUBCMD_ENABLE_GSCAN,                          /* 0x1003 */
49    GSCAN_SUBCMD_GET_SCAN_RESULTS,                      /* 0x1004 */
50    GSCAN_SUBCMD_SCAN_RESULTS,                          /* 0x1005 */
51
52    GSCAN_SUBCMD_SET_HOTLIST,                           /* 0x1006 */
53
54    GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG,         /* 0x1007 */
55    GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS,              /* 0x1008 */
56
57    /* Add more sub commands here */
58
59    GSCAN_SUBCMD_MAX                                    /* 0x1009 */
60
61} GSCAN_SUB_COMMAND;
62
63typedef enum {
64
65    GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
66    GSCAN_ATTRIBUTE_BASE_PERIOD,
67    GSCAN_ATTRIBUTE_BUCKETS_BAND,
68    GSCAN_ATTRIBUTE_BUCKET_ID,
69    GSCAN_ATTRIBUTE_BUCKET_PERIOD,
70    GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
71    GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
72    GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
73    GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
74    GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
75
76    GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
77    GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,              /* indicates no more results */
78    GSCAN_ATTRIBUTE_FLUSH_FEATURE,                      /* Flush all the configs */
79    GSCAN_ENABLE_FULL_SCAN_RESULTS,
80    GSCAN_ATTRIBUTE_REPORT_EVENTS,
81
82    /* remaining reserved for additional attributes */
83    GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
84    GSCAN_ATTRIBUTE_FLUSH_RESULTS,
85    GSCAN_ATTRIBUTE_SCAN_RESULTS,                       /* flat array of wifi_scan_result */
86    GSCAN_ATTRIBUTE_SCAN_ID,                            /* indicates scan number */
87    GSCAN_ATTRIBUTE_SCAN_FLAGS,                         /* indicates if scan was aborted */
88    GSCAN_ATTRIBUTE_AP_FLAGS,                           /* flags on significant change event */
89
90    /* remaining reserved for additional attributes */
91
92    GSCAN_ATTRIBUTE_SSID = 40,
93    GSCAN_ATTRIBUTE_BSSID,
94    GSCAN_ATTRIBUTE_CHANNEL,
95    GSCAN_ATTRIBUTE_RSSI,
96    GSCAN_ATTRIBUTE_TIMESTAMP,
97    GSCAN_ATTRIBUTE_RTT,
98    GSCAN_ATTRIBUTE_RTTSD,
99
100    /* remaining reserved for additional attributes */
101
102    GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,
103    GSCAN_ATTRIBUTE_RSSI_LOW,
104    GSCAN_ATTRIBUTE_RSSI_HIGH,
105    GSCAN_ATTRIBUTE_HOTLIST_ELEM,
106    GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
107
108    /* remaining reserved for additional attributes */
109    GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
110    GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
111    GSCAN_ATTRIBUTE_MIN_BREACHING,
112    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
113    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH,
114
115    GSCAN_ATTRIBUTE_MAX
116
117} GSCAN_ATTRIBUTE;
118
119
120// helper methods
121wifi_error wifi_enable_full_scan_results(wifi_request_id id, wifi_interface_handle iface,
122         wifi_scan_result_handler handler);
123wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface);
124
125
126/////////////////////////////////////////////////////////////////////////////
127
128class GetCapabilitiesCommand : public WifiCommand
129{
130    wifi_gscan_capabilities *mCapabilities;
131public:
132    GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites)
133        : WifiCommand(iface, 0), mCapabilities(capabitlites)
134    {
135        memset(mCapabilities, 0, sizeof(*mCapabilities));
136    }
137
138    virtual int create() {
139        ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);
140
141        int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CAPABILITIES);
142        if (ret < 0) {
143            return ret;
144        }
145
146        return ret;
147    }
148
149protected:
150    virtual int handleResponse(WifiEvent& reply) {
151
152        ALOGD("In GetCapabilities::handleResponse");
153
154        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
155            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
156            return NL_SKIP;
157        }
158
159        int id = reply.get_vendor_id();
160        int subcmd = reply.get_vendor_subcmd();
161
162        ALOGD("Id = %0x, subcmd = %d", id, subcmd);
163
164        void *data = reply.get_vendor_data();
165        int len = reply.get_vendor_data_len();
166
167        if (len == sizeof(*mCapabilities)) {
168            ALOGE("Invalid reply length");
169            memcpy(mCapabilities, data, len);
170        } else {
171            ALOGE("Invalid reply length: %d", len);
172        }
173
174        return NL_OK;
175    }
176};
177
178
179wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
180        wifi_gscan_capabilities *capabilities)
181{
182    GetCapabilitiesCommand command(handle, capabilities);
183    return (wifi_error) command.requestResponse();
184}
185
186/////////////////////////////////////////////////////////////////////////////
187
188/* helper functions */
189
190static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)
191{
192    memset(results, 0, sizeof(wifi_scan_result) * num);
193
194    int i = 0;
195    for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {
196
197        int index = it.get_type();
198        ALOGI("retrieved scan result %d", index);
199        nlattr *sc_data = (nlattr *) it.get_data();
200        wifi_scan_result *result = results + i;
201
202        for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) {
203            int type = it2.get_type();
204            if (type == GSCAN_ATTRIBUTE_SSID) {
205                strncpy(result->ssid, (char *) it2.get_data(), it2.get_len());
206                result->ssid[it2.get_len()] = 0;
207            } else if (type == GSCAN_ATTRIBUTE_BSSID) {
208                memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr));
209            } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) {
210                result->ts = it2.get_u64();
211            } else if (type == GSCAN_ATTRIBUTE_CHANNEL) {
212                result->ts = it2.get_u16();
213            } else if (type == GSCAN_ATTRIBUTE_RSSI) {
214                result->rssi = it2.get_u8();
215            } else if (type == GSCAN_ATTRIBUTE_RTT) {
216                result->rtt = it2.get_u64();
217            } else if (type == GSCAN_ATTRIBUTE_RTTSD) {
218                result->rtt_sd = it2.get_u64();
219            }
220        }
221
222    }
223
224    if (i >= num) {
225        ALOGE("Got too many results; skipping some");
226    }
227
228    return i;
229}
230
231int createFeatureRequest(WifiRequest& request, int subcmd, int enable) {
232
233    int result = request.create(GOOGLE_OUI, subcmd);
234    if (result < 0) {
235        return result;
236    }
237
238    nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
239    result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable);
240    if (result < 0) {
241        return result;
242    }
243
244    request.attr_end(data);
245    return WIFI_SUCCESS;
246}
247
248/////////////////////////////////////////////////////////////////////////////
249class FullScanResultsCommand : public WifiCommand
250{
251    int *mParams;
252    wifi_scan_result_handler mHandler;
253public:
254    FullScanResultsCommand(wifi_interface_handle iface, int id, int *params,
255                wifi_scan_result_handler handler)
256        : WifiCommand(iface, id), mParams(params), mHandler(handler)
257    { }
258
259    int createRequest(WifiRequest& request, int subcmd, int enable) {
260        int result = request.create(GOOGLE_OUI, subcmd);
261        if (result < 0) {
262            return result;
263        }
264
265        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
266        result = request.put_u32(GSCAN_ENABLE_FULL_SCAN_RESULTS, enable);
267        if (result < 0) {
268            return result;
269        }
270
271        request.attr_end(data);
272        return WIFI_SUCCESS;
273
274    }
275
276    int start() {
277        ALOGD("Enabling Full scan results");
278        WifiRequest request(familyId(), ifaceId());
279        int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 1);
280        if (result != WIFI_SUCCESS) {
281            ALOGE("failed to create request; result = %d", result);
282            return result;
283        }
284
285        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
286
287        result = requestResponse(request);
288        if (result != WIFI_SUCCESS) {
289            ALOGE("failed to enable full scan results; result = %d", result);
290            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
291            return result;
292        }
293
294        return result;
295    }
296
297    virtual int cancel() {
298        ALOGD("Disabling Full scan results");
299
300        WifiRequest request(familyId(), ifaceId());
301        int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 0);
302        if (result != WIFI_SUCCESS) {
303            ALOGE("failed to create request; result = %d", result);
304        } else {
305            result = requestResponse(request);
306            if (result != WIFI_SUCCESS) {
307                ALOGE("failed to disable full scan results;result = %d", result);
308            }
309        }
310
311        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
312        return WIFI_SUCCESS;
313    }
314
315    virtual int handleResponse(WifiEvent& reply) {
316         ALOGD("Request complete!");
317        /* Nothing to do on response! */
318        return NL_SKIP;
319    }
320
321    virtual int handleEvent(WifiEvent& event) {
322        ALOGI("Full scan results:  Got an event");
323
324        event.log();
325
326        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
327        unsigned int len = event.get_vendor_data_len();
328
329        if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {
330            ALOGI("No scan results found");
331            return NL_SKIP;
332        }
333
334        wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data();
335
336        (*mHandler.on_full_scan_result)(id(), result);
337        ALOGI("%-32s\t", result->ssid);
338
339        ALOGI("%02x:%02x:%02x:%02x:%02x:%02x ", result->bssid[0], result->bssid[1],
340                result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5]);
341
342        ALOGI("%d\t", result->rssi);
343        ALOGI("%d\t", result->channel);
344        ALOGI("%lld\t", result->ts);
345        ALOGI("%lld\t", result->rtt);
346        ALOGI("%lld\n", result->rtt_sd);
347
348
349        return NL_SKIP;
350    }
351
352};
353/////////////////////////////////////////////////////////////////////////////
354
355class ScanCommand : public WifiCommand
356{
357    wifi_scan_cmd_params *mParams;
358    wifi_scan_result_handler mHandler;
359    static unsigned mGlobalFullScanBuckets;
360    bool mLocalFullScanBuckets;
361public:
362    ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
363                wifi_scan_result_handler handler)
364        : WifiCommand(iface, id), mParams(params), mHandler(handler),
365          mLocalFullScanBuckets(0)
366    { }
367
368    int createSetupRequest(WifiRequest& request) {
369        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG);
370        if (result < 0) {
371            return result;
372        }
373
374        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
375        result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);
376        if (result < 0) {
377            return result;
378        }
379
380        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
381        if (result < 0) {
382            return result;
383        }
384
385        for (int i = 0; i < mParams->num_buckets; i++) {
386            nlattr * bucket = request.attr_start(i);    // next bucket
387            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
388            if (result < 0) {
389                return result;
390            }
391            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
392            if (result < 0) {
393                return result;
394            }
395            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND,
396                    mParams->buckets[i].band);
397            if (result < 0) {
398                return result;
399            }
400
401            result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS,
402                    mParams->buckets[i].report_events);
403            if (result < 0) {
404                return result;
405            }
406
407            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
408                    mParams->buckets[i].num_channels);
409            if (result < 0) {
410                return result;
411            }
412
413            if (mParams->buckets[i].num_channels) {
414                nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
415                for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
416                    result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
417                    if (result < 0) {
418                        return result;
419                    }
420                }
421                request.attr_end(channels);
422            }
423
424            request.attr_end(bucket);
425        }
426
427        request.attr_end(data);
428        return WIFI_SUCCESS;
429    }
430
431    int createScanConfigRequest(WifiRequest& request) {
432        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG);
433        if (result < 0) {
434            return result;
435        }
436
437        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
438        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);
439        if (result < 0) {
440            return result;
441        }
442
443        result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold);
444        if (result < 0) {
445            return result;
446        }
447
448        int num_scans = 10;
449        for (int i = 0; i < mParams->num_buckets; i++) {
450            if (mParams->buckets[i].report_events == 1) {
451                num_scans = 1;
452                break;
453            }
454        }
455
456        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, num_scans);
457        if (result < 0) {
458            return result;
459        }
460
461        request.attr_end(data);
462        return WIFI_SUCCESS;
463    }
464
465    int createStartRequest(WifiRequest& request) {
466        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
467    }
468
469    int createStopRequest(WifiRequest& request) {
470        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0);
471    }
472
473    int enableFullScanResultsIfRequired() {
474        /* temporary workaround till we have full support for per bucket scans */
475
476        ALOGI("enabling full scan results if needed");
477        int nBuckets = 0;
478        for (int i = 0; i < mParams->num_buckets; i++) {
479            if (mParams->buckets[i].report_events == 2) {
480                nBuckets++;
481            }
482        }
483
484        if (mGlobalFullScanBuckets == 0 && nBuckets != 0) {
485            int result = wifi_enable_full_scan_results(0x1000, ifaceHandle(), mHandler);
486            if (result != WIFI_SUCCESS) {
487                ALOGI("failed to enable full scan results");
488                return result;
489            } else {
490                ALOGI("successfully enabled full scan results");
491            }
492        } else {
493            ALOGI("mGlobalFullScanBuckets = %d, nBuckets = %d", mGlobalFullScanBuckets, nBuckets);
494        }
495
496        mLocalFullScanBuckets = nBuckets;
497        mGlobalFullScanBuckets += nBuckets;
498        return WIFI_SUCCESS;
499    }
500
501    int disableFullScanResultsIfRequired() {
502        /* temporary workaround till we have full support for per bucket scans */
503
504        if (mLocalFullScanBuckets == 0) {
505            return WIFI_SUCCESS;
506        }
507
508        mGlobalFullScanBuckets -= mLocalFullScanBuckets;
509        if (mGlobalFullScanBuckets == 0) {
510            int result = wifi_disable_full_scan_results(0x1000, ifaceHandle());
511            if (result != WIFI_SUCCESS) {
512                ALOGI("failed to disable full scan results");
513            } else {
514                ALOGI("successfully disable full scan results");
515            }
516        }
517
518        return WIFI_SUCCESS;
519    }
520
521    int start() {
522        ALOGD("Setting configuration");
523        WifiRequest request(familyId(), ifaceId());
524        int result = createSetupRequest(request);
525        if (result != WIFI_SUCCESS) {
526            ALOGE("failed to create setup request; result = %d", result);
527            return result;
528        }
529
530        result = requestResponse(request);
531        if (result != WIFI_SUCCESS) {
532            ALOGE("failed to configure setup; result = %d", result);
533            return result;
534        }
535
536        request.destroy();
537
538        result = createScanConfigRequest(request);
539        if (result != WIFI_SUCCESS) {
540            ALOGE("failed to create scan config request; result = %d", result);
541            return result;
542        }
543
544        result = requestResponse(request);
545        if (result != WIFI_SUCCESS) {
546            ALOGE("failed to configure scan; result = %d", result);
547            return result;
548        }
549
550        ALOGD("Starting scan");
551
552        result = createStartRequest(request);
553        if (result != WIFI_SUCCESS) {
554            ALOGE("failed to create start request; result = %d", result);
555            return result;
556        }
557
558        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
559
560        result = requestResponse(request);
561        if (result != WIFI_SUCCESS) {
562            ALOGE("failed to start scan; result = %d", result);
563            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
564            return result;
565        }
566
567        result = enableFullScanResultsIfRequired();
568        return result;
569    }
570
571    virtual int cancel() {
572        ALOGD("Stopping scan");
573
574        WifiRequest request(familyId(), ifaceId());
575        int result = createStopRequest(request);
576        if (result != WIFI_SUCCESS) {
577            ALOGE("failed to create stop request; result = %d", result);
578        } else {
579            result = requestResponse(request);
580            if (result != WIFI_SUCCESS) {
581                ALOGE("failed to stop scan; result = %d", result);
582            }
583        }
584
585        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
586        disableFullScanResultsIfRequired();
587
588        return WIFI_SUCCESS;
589    }
590
591    virtual int handleResponse(WifiEvent& reply) {
592        /* Nothing to do on response! */
593        return NL_SKIP;
594    }
595
596    virtual int handleEvent(WifiEvent& event) {
597        ALOGI("Got a scan results event");
598
599        // event.log();
600
601        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
602        int len = event.get_vendor_data_len();
603
604        if (vendor_data == NULL || len != 4) {
605            ALOGI("No scan results found");
606            return NL_SKIP;
607        }
608
609        int num = event.get_u32(NL80211_ATTR_VENDOR_DATA);
610        ALOGI("Found %d scan results", num);
611        (*mHandler.on_scan_results_available)(id(), num);
612        return NL_SKIP;
613    }
614};
615
616unsigned ScanCommand::mGlobalFullScanBuckets = 0;
617
618wifi_error wifi_start_gscan(
619        wifi_request_id id,
620        wifi_interface_handle iface,
621        wifi_scan_cmd_params params,
622        wifi_scan_result_handler handler)
623{
624    wifi_handle handle = getWifiHandle(iface);
625
626    ALOGD("Starting GScan, halHandle = %p", handle);
627
628    ScanCommand *cmd = new ScanCommand(iface, id, &params, handler);
629    wifi_register_cmd(handle, id, cmd);
630    return (wifi_error)cmd->start();
631}
632
633wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
634{
635    ALOGD("Stopping GScan");
636    wifi_handle handle = getWifiHandle(iface);
637
638    if(id == -1) {
639        wifi_scan_result_handler handler;
640        wifi_scan_cmd_params dummy_params;
641        wifi_handle handle = getWifiHandle(iface);
642        memset(&handler, 0, sizeof(handler));
643
644        ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
645        cmd->cancel();
646        delete cmd;
647        return WIFI_SUCCESS;
648    }
649
650
651    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
652    if (cmd) {
653        cmd->cancel();
654        delete cmd;
655        return WIFI_SUCCESS;
656    }
657
658    return WIFI_ERROR_INVALID_ARGS;
659}
660
661
662wifi_error wifi_enable_full_scan_results(
663        wifi_request_id id,
664        wifi_interface_handle iface,
665        wifi_scan_result_handler handler)
666{
667    wifi_handle handle = getWifiHandle(iface);
668    int params_dummy;
669    ALOGD("Enabling full scan results, halHandle = %p", handle);
670
671    FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, id, &params_dummy, handler);
672    wifi_register_cmd(handle, id, cmd);
673
674    return (wifi_error)cmd->start();
675}
676
677wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface)
678{
679    ALOGD("Disabling full scan results");
680    wifi_handle handle = getWifiHandle(iface);
681
682    if(id == -1) {
683        wifi_scan_result_handler handler;
684        wifi_handle handle = getWifiHandle(iface);
685        int params_dummy;
686
687        memset(&handler, 0, sizeof(handler));
688        FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, 0, &params_dummy, handler);
689        cmd->cancel();
690        delete cmd;
691        return WIFI_SUCCESS;
692    }
693
694    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
695    if (cmd) {
696        cmd->cancel();
697        delete cmd;
698        return WIFI_SUCCESS;
699    }
700
701    return WIFI_ERROR_INVALID_ARGS;
702}
703
704
705/////////////////////////////////////////////////////////////////////////////
706
707class GetScanResultsCommand : public WifiCommand {
708    wifi_scan_result *mResults;
709    int *mNum;
710    int mRetrieved;
711    byte mFlush;
712    int mCompleted;
713public:
714    GetScanResultsCommand(wifi_interface_handle iface, byte flush,
715            wifi_scan_result *results, int *num)
716        : WifiCommand(iface, -1), mResults(results), mNum(num),
717                mRetrieved(0), mFlush(flush), mCompleted(0)
718    { }
719
720    int createRequest(WifiRequest& request, int num, byte flush) {
721        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS);
722        if (result < 0) {
723            return result;
724        }
725
726        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
727        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
728        if (result < 0) {
729            return result;
730        }
731
732        result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush);
733        if (result < 0) {
734            return result;
735        }
736
737        request.attr_end(data);
738        return WIFI_SUCCESS;
739    }
740
741    int execute() {
742        WifiRequest request(familyId(), ifaceId());
743        ALOGI("retrieving %d scan results", *mNum);
744
745        for (int i = 0; i < 10 && mRetrieved < *mNum; i++) {
746            int result = createRequest(request, (*mNum - mRetrieved), mFlush);
747            if (result < 0) {
748                ALOGE("failed to create request");
749                return result;
750            }
751
752            int prev_retrieved = mRetrieved;
753
754            result = requestResponse(request);
755
756            if (result != WIFI_SUCCESS) {
757                ALOGE("failed to retrieve scan results; result = %d", result);
758                return result;
759            }
760
761            if (mRetrieved == prev_retrieved || mCompleted) {
762                /* no more items left to retrieve */
763                break;
764            }
765
766            request.destroy();
767        }
768
769        ALOGE("GetScanResults read %d results", mRetrieved);
770        *mNum = mRetrieved;
771        return WIFI_SUCCESS;
772    }
773
774    virtual int handleResponse(WifiEvent& reply) {
775        ALOGD("In GetScanResultsCommand::handleResponse");
776
777        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
778            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
779            return NL_SKIP;
780        }
781
782        int id = reply.get_vendor_id();
783        int subcmd = reply.get_vendor_subcmd();
784
785        ALOGD("Id = %0x, subcmd = %d", id, subcmd);
786
787        /*
788        if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) {
789            ALOGE("Invalid response to GetScanResultsCommand; ignoring it");
790            return NL_SKIP;
791        }
792        */
793
794        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
795        int len = reply.get_vendor_data_len();
796
797        if (vendor_data == NULL || len == 0) {
798            ALOGE("no vendor data in GetScanResults response; ignoring it");
799            return NL_SKIP;
800        }
801
802        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
803            if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) {
804                mCompleted = it.get_u8();
805                ALOGI("retrieved mCompleted flag : %d", mCompleted);
806            } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {
807                for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
808                    int scan_id = 0, flags = 0, num = 0;
809                    if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) {
810                        scan_id = it.get_u32();
811                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
812                        flags = it.get_u8();
813                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
814                        num = it2.get_u32();
815                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
816                        num = it2.get_len() / sizeof(wifi_scan_result);
817                        num = min(*mNum - mRetrieved, num);
818                        memcpy(mResults + mRetrieved, it2.get_data(),
819                                sizeof(wifi_scan_result) * num);
820                        ALOGI("Retrieved %d scan results", num);
821                        wifi_scan_result *results = (wifi_scan_result *)it2.get_data();
822                        for (int i = 0; i < num; i++) {
823                            wifi_scan_result *result = results + i;
824                            ALOGI("%02d  %-32s  %02x:%02x:%02x:%02x:%02x:%02x  %04d", i,
825                                result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
826                                result->bssid[3], result->bssid[4], result->bssid[5],
827                                result->rssi);
828                        }
829                        mRetrieved += num;
830                    } else {
831                        ALOGW("Ignoring invalid attribute type = %d, size = %d",
832                                it.get_type(), it.get_len());
833                    }
834                }
835            } else {
836                ALOGW("Ignoring invalid attribute type = %d, size = %d",
837                        it.get_type(), it.get_len());
838            }
839        }
840
841        return NL_OK;
842    }
843};
844
845wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
846        wifi_scan_result *results, int *num) {
847
848    ALOGD("Getting cached scan results, iface handle = %p, num = %d", iface, *num);
849
850    GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, num);
851    return (wifi_error)cmd->execute();
852}
853
854/////////////////////////////////////////////////////////////////////////////
855
856class BssidHotlistCommand : public WifiCommand
857{
858private:
859    wifi_bssid_hotlist_params mParams;
860    wifi_hotlist_ap_found_handler mHandler;
861    static const int MAX_RESULTS = 64;
862    wifi_scan_result mResults[MAX_RESULTS];
863public:
864    BssidHotlistCommand(wifi_interface_handle handle, int id,
865            wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
866        : WifiCommand(handle, id), mParams(params), mHandler(handler)
867    { }
868
869    int createSetupRequest(WifiRequest& request) {
870        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
871        if (result < 0) {
872            return result;
873        }
874
875        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
876        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
877        if (result < 0) {
878            return result;
879        }
880
881        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
882        for (int i = 0; i < mParams.num; i++) {
883            nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM);
884            if (attr2 == NULL) {
885                return WIFI_ERROR_OUT_OF_MEMORY;
886            }
887            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.bssids[i].bssid);
888            if (result < 0) {
889                return result;
890            }
891            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.bssids[i].high);
892            if (result < 0) {
893                return result;
894            }
895            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.bssids[i].low);
896            if (result < 0) {
897                return result;
898            }
899            request.attr_end(attr2);
900        }
901
902        request.attr_end(attr);
903        request.attr_end(data);
904        return result;
905    }
906
907    int createTeardownRequest(WifiRequest& request) {
908        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
909        if (result < 0) {
910            return result;
911        }
912
913        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
914        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
915        if (result < 0) {
916            return result;
917        }
918
919        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
920        request.attr_end(attr);
921        request.attr_end(data);
922        return result;
923    }
924
925    int start() {
926        ALOGI("Executing hotlist setup request, num = %d", mParams.num);
927        WifiRequest request(familyId(), ifaceId());
928        int result = createSetupRequest(request);
929        if (result < 0) {
930            return result;
931        }
932
933        result = requestResponse(request);
934        if (result < 0) {
935            ALOGI("Failed to execute hotlist setup request, result = %d", result);
936            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
937            return result;
938        }
939
940        ALOGI("Successfully set %d APs in the hotlist", mParams.num);
941        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
942        if (result < 0) {
943            return result;
944        }
945
946        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
947
948        result = requestResponse(request);
949        if (result < 0) {
950            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
951            return result;
952        }
953
954        ALOGI("successfully restarted the scan");
955        return result;
956    }
957
958    virtual int cancel() {
959        /* unregister event handler */
960        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
961
962        /* create set hotlist message with empty hotlist */
963        WifiRequest request(familyId(), ifaceId());
964        int result = createTeardownRequest(request);
965        if (result < 0) {
966            return result;
967        }
968
969        result = requestResponse(request);
970        if (result < 0) {
971            return result;
972        }
973
974        ALOGI("Successfully reset APs in current hotlist");
975        return result;
976    }
977
978    virtual int handleResponse(WifiEvent& reply) {
979        /* Nothing to do on response! */
980        return NL_SKIP;
981    }
982
983    virtual int handleEvent(WifiEvent& event) {
984        ALOGI("Got a hotlist ap found event");
985
986        // event.log();
987
988        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
989        int len = event.get_vendor_data_len();
990
991        if (vendor_data == NULL || len == 0) {
992            ALOGI("No scan results found");
993            return NL_SKIP;
994        }
995
996        memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS);
997
998        int num = len / sizeof(wifi_scan_result);
999        num = min(MAX_RESULTS, num);
1000        memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result));
1001        ALOGI("Retrieved %d hot APs", num);
1002
1003        (*mHandler.on_hotlist_ap_found)(id(), num, mResults);
1004        return NL_SKIP;
1005    }
1006};
1007
1008wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
1009        wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
1010{
1011    wifi_handle handle = getWifiHandle(iface);
1012
1013    BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler);
1014    wifi_register_cmd(handle, id, cmd);
1015    return (wifi_error)cmd->start();
1016}
1017
1018wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
1019{
1020    wifi_handle handle = getWifiHandle(iface);
1021
1022    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
1023    if (cmd) {
1024        cmd->cancel();
1025        delete cmd;
1026        return WIFI_SUCCESS;
1027    }
1028
1029    return WIFI_ERROR_INVALID_ARGS;
1030}
1031
1032
1033/////////////////////////////////////////////////////////////////////////////
1034
1035class SignificantWifiChangeCommand : public WifiCommand
1036{
1037private:
1038    wifi_significant_change_params mParams;
1039    wifi_significant_change_handler mHandler;
1040    static const int MAX_RESULTS = 64;
1041    wifi_scan_result mResults[MAX_RESULTS];
1042public:
1043    SignificantWifiChangeCommand(wifi_interface_handle handle, int id,
1044            wifi_significant_change_params params, wifi_significant_change_handler handler)
1045        : WifiCommand(handle, id), mParams(params), mHandler(handler)
1046    { }
1047
1048    int createSetupRequest(WifiRequest& request) {
1049        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
1050        if (result < 0) {
1051            return result;
1052        }
1053
1054        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
1055        result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
1056        if (result < 0) {
1057            return result;
1058        }
1059        result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);
1060        if (result < 0) {
1061            return result;
1062        }
1063        result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
1064        if (result < 0) {
1065            return result;
1066        }
1067        result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);
1068        if (result < 0) {
1069            return result;
1070        }
1071
1072        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
1073
1074        for (int i = 0; i < mParams.num; i++) {
1075
1076            nlattr *attr2 = request.attr_start(i);
1077            if (attr2 == NULL) {
1078                return WIFI_ERROR_OUT_OF_MEMORY;
1079            }
1080            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.bssids[i].bssid);
1081            if (result < 0) {
1082                return result;
1083            }
1084            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.bssids[i].high);
1085            if (result < 0) {
1086                return result;
1087            }
1088            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.bssids[i].low);
1089            if (result < 0) {
1090                return result;
1091            }
1092            request.attr_end(attr2);
1093        }
1094
1095        request.attr_end(attr);
1096        request.attr_end(data);
1097
1098        return result;
1099    }
1100
1101    int createTeardownRequest(WifiRequest& request) {
1102        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
1103        if (result < 0) {
1104            return result;
1105        }
1106
1107        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
1108        result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
1109        if (result < 0) {
1110            return result;
1111        }
1112
1113        request.attr_end(data);
1114        return result;
1115    }
1116
1117    int start() {
1118        ALOGI("Set significant wifi change config");
1119        WifiRequest request(familyId(), ifaceId());
1120
1121        int result = createSetupRequest(request);
1122        if (result < 0) {
1123            return result;
1124        }
1125
1126        result = requestResponse(request);
1127        if (result < 0) {
1128            ALOGI("failed to set significant wifi change config %d", result);
1129            return result;
1130        }
1131
1132        ALOGI("successfully set significant wifi change config");
1133
1134        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
1135        if (result < 0) {
1136            return result;
1137        }
1138
1139        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
1140
1141        result = requestResponse(request);
1142        if (result < 0) {
1143            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
1144            return result;
1145        }
1146
1147        ALOGI("successfully restarted the scan");
1148        return result;
1149    }
1150
1151    virtual int cancel() {
1152        /* unregister event handler */
1153        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
1154
1155        /* create set significant change monitor message with empty hotlist */
1156        WifiRequest request(familyId(), ifaceId());
1157
1158        int result = createTeardownRequest(request);
1159        if (result < 0) {
1160            return result;
1161        }
1162
1163        result = requestResponse(request);
1164        if (result < 0) {
1165            return result;
1166        }
1167
1168        ALOGI("successfully reset significant wifi change config");
1169        return result;
1170    }
1171
1172    virtual int handleResponse(WifiEvent& reply) {
1173        /* Nothing to do on response! */
1174        return NL_SKIP;
1175    }
1176
1177    virtual int handleEvent(WifiEvent& event) {
1178        ALOGI("Got a significant wifi change event");
1179
1180        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
1181        int len = event.get_vendor_data_len();
1182
1183        if (vendor_data == NULL || len == 0) {
1184            ALOGI("No scan results found");
1185            return NL_SKIP;
1186        }
1187
1188        typedef struct {
1189            uint16_t flags;
1190            uint16_t channel;
1191            mac_addr bssid;
1192            byte rssi_history[8];
1193        } ChangeInfo;
1194
1195        int num = min(len / sizeof(ChangeInfo), MAX_RESULTS);
1196        ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data();
1197
1198        for (int i = 0; i < num; i++) {
1199            memcpy(mResults[i].bssid, ci[i].bssid, sizeof(mac_addr));
1200            mResults[i].rssi = ci[i].rssi_history[7];
1201            mResults[i].channel = ci[i].channel;
1202        }
1203
1204        ALOGI("Retrieved %d scan results", num);
1205
1206        if (num != 0) {
1207            (*mHandler.on_significant_change)(id(), num, mResults);
1208        } else {
1209            ALOGW("No significant change reported");
1210        }
1211
1212        return NL_SKIP;
1213    }
1214};
1215
1216wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
1217        wifi_significant_change_params params, wifi_significant_change_handler handler)
1218{
1219    wifi_handle handle = getWifiHandle(iface);
1220
1221    SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand(
1222            iface, id, params, handler);
1223    wifi_register_cmd(handle, id, cmd);
1224    return (wifi_error)cmd->start();
1225}
1226
1227wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
1228{
1229    wifi_handle handle = getWifiHandle(iface);
1230
1231    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
1232    if (cmd) {
1233        cmd->cancel();
1234        delete cmd;
1235        return WIFI_SUCCESS;
1236    }
1237
1238    return WIFI_ERROR_INVALID_ARGS;
1239}
1240