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