1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "sync.h"
18#define LOG_TAG  "WifiHAL"
19#include <utils/Log.h>
20#include <time.h>
21#include <errno.h>
22#include <stdlib.h>
23
24#include "common.h"
25#include "cpp_bindings.h"
26#include "gscancommand.h"
27#include "gscan_event_handler.h"
28
29#define GSCAN_EVENT_WAIT_TIME_SECONDS 4
30
31/* BSSID blacklist */
32typedef struct {
33    int num_bssid;                           // number of blacklisted BSSIDs
34    mac_addr bssids[MAX_BLACKLIST_BSSID];    // blacklisted BSSIDs
35} wifi_bssid_params;
36
37/* Used to handle gscan command events from driver/firmware.*/
38typedef struct gscan_event_handlers_s {
39    GScanCommandEventHandler *gscanStartCmdEventHandler;
40    GScanCommandEventHandler *gScanSetBssidHotlistCmdEventHandler;
41    GScanCommandEventHandler *gScanSetSignificantChangeCmdEventHandler;
42    GScanCommandEventHandler *gScanSetSsidHotlistCmdEventHandler;
43    GScanCommandEventHandler *gScanSetPnoListCmdEventHandler;
44    GScanCommandEventHandler *gScanPnoSetPasspointListCmdEventHandler;
45} gscan_event_handlers;
46
47wifi_error initializeGscanHandlers(hal_info *info)
48{
49    info->gscan_handlers = (gscan_event_handlers *)malloc(sizeof(gscan_event_handlers));
50    if (info->gscan_handlers) {
51        memset(info->gscan_handlers, 0, sizeof(gscan_event_handlers));
52    }
53    else {
54        ALOGE("%s: Allocation of gscan event handlers failed",
55              __FUNCTION__);
56        return WIFI_ERROR_OUT_OF_MEMORY;
57    }
58    return WIFI_SUCCESS;
59}
60
61wifi_error cleanupGscanHandlers(hal_info *info)
62{
63    gscan_event_handlers* event_handlers;
64    if (info && info->gscan_handlers) {
65        event_handlers = (gscan_event_handlers*) info->gscan_handlers;
66        if (event_handlers->gscanStartCmdEventHandler) {
67            delete event_handlers->gscanStartCmdEventHandler;
68        }
69        if (event_handlers->gScanSetBssidHotlistCmdEventHandler) {
70            delete event_handlers->gScanSetBssidHotlistCmdEventHandler;
71        }
72        if (event_handlers->gScanSetSignificantChangeCmdEventHandler) {
73            delete event_handlers->gScanSetSignificantChangeCmdEventHandler;
74        }
75        if (event_handlers->gScanSetSsidHotlistCmdEventHandler) {
76            delete event_handlers->gScanSetSsidHotlistCmdEventHandler;
77        }
78        if (event_handlers->gScanSetPnoListCmdEventHandler) {
79            delete event_handlers->gScanSetPnoListCmdEventHandler;
80        }
81        if (event_handlers->gScanPnoSetPasspointListCmdEventHandler) {
82            delete event_handlers->gScanPnoSetPasspointListCmdEventHandler;
83        }
84        memset(event_handlers, 0, sizeof(gscan_event_handlers));
85        return WIFI_SUCCESS;
86    }
87    ALOGE ("%s: info or info->gscan_handlers NULL", __FUNCTION__);
88    return WIFI_ERROR_UNKNOWN;
89}
90
91/* Implementation of the API functions exposed in gscan.h */
92wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
93       int band, int max_channels, wifi_channel *channels, int *num_channels)
94{
95    int requestId, ret = 0;
96    GScanCommand *gScanCommand;
97    struct nlattr *nlData;
98    interface_info *ifaceInfo = getIfaceInfo(handle);
99    wifi_handle wifiHandle = getWifiHandle(handle);
100    lowi_cb_table_t *lowiWifiHalApi = NULL;
101
102    /* Route GSCAN request through LOWI if supported */
103    lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
104    if (lowiWifiHalApi == NULL ||
105        lowiWifiHalApi->get_valid_channels == NULL) {
106        ALOGV("%s: Sending cmd directly to host", __FUNCTION__);
107    } else {
108        ret = lowiWifiHalApi->get_valid_channels(handle, band, max_channels,
109                          channels, num_channels);
110        ALOGV("%s: lowi get_valid_channels "
111            "returned: %d. Exit.", __FUNCTION__, ret);
112        return (wifi_error)ret;
113    }
114
115    /* No request id from caller, so generate one and pass it on to the driver.
116     * Generate one randomly.
117     */
118    requestId = get_requestid();
119    ALOGV("%s: RequestId:%d band:%d max_channels:%d", __FUNCTION__,
120          requestId, band, max_channels);
121
122    if (channels == NULL) {
123        ALOGE("%s: NULL channels pointer provided. Exit.",
124            __FUNCTION__);
125        return WIFI_ERROR_INVALID_ARGS;
126    }
127
128    gScanCommand = new GScanCommand(
129                            wifiHandle,
130                            requestId,
131                            OUI_QCA,
132                            QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS);
133    if (gScanCommand == NULL) {
134        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
135        return WIFI_ERROR_UNKNOWN;
136    }
137    /* Create the NL message. */
138    ret = gScanCommand->create();
139    if (ret < 0)
140        goto cleanup;
141
142    /* Set the interface Id of the message. */
143    ret = gScanCommand->set_iface_id(ifaceInfo->name);
144    if (ret < 0)
145        goto cleanup;
146
147    /* Add the vendor specific attributes for the NL command. */
148    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
149    if (!nlData)
150        goto cleanup;
151
152    if (gScanCommand->put_u32(
153            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
154            requestId) ||
155        gScanCommand->put_u32(
156        QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND,
157            band) ||
158        gScanCommand->put_u32(
159        QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS,
160            max_channels) )
161    {
162        goto cleanup;
163    }
164    gScanCommand->attr_end(nlData);
165    /* Populate the input received from caller/framework. */
166    gScanCommand->setMaxChannels(max_channels);
167    gScanCommand->setChannels(channels);
168    gScanCommand->setNumChannelsPtr(num_channels);
169
170    /* Send the msg and wait for a response. */
171    ret = gScanCommand->requestResponse();
172    if (ret) {
173        ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
174    }
175
176cleanup:
177    delete gScanCommand;
178    return (wifi_error)ret;
179}
180
181wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
182                                 wifi_gscan_capabilities *capabilities)
183{
184    wifi_error ret = WIFI_SUCCESS;
185    wifi_handle wifiHandle = getWifiHandle(handle);
186    hal_info *info = getHalInfo(wifiHandle);
187    lowi_cb_table_t *lowiWifiHalApi = NULL;
188
189    if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
190        ALOGE("%s: GSCAN is not supported by driver", __FUNCTION__);
191        return WIFI_ERROR_NOT_SUPPORTED;
192     }
193
194    if (capabilities == NULL) {
195        ALOGE("%s: NULL capabilities pointer provided. Exit.", __FUNCTION__);
196        return WIFI_ERROR_INVALID_ARGS;
197    }
198
199    /* Route GSCAN request through LOWI if supported */
200    lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
201    if (lowiWifiHalApi == NULL ||
202        lowiWifiHalApi->get_gscan_capabilities == NULL) {
203        ALOGV("%s: Sending cmd directly to host", __FUNCTION__);
204    } else {
205        ret = lowiWifiHalApi->get_gscan_capabilities(handle, capabilities);
206        ALOGV("%s: lowi get_gscan_capabilities returned: %d. Exit.", __FUNCTION__, ret);
207        return ret;
208    }
209
210    memcpy(capabilities, &info->capa.gscan_capa, sizeof(wifi_gscan_capabilities));
211
212    return ret;
213}
214
215wifi_error wifi_start_gscan(wifi_request_id id,
216                            wifi_interface_handle iface,
217                            wifi_scan_cmd_params params,
218                            wifi_scan_result_handler handler)
219{
220    int ret = 0;
221    u32 i, j;
222    GScanCommand *gScanCommand;
223    struct nlattr *nlData;
224    interface_info *ifaceInfo = getIfaceInfo(iface);
225    wifi_handle wifiHandle = getWifiHandle(iface);
226    u32 num_scan_buckets, numChannelSpecs;
227    wifi_scan_bucket_spec bucketSpec;
228    struct nlattr *nlBuckectSpecList;
229    hal_info *info = getHalInfo(wifiHandle);
230    lowi_cb_table_t *lowiWifiHalApi = NULL;
231    gscan_event_handlers* event_handlers;
232    GScanCommandEventHandler *gScanStartCmdEventHandler;
233
234    event_handlers = (gscan_event_handlers*)info->gscan_handlers;
235    gScanStartCmdEventHandler = event_handlers->gscanStartCmdEventHandler;
236
237    if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
238        ALOGE("%s: GSCAN is not supported by driver",
239            __FUNCTION__);
240        return WIFI_ERROR_NOT_SUPPORTED;
241    }
242
243    /* Route GSCAN request through LOWI if supported */
244    lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
245    if (lowiWifiHalApi == NULL ||
246        lowiWifiHalApi->start_gscan  == NULL) {
247        ALOGV("%s: Sending cmd directly to host", __FUNCTION__);
248    } else {
249        ret = lowiWifiHalApi->start_gscan(id, iface, params, handler);
250        ALOGV("%s: lowi start_gscan "
251            "returned: %d. Exit.", __FUNCTION__, ret);
252        return (wifi_error)ret;
253    }
254
255    ALOGV("%s: RequestId:%d ", __FUNCTION__, id);
256    /* Wi-Fi HAL doesn't need to check if a similar request to start gscan was
257     *  made earlier. If start_gscan() is called while another gscan is already
258     *  running, the request will be sent down to driver and firmware. If new
259     * request is successfully honored, then Wi-Fi HAL will use the new request
260     * id for the gScanStartCmdEventHandler object.
261     */
262    gScanCommand = new GScanCommand(
263                                wifiHandle,
264                                id,
265                                OUI_QCA,
266                                QCA_NL80211_VENDOR_SUBCMD_GSCAN_START);
267    if (gScanCommand == NULL) {
268        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
269        return WIFI_ERROR_UNKNOWN;
270    }
271
272    /* Create the NL message. */
273    ret = gScanCommand->create();
274    if (ret < 0)
275        goto cleanup;
276
277    /* Set the interface Id of the message. */
278    ret = gScanCommand->set_iface_id(ifaceInfo->name);
279    if (ret < 0)
280        goto cleanup;
281
282    /* Add the vendor specific attributes for the NL command. */
283    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
284    if (!nlData)
285        goto cleanup;
286
287    num_scan_buckets = (unsigned int)params.num_buckets > MAX_BUCKETS ?
288                            MAX_BUCKETS : params.num_buckets;
289
290    ALOGV("%s: Base Period:%d Max_ap_per_scan:%d "
291          "Threshold_percent:%d Threshold_num_scans:%d "
292          "num_buckets:%d", __FUNCTION__, params.base_period,
293          params.max_ap_per_scan, params.report_threshold_percent,
294          params.report_threshold_num_scans, num_scan_buckets);
295    if (gScanCommand->put_u32(
296            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
297            id) ||
298        gScanCommand->put_u32(
299            QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_BASE_PERIOD,
300            params.base_period) ||
301        gScanCommand->put_u32(
302            QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN,
303            params.max_ap_per_scan) ||
304        gScanCommand->put_u8(
305            QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT,
306            params.report_threshold_percent) ||
307        gScanCommand->put_u8(
308            QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS,
309            params.report_threshold_num_scans) ||
310        gScanCommand->put_u8(
311            QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS,
312            num_scan_buckets))
313    {
314        goto cleanup;
315    }
316
317    nlBuckectSpecList =
318        gScanCommand->attr_start(QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC);
319    /* Add NL attributes for scan bucket specs . */
320    for (i = 0; i < num_scan_buckets; i++) {
321        bucketSpec = params.buckets[i];
322        numChannelSpecs = (unsigned int)bucketSpec.num_channels > MAX_CHANNELS ?
323                                MAX_CHANNELS : bucketSpec.num_channels;
324
325        ALOGV("%s: Index: %d Bucket Id:%d Band:%d Period:%d ReportEvent:%d "
326              "numChannelSpecs:%d max_period:%d base:%d step_count:%d",
327              __FUNCTION__, i, bucketSpec.bucket, bucketSpec.band,
328              bucketSpec.period, bucketSpec.report_events,
329              numChannelSpecs, bucketSpec.max_period,
330              bucketSpec.base, bucketSpec.step_count);
331
332        struct nlattr *nlBucketSpec = gScanCommand->attr_start(i);
333        if (gScanCommand->put_u8(
334                QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_INDEX,
335                bucketSpec.bucket) ||
336            gScanCommand->put_u8(
337                QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BAND,
338                bucketSpec.band) ||
339            gScanCommand->put_u32(
340                QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_PERIOD,
341                bucketSpec.period) ||
342            gScanCommand->put_u8(
343                QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_REPORT_EVENTS,
344                bucketSpec.report_events) ||
345            gScanCommand->put_u32(
346                QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS,
347                numChannelSpecs) ||
348            gScanCommand->put_u32(
349                QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_MAX_PERIOD,
350                bucketSpec.max_period) ||
351            gScanCommand->put_u32(
352                QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BASE,
353                bucketSpec.base) ||
354            gScanCommand->put_u32(
355                QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_STEP_COUNT,
356                bucketSpec.step_count))
357        {
358            goto cleanup;
359        }
360
361        struct nlattr *nl_channelSpecList =
362            gScanCommand->attr_start(QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC);
363
364        /* Add NL attributes for scan channel specs . */
365        for (j = 0; j < numChannelSpecs; j++) {
366            struct nlattr *nl_channelSpec = gScanCommand->attr_start(j);
367            wifi_scan_channel_spec channel_spec = bucketSpec.channels[j];
368
369            ALOGV("%s: Channel Spec Index:%d Channel:%d Dwell Time:%d "
370                  "passive:%d", __FUNCTION__, j, channel_spec.channel,
371                  channel_spec.dwellTimeMs, channel_spec.passive);
372
373            if ( gScanCommand->put_u32(
374                    QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_CHANNEL,
375                    channel_spec.channel) ||
376                gScanCommand->put_u32(
377                    QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_DWELL_TIME,
378                    channel_spec.dwellTimeMs) ||
379                gScanCommand->put_u8(
380                    QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_PASSIVE,
381                    channel_spec.passive) )
382            {
383                goto cleanup;
384            }
385
386            gScanCommand->attr_end(nl_channelSpec);
387        }
388        gScanCommand->attr_end(nl_channelSpecList);
389        gScanCommand->attr_end(nlBucketSpec);
390    }
391    gScanCommand->attr_end(nlBuckectSpecList);
392
393    gScanCommand->attr_end(nlData);
394
395    /* Set the callback handler functions for related events. */
396    GScanCallbackHandler callbackHandler;
397    memset(&callbackHandler, 0, sizeof(callbackHandler));
398    callbackHandler.on_full_scan_result = handler.on_full_scan_result;
399    callbackHandler.on_scan_event = handler.on_scan_event;
400
401    /* Create an object to handle the related events from firmware/driver. */
402    if (gScanStartCmdEventHandler == NULL) {
403        gScanStartCmdEventHandler = new GScanCommandEventHandler(
404                                    wifiHandle,
405                                    id,
406                                    OUI_QCA,
407                                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_START,
408                                    callbackHandler);
409        if (gScanStartCmdEventHandler == NULL) {
410            ALOGE("%s: Error gScanStartCmdEventHandler NULL", __FUNCTION__);
411            ret = WIFI_ERROR_UNKNOWN;
412            goto cleanup;
413        }
414        event_handlers->gscanStartCmdEventHandler = gScanStartCmdEventHandler;
415    } else {
416        gScanStartCmdEventHandler->setCallbackHandler(callbackHandler);
417    }
418
419    ret = gScanCommand->requestResponse();
420    if (ret != 0) {
421        ALOGE("%s : requestResponse Error:%d", __FUNCTION__, ret);
422        goto cleanup;
423    }
424
425    if (gScanStartCmdEventHandler != NULL) {
426        gScanStartCmdEventHandler->set_request_id(id);
427        gScanStartCmdEventHandler->enableEventHandling();
428    }
429
430cleanup:
431    delete gScanCommand;
432    /* Disable Event Handling if ret != 0 */
433    if (ret && gScanStartCmdEventHandler) {
434        ALOGI("%s: Error ret:%d, disable event handling",
435            __FUNCTION__, ret);
436        gScanStartCmdEventHandler->disableEventHandling();
437    }
438    return (wifi_error)ret;
439
440}
441
442wifi_error wifi_stop_gscan(wifi_request_id id,
443                            wifi_interface_handle iface)
444{
445    int ret = 0;
446    GScanCommand *gScanCommand;
447    struct nlattr *nlData;
448    lowi_cb_table_t *lowiWifiHalApi = NULL;
449
450    interface_info *ifaceInfo = getIfaceInfo(iface);
451    wifi_handle wifiHandle = getWifiHandle(iface);
452    hal_info *info = getHalInfo(wifiHandle);
453    gscan_event_handlers* event_handlers;
454    GScanCommandEventHandler *gScanStartCmdEventHandler;
455
456    event_handlers = (gscan_event_handlers*)info->gscan_handlers;
457    gScanStartCmdEventHandler = event_handlers->gscanStartCmdEventHandler;
458
459    if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
460        ALOGE("%s: GSCAN is not supported by driver",
461            __FUNCTION__);
462        return WIFI_ERROR_NOT_SUPPORTED;
463    }
464
465    /* Route GSCAN request through LOWI if supported */
466    lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
467    if (lowiWifiHalApi == NULL ||
468        lowiWifiHalApi->stop_gscan == NULL) {
469        ALOGV("%s: Sending cmd directly to host", __FUNCTION__);
470    } else {
471        ret = lowiWifiHalApi->stop_gscan(id, iface);
472        ALOGV("%s: lowi stop_gscan "
473            "returned: %d. Exit.", __FUNCTION__, ret);
474        return (wifi_error)ret;
475    }
476
477    if (gScanStartCmdEventHandler == NULL ||
478        gScanStartCmdEventHandler->isEventHandlingEnabled() == false) {
479        ALOGE("%s: GSCAN isn't running or already stopped. "
480            "Nothing to do. Exit", __FUNCTION__);
481        return WIFI_ERROR_NOT_AVAILABLE;
482    }
483
484    gScanCommand = new GScanCommand(
485                                wifiHandle,
486                                id,
487                                OUI_QCA,
488                                QCA_NL80211_VENDOR_SUBCMD_GSCAN_STOP);
489    if (gScanCommand == NULL) {
490        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
491        return WIFI_ERROR_UNKNOWN;
492    }
493
494    /* Create the NL message. */
495    ret = gScanCommand->create();
496    if (ret < 0)
497        goto cleanup;
498
499    /* Set the interface Id of the message. */
500    ret = gScanCommand->set_iface_id(ifaceInfo->name);
501    if (ret < 0)
502        goto cleanup;
503
504    /* Add the vendor specific attributes for the NL command. */
505    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
506    if (!nlData)
507        goto cleanup;
508
509    ret = gScanCommand->put_u32(
510            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
511            id);
512    if (ret < 0)
513        goto cleanup;
514
515    gScanCommand->attr_end(nlData);
516
517    ret = gScanCommand->requestResponse();
518    if (ret != 0) {
519        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
520    }
521
522    /* Disable Event Handling. */
523    if (gScanStartCmdEventHandler) {
524        gScanStartCmdEventHandler->disableEventHandling();
525    }
526
527cleanup:
528    delete gScanCommand;
529    return (wifi_error)ret;
530}
531
532/* Set the GSCAN BSSID Hotlist. */
533wifi_error wifi_set_bssid_hotlist(wifi_request_id id,
534                                    wifi_interface_handle iface,
535                                    wifi_bssid_hotlist_params params,
536                                    wifi_hotlist_ap_found_handler handler)
537{
538    int i, numAp, ret = 0;
539    GScanCommand *gScanCommand;
540    struct nlattr *nlData, *nlApThresholdParamList;
541    interface_info *ifaceInfo = getIfaceInfo(iface);
542    wifi_handle wifiHandle = getWifiHandle(iface);
543    hal_info *info = getHalInfo(wifiHandle);
544    lowi_cb_table_t *lowiWifiHalApi = NULL;
545    gscan_event_handlers* event_handlers;
546    GScanCommandEventHandler *gScanSetBssidHotlistCmdEventHandler;
547
548    event_handlers = (gscan_event_handlers*)info->gscan_handlers;
549    gScanSetBssidHotlistCmdEventHandler =
550        event_handlers->gScanSetBssidHotlistCmdEventHandler;
551
552    if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
553        ALOGE("%s: GSCAN is not supported by driver",
554            __FUNCTION__);
555        return WIFI_ERROR_NOT_SUPPORTED;
556    }
557
558    /* Route request through LOWI if supported*/
559    lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
560    if (lowiWifiHalApi == NULL ||
561        lowiWifiHalApi->set_bssid_hotlist == NULL) {
562        ALOGV("%s: Sending cmd directly to host", __FUNCTION__);
563    } else {
564        ret = lowiWifiHalApi->set_bssid_hotlist(id, iface, params,handler);
565        ALOGV("%s: lowi set_bssid_hotlist "
566            "returned: %d. Exit.", __FUNCTION__, ret);
567        return (wifi_error)ret;
568    }
569
570    /* Wi-Fi HAL doesn't need to check if a similar request to set bssid
571     * hotlist was made earlier. If set_bssid_hotlist() is called while
572     * another one is running, the request will be sent down to driver and
573     * firmware. If the new request is successfully honored, then Wi-Fi HAL
574     * will use the new request id for the gScanSetBssidHotlistCmdEventHandler
575     * object.
576     */
577
578    gScanCommand =
579        new GScanCommand(
580                    wifiHandle,
581                    id,
582                    OUI_QCA,
583                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST);
584    if (gScanCommand == NULL) {
585        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
586        return WIFI_ERROR_UNKNOWN;
587    }
588
589    /* Create the NL message. */
590    ret = gScanCommand->create();
591    if (ret < 0)
592        goto cleanup;
593
594    /* Set the interface Id of the message. */
595    ret = gScanCommand->set_iface_id(ifaceInfo->name);
596    if (ret < 0)
597        goto cleanup;
598
599    /* Add the vendor specific attributes for the NL command. */
600    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
601    if (!nlData)
602        goto cleanup;
603
604    numAp = (unsigned int)params.num_bssid > MAX_HOTLIST_APS ?
605        MAX_HOTLIST_APS : params.num_bssid;
606    if (gScanCommand->put_u32(
607            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
608            id) ||
609        gScanCommand->put_u32(
610            QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE,
611            params.lost_ap_sample_size) ||
612        gScanCommand->put_u32(
613            QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_NUM_AP,
614            numAp))
615    {
616        goto cleanup;
617    }
618
619    ALOGV("%s: lost_ap_sample_size:%d numAp:%d", __FUNCTION__,
620          params.lost_ap_sample_size, numAp);
621    /* Add the vendor specific attributes for the NL command. */
622    nlApThresholdParamList =
623        gScanCommand->attr_start(
624                                QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM);
625    if (!nlApThresholdParamList)
626        goto cleanup;
627
628    /* Add nested NL attributes for AP Threshold Param. */
629    for (i = 0; i < numAp; i++) {
630        ap_threshold_param apThreshold = params.ap[i];
631        struct nlattr *nlApThresholdParam = gScanCommand->attr_start(i);
632        if (!nlApThresholdParam)
633            goto cleanup;
634        if (gScanCommand->put_addr(
635                QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_BSSID,
636                apThreshold.bssid) ||
637            gScanCommand->put_s32(
638                QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_LOW,
639                apThreshold.low) ||
640            gScanCommand->put_s32(
641                QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH,
642                apThreshold.high))
643        {
644            goto cleanup;
645        }
646        ALOGV("%s: Index:%d BssId: %hhx:%hhx:%hhx:%hhx:%hhx:%hhx "
647              "Threshold low:%d high:%d", __FUNCTION__, i,
648              apThreshold.bssid[0], apThreshold.bssid[1],
649              apThreshold.bssid[2], apThreshold.bssid[3],
650              apThreshold.bssid[4], apThreshold.bssid[5],
651              apThreshold.low, apThreshold.high);
652        gScanCommand->attr_end(nlApThresholdParam);
653    }
654
655    gScanCommand->attr_end(nlApThresholdParamList);
656
657    gScanCommand->attr_end(nlData);
658
659    GScanCallbackHandler callbackHandler;
660    memset(&callbackHandler, 0, sizeof(callbackHandler));
661    callbackHandler.on_hotlist_ap_found = handler.on_hotlist_ap_found;
662    callbackHandler.on_hotlist_ap_lost = handler.on_hotlist_ap_lost;
663
664    /* Create an object of the event handler class to take care of the
665      * asychronous events on the north-bound.
666      */
667    if (gScanSetBssidHotlistCmdEventHandler == NULL) {
668        gScanSetBssidHotlistCmdEventHandler = new GScanCommandEventHandler(
669                            wifiHandle,
670                            id,
671                            OUI_QCA,
672                            QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST,
673                            callbackHandler);
674        if (gScanSetBssidHotlistCmdEventHandler == NULL) {
675            ALOGE("%s: Error instantiating "
676                "gScanSetBssidHotlistCmdEventHandler.", __FUNCTION__);
677            ret = WIFI_ERROR_UNKNOWN;
678            goto cleanup;
679        }
680        event_handlers->gScanSetBssidHotlistCmdEventHandler =
681            gScanSetBssidHotlistCmdEventHandler;
682    } else {
683        gScanSetBssidHotlistCmdEventHandler->setCallbackHandler(callbackHandler);
684    }
685
686    ret = gScanCommand->requestResponse();
687    if (ret != 0) {
688        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
689        goto cleanup;
690    }
691
692    if (gScanSetBssidHotlistCmdEventHandler != NULL) {
693        gScanSetBssidHotlistCmdEventHandler->set_request_id(id);
694        gScanSetBssidHotlistCmdEventHandler->enableEventHandling();
695    }
696
697cleanup:
698    delete gScanCommand;
699    /* Disable Event Handling if ret != 0 */
700    if (ret && gScanSetBssidHotlistCmdEventHandler) {
701        ALOGI("%s: Error ret:%d, disable event handling",
702            __FUNCTION__, ret);
703        gScanSetBssidHotlistCmdEventHandler->disableEventHandling();
704    }
705    return (wifi_error)ret;
706}
707
708wifi_error wifi_reset_bssid_hotlist(wifi_request_id id,
709                            wifi_interface_handle iface)
710{
711    int ret = 0;
712    GScanCommand *gScanCommand;
713    struct nlattr *nlData;
714    interface_info *ifaceInfo = getIfaceInfo(iface);
715    wifi_handle wifiHandle = getWifiHandle(iface);
716    hal_info *info = getHalInfo(wifiHandle);
717    lowi_cb_table_t *lowiWifiHalApi = NULL;
718    gscan_event_handlers* event_handlers;
719    GScanCommandEventHandler *gScanSetBssidHotlistCmdEventHandler;
720
721    event_handlers = (gscan_event_handlers*)info->gscan_handlers;
722    gScanSetBssidHotlistCmdEventHandler =
723        event_handlers->gScanSetBssidHotlistCmdEventHandler;
724
725    if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
726        ALOGE("%s: GSCAN is not supported by driver",
727            __FUNCTION__);
728        return WIFI_ERROR_NOT_SUPPORTED;
729    }
730
731    /* Route request through LOWI if supported*/
732    lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
733    if (lowiWifiHalApi == NULL ||
734        lowiWifiHalApi->reset_bssid_hotlist == NULL) {
735        ALOGV("%s: Sending cmd directly to host", __FUNCTION__);
736    } else {
737        ret = lowiWifiHalApi->reset_bssid_hotlist(id, iface);
738        ALOGV("%s: lowi reset_bssid_hotlist "
739            "returned: %d. Exit.", __FUNCTION__, ret);
740        return (wifi_error)ret;
741    }
742
743
744    if (gScanSetBssidHotlistCmdEventHandler == NULL ||
745        (gScanSetBssidHotlistCmdEventHandler->isEventHandlingEnabled() ==
746         false)) {
747        ALOGE("wifi_reset_bssid_hotlist: GSCAN bssid_hotlist isn't set. "
748            "Nothing to do. Exit");
749        return WIFI_ERROR_NOT_AVAILABLE;
750    }
751
752    gScanCommand = new GScanCommand(
753                        wifiHandle,
754                        id,
755                        OUI_QCA,
756                        QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_BSSID_HOTLIST);
757
758    if (gScanCommand == NULL) {
759        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
760        return WIFI_ERROR_UNKNOWN;
761    }
762
763    /* Create the NL message. */
764    ret = gScanCommand->create();
765    if (ret < 0)
766        goto cleanup;
767
768    /* Set the interface Id of the message. */
769    ret = gScanCommand->set_iface_id(ifaceInfo->name);
770    if (ret < 0)
771        goto cleanup;
772
773    /* Add the vendor specific attributes for the NL command. */
774    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
775    if (!nlData)
776        goto cleanup;
777
778    ret = gScanCommand->put_u32(
779            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID, id);
780    if (ret < 0)
781        goto cleanup;
782
783    gScanCommand->attr_end(nlData);
784
785    ret = gScanCommand->requestResponse();
786    if (ret != 0) {
787        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
788    }
789
790    /* Disable Event Handling. */
791    if (gScanSetBssidHotlistCmdEventHandler) {
792        gScanSetBssidHotlistCmdEventHandler->disableEventHandling();
793    }
794
795cleanup:
796    delete gScanCommand;
797    return (wifi_error)ret;
798}
799
800/* Set the GSCAN Significant AP Change list. */
801wifi_error wifi_set_significant_change_handler(wifi_request_id id,
802                                            wifi_interface_handle iface,
803                                    wifi_significant_change_params params,
804                                    wifi_significant_change_handler handler)
805{
806    int i, numAp, ret = 0;
807    GScanCommand *gScanCommand;
808    struct nlattr *nlData, *nlApThresholdParamList;
809    interface_info *ifaceInfo = getIfaceInfo(iface);
810    wifi_handle wifiHandle = getWifiHandle(iface);
811    hal_info *info = getHalInfo(wifiHandle);
812    lowi_cb_table_t *lowiWifiHalApi = NULL;
813    gscan_event_handlers* event_handlers;
814    GScanCommandEventHandler *gScanSetSignificantChangeCmdEventHandler;
815
816    event_handlers = (gscan_event_handlers*)info->gscan_handlers;
817    gScanSetSignificantChangeCmdEventHandler =
818        event_handlers->gScanSetSignificantChangeCmdEventHandler;
819
820    if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
821        ALOGE("%s: GSCAN is not supported by driver",
822            __FUNCTION__);
823        return WIFI_ERROR_NOT_SUPPORTED;
824    }
825
826    /* Route request through LOWI if supported*/
827    lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
828    if (lowiWifiHalApi == NULL ||
829        lowiWifiHalApi->set_significant_change_handler == NULL) {
830        ALOGV("%s: Sending cmd directly to host", __FUNCTION__);
831    } else {
832        ret = lowiWifiHalApi->set_significant_change_handler(id,
833                                                             iface,
834                                                             params,
835                                                             handler);
836        ALOGV("%s: lowi set_significant_change_handler "
837            "returned: %d. Exit.", __FUNCTION__, ret);
838        return (wifi_error)ret;
839    }
840
841    /* Wi-Fi HAL doesn't need to check if a similar request to set significant
842     * change list was made earlier. If set_significant_change() is called while
843     * another one is running, the request will be sent down to driver and
844     * firmware. If the new request is successfully honored, then Wi-Fi HAL
845     * will use the new request id for the gScanSetSignificantChangeCmdEventHandler
846     * object.
847     */
848
849    gScanCommand = new GScanCommand(
850                    wifiHandle,
851                    id,
852                    OUI_QCA,
853                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE);
854    if (gScanCommand == NULL) {
855        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
856        return WIFI_ERROR_UNKNOWN;
857    }
858
859    /* Create the NL message. */
860    ret = gScanCommand->create();
861    if (ret < 0)
862        goto cleanup;
863
864    /* Set the interface Id of the message. */
865    ret = gScanCommand->set_iface_id(ifaceInfo->name);
866    if (ret < 0)
867        goto cleanup;
868
869    /* Add the vendor specific attributes for the NL command. */
870    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
871    if (!nlData)
872        goto cleanup;
873
874    numAp = (unsigned int)params.num_bssid > MAX_SIGNIFICANT_CHANGE_APS ?
875        MAX_SIGNIFICANT_CHANGE_APS : params.num_bssid;
876
877    if (gScanCommand->put_u32(
878            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
879            id) ||
880        gScanCommand->put_u32(
881        QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE,
882            params.rssi_sample_size) ||
883        gScanCommand->put_u32(
884        QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE,
885            params.lost_ap_sample_size) ||
886        gScanCommand->put_u32(
887            QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING,
888            params.min_breaching) ||
889        gScanCommand->put_u32(
890            QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP,
891            numAp))
892    {
893        goto cleanup;
894    }
895
896    ALOGV("%s: Number of AP params:%d Rssi_sample_size:%d "
897          "lost_ap_sample_size:%d min_breaching:%d", __FUNCTION__,
898          numAp, params.rssi_sample_size, params.lost_ap_sample_size,
899          params.min_breaching);
900
901    /* Add the vendor specific attributes for the NL command. */
902    nlApThresholdParamList =
903        gScanCommand->attr_start(
904                                QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM);
905    if (!nlApThresholdParamList)
906        goto cleanup;
907
908    /* Add nested NL attributes for AP Threshold Param list. */
909    for (i = 0; i < numAp; i++) {
910        ap_threshold_param apThreshold = params.ap[i];
911        struct nlattr *nlApThresholdParam = gScanCommand->attr_start(i);
912        if (!nlApThresholdParam)
913            goto cleanup;
914        if ( gScanCommand->put_addr(
915                QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_BSSID,
916                apThreshold.bssid) ||
917            gScanCommand->put_s32(
918                QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_LOW,
919                apThreshold.low) ||
920            gScanCommand->put_s32(
921                QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH,
922                apThreshold.high))
923        {
924            goto cleanup;
925        }
926        ALOGV("%s: ap[%d].bssid:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx "
927              "ap[%d].low:%d  ap[%d].high:%d", __FUNCTION__,
928              i,
929              apThreshold.bssid[0], apThreshold.bssid[1],
930              apThreshold.bssid[2], apThreshold.bssid[3],
931              apThreshold.bssid[4], apThreshold.bssid[5],
932              i, apThreshold.low, i, apThreshold.high);
933        gScanCommand->attr_end(nlApThresholdParam);
934    }
935
936    gScanCommand->attr_end(nlApThresholdParamList);
937
938    gScanCommand->attr_end(nlData);
939
940    GScanCallbackHandler callbackHandler;
941    memset(&callbackHandler, 0, sizeof(callbackHandler));
942    callbackHandler.on_significant_change = handler.on_significant_change;
943
944    /* Create an object of the event handler class to take care of the
945      * asychronous events on the north-bound.
946      */
947    if (gScanSetSignificantChangeCmdEventHandler == NULL) {
948        gScanSetSignificantChangeCmdEventHandler =
949            new GScanCommandEventHandler(
950                     wifiHandle,
951                     id,
952                     OUI_QCA,
953                     QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE,
954                     callbackHandler);
955        if (gScanSetSignificantChangeCmdEventHandler == NULL) {
956            ALOGE("%s: Error in instantiating, "
957                "gScanSetSignificantChangeCmdEventHandler.",
958                __FUNCTION__);
959            ret = WIFI_ERROR_UNKNOWN;
960            goto cleanup;
961        }
962        event_handlers->gScanSetSignificantChangeCmdEventHandler =
963            gScanSetSignificantChangeCmdEventHandler;
964    } else {
965        gScanSetSignificantChangeCmdEventHandler->setCallbackHandler(callbackHandler);
966    }
967
968    ret = gScanCommand->requestResponse();
969    if (ret != 0) {
970        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
971        goto cleanup;
972    }
973
974    if (gScanSetSignificantChangeCmdEventHandler != NULL) {
975        gScanSetSignificantChangeCmdEventHandler->set_request_id(id);
976        gScanSetSignificantChangeCmdEventHandler->enableEventHandling();
977    }
978
979cleanup:
980    /* Disable Event Handling if ret != 0 */
981    if (ret && gScanSetSignificantChangeCmdEventHandler) {
982        ALOGI("%s: Error ret:%d, disable event handling",
983            __FUNCTION__, ret);
984        gScanSetSignificantChangeCmdEventHandler->disableEventHandling();
985    }
986    delete gScanCommand;
987    return (wifi_error)ret;
988}
989
990/* Clear the GSCAN Significant AP change list. */
991wifi_error wifi_reset_significant_change_handler(wifi_request_id id,
992                                            wifi_interface_handle iface)
993{
994    int ret = 0;
995    GScanCommand *gScanCommand;
996    struct nlattr *nlData;
997    interface_info *ifaceInfo = getIfaceInfo(iface);
998    wifi_handle wifiHandle = getWifiHandle(iface);
999    hal_info *info = getHalInfo(wifiHandle);
1000    lowi_cb_table_t *lowiWifiHalApi = NULL;
1001    gscan_event_handlers* event_handlers;
1002    GScanCommandEventHandler *gScanSetSignificantChangeCmdEventHandler;
1003
1004    event_handlers = (gscan_event_handlers*)info->gscan_handlers;
1005    gScanSetSignificantChangeCmdEventHandler =
1006        event_handlers->gScanSetSignificantChangeCmdEventHandler;
1007
1008    if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
1009        ALOGE("%s: GSCAN is not supported by driver",
1010            __FUNCTION__);
1011        return WIFI_ERROR_NOT_SUPPORTED;
1012    }
1013
1014    /* Route request through LOWI if supported*/
1015    lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
1016    if (lowiWifiHalApi == NULL ||
1017        lowiWifiHalApi->reset_significant_change_handler == NULL) {
1018        ALOGV("%s: Sending cmd directly to host", __FUNCTION__);
1019    } else {
1020        ret = lowiWifiHalApi->reset_significant_change_handler(id, iface);
1021        ALOGV("%s: lowi reset_significant_change_handler "
1022            "returned: %d. Exit.", __FUNCTION__, ret);
1023        return (wifi_error)ret;
1024    }
1025
1026    if (gScanSetSignificantChangeCmdEventHandler == NULL ||
1027        (gScanSetSignificantChangeCmdEventHandler->isEventHandlingEnabled() ==
1028        false)) {
1029        ALOGE("wifi_reset_significant_change_handler: GSCAN significant_change"
1030            " isn't set. Nothing to do. Exit");
1031        return WIFI_ERROR_NOT_AVAILABLE;
1032    }
1033
1034    gScanCommand =
1035        new GScanCommand
1036                    (
1037                    wifiHandle,
1038                    id,
1039                    OUI_QCA,
1040                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SIGNIFICANT_CHANGE);
1041    if (gScanCommand == NULL) {
1042        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
1043        return WIFI_ERROR_UNKNOWN;
1044    }
1045
1046    /* Create the NL message. */
1047    ret = gScanCommand->create();
1048    if (ret < 0)
1049        goto cleanup;
1050
1051    /* Set the interface Id of the message. */
1052    ret = gScanCommand->set_iface_id(ifaceInfo->name);
1053    if (ret < 0)
1054        goto cleanup;
1055
1056    /* Add the vendor specific attributes for the NL command. */
1057    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1058    if (!nlData)
1059        goto cleanup;
1060
1061    ret = gScanCommand->put_u32(
1062                    QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
1063                    id);
1064    if (ret < 0)
1065        goto cleanup;
1066
1067    gScanCommand->attr_end(nlData);
1068
1069    ret = gScanCommand->requestResponse();
1070    if (ret != 0) {
1071        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
1072    }
1073
1074    /* Disable Event Handling. */
1075    if (gScanSetSignificantChangeCmdEventHandler) {
1076        gScanSetSignificantChangeCmdEventHandler->disableEventHandling();
1077    }
1078
1079cleanup:
1080    delete gScanCommand;
1081    return (wifi_error)ret;
1082}
1083
1084/* Get the GSCAN cached scan results. */
1085wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface,
1086                                            byte flush, int max,
1087                                            wifi_cached_scan_results *results,
1088                                            int *num)
1089{
1090    int requestId, ret = 0, retRequestRsp = 0;
1091    GScanCommand *gScanCommand;
1092    struct nlattr *nlData;
1093    lowi_cb_table_t *lowiWifiHalApi = NULL;
1094
1095    interface_info *ifaceInfo = getIfaceInfo(iface);
1096    wifi_handle wifiHandle = getWifiHandle(iface);
1097    hal_info *info = getHalInfo(wifiHandle);
1098
1099    if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
1100        ALOGE("%s: GSCAN is not supported by driver",
1101            __FUNCTION__);
1102        return WIFI_ERROR_NOT_SUPPORTED;
1103    }
1104
1105    /* Route GSCAN request through LOWI if supported */
1106    lowiWifiHalApi = getLowiCallbackTable(GSCAN_SUPPORTED);
1107    if (lowiWifiHalApi == NULL ||
1108        lowiWifiHalApi->get_cached_gscan_results == NULL) {
1109        ALOGV("%s: Sending cmd directly to host", __FUNCTION__);
1110    } else {
1111        ret = lowiWifiHalApi->get_cached_gscan_results(iface,
1112                                                       flush,
1113                                                       max,
1114                                                       results,
1115                                                       num);
1116        ALOGV("%s: lowi get_cached_gscan_results"
1117            "returned: %d. Exit.", __FUNCTION__, ret);
1118        return (wifi_error)ret;
1119    }
1120
1121    /* No request id from caller, so generate one and pass it on to the driver. */
1122    /* Generate it randomly */
1123    requestId = get_requestid();
1124
1125    if (results == NULL || num == NULL) {
1126        ALOGE("%s: NULL pointer provided. Exit.",
1127            __FUNCTION__);
1128        return WIFI_ERROR_INVALID_ARGS;
1129    }
1130
1131    gScanCommand = new GScanCommand(
1132                        wifiHandle,
1133                        requestId,
1134                        OUI_QCA,
1135                        QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS);
1136    if (gScanCommand == NULL) {
1137        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
1138        return WIFI_ERROR_UNKNOWN;
1139    }
1140
1141    ret = gScanCommand->allocRspParams(eGScanGetCachedResultsRspParams);
1142    if (ret != 0) {
1143        ALOGE("%s: Failed to allocate memory for response struct. Error:%d",
1144            __FUNCTION__, ret);
1145        goto cleanup;
1146    }
1147
1148    ret = gScanCommand->allocCachedResultsTemp(max, results);
1149    if (ret != 0) {
1150        ALOGE("%s: Failed to allocate memory for temp gscan cached list. "
1151            "Error:%d", __FUNCTION__, ret);
1152        goto cleanup;
1153    }
1154
1155    /* Clear the destination cached results list before copying results. */
1156    memset(results, 0, max * sizeof(wifi_cached_scan_results));
1157
1158    /* Create the NL message. */
1159    ret = gScanCommand->create();
1160    if (ret < 0)
1161        goto cleanup;
1162
1163    /* Set the interface Id of the message. */
1164    ret = gScanCommand->set_iface_id(ifaceInfo->name);
1165    if (ret < 0)
1166        goto cleanup;
1167
1168    /* Add the vendor specific attributes for the NL command. */
1169    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1170    if (!nlData)
1171        goto cleanup;
1172
1173    if (ret < 0)
1174        goto cleanup;
1175
1176    if (gScanCommand->put_u32(
1177         QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
1178            requestId) ||
1179        gScanCommand->put_u8(
1180         QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH,
1181            flush) ||
1182        gScanCommand->put_u32(
1183         QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX,
1184            max))
1185    {
1186        goto cleanup;
1187    }
1188
1189    ALOGV("%s: flush:%d max:%d", __FUNCTION__, flush, max);
1190    gScanCommand->attr_end(nlData);
1191
1192    retRequestRsp = gScanCommand->requestResponse();
1193    if (retRequestRsp != 0) {
1194        ALOGE("%s: requestResponse Error:%d",
1195            __FUNCTION__, retRequestRsp);
1196        if (retRequestRsp != -ETIMEDOUT) {
1197            /* Proceed to cleanup & return no results */
1198            goto cleanup;
1199        }
1200    }
1201
1202    /* No more data, copy the parsed results into the caller's results array */
1203    ret = gScanCommand->copyCachedScanResults(num, results);
1204    ALOGV("%s: max: %d, num:%d", __FUNCTION__, max, *num);
1205
1206    if (!ret) {
1207        /* If requestResponse returned a TIMEOUT */
1208        if (retRequestRsp == -ETIMEDOUT) {
1209            if (*num > 0) {
1210                /* Mark scan results as incomplete for the last scan_id */
1211                results[(*num)-1].flags = WIFI_SCAN_FLAG_INTERRUPTED;
1212                ALOGV("%s: Timeout happened. Mark scan results as incomplete "
1213                    "for scan_id:%d", __FUNCTION__, results[(*num)-1].scan_id);
1214                ret = WIFI_SUCCESS;
1215            } else
1216                ret = WIFI_ERROR_TIMED_OUT;
1217        }
1218    }
1219cleanup:
1220    gScanCommand->freeRspParams(eGScanGetCachedResultsRspParams);
1221    delete gScanCommand;
1222    return (wifi_error)ret;
1223}
1224
1225/* Random MAC OUI for PNO */
1226wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)
1227{
1228    int ret = 0;
1229    struct nlattr *nlData;
1230    WifiVendorCommand *vCommand = NULL;
1231    interface_info *iinfo = getIfaceInfo(handle);
1232    wifi_handle wifiHandle = getWifiHandle(handle);
1233
1234    vCommand = new WifiVendorCommand(wifiHandle, 0,
1235            OUI_QCA,
1236            QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI);
1237    if (vCommand == NULL) {
1238        ALOGE("%s: Error vCommand NULL", __FUNCTION__);
1239        return WIFI_ERROR_OUT_OF_MEMORY;
1240    }
1241
1242    /* create the message */
1243    ret = vCommand->create();
1244    if (ret < 0)
1245        goto cleanup;
1246
1247    ret = vCommand->set_iface_id(iinfo->name);
1248    if (ret < 0)
1249        goto cleanup;
1250
1251    /* Add the vendor specific attributes for the NL command. */
1252    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1253    if (!nlData)
1254        goto cleanup;
1255
1256    ALOGV("%s: MAC_OUI - %02x:%02x:%02x", __FUNCTION__,
1257          scan_oui[0], scan_oui[1], scan_oui[2]);
1258
1259    /* Add the fixed part of the mac_oui to the nl command */
1260    ret = vCommand->put_bytes(
1261            QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI,
1262            (char *)scan_oui,
1263            WIFI_SCANNING_MAC_OUI_LENGTH);
1264    if (ret < 0)
1265        goto cleanup;
1266
1267    vCommand->attr_end(nlData);
1268
1269    ret = vCommand->requestResponse();
1270    if (ret != 0) {
1271        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
1272        goto cleanup;
1273    }
1274
1275cleanup:
1276    delete vCommand;
1277    return (wifi_error)ret;
1278}
1279
1280
1281GScanCommand::GScanCommand(wifi_handle handle, int id, u32 vendor_id,
1282                                  u32 subcmd)
1283        : WifiVendorCommand(handle, id, vendor_id, subcmd)
1284{
1285    /* Initialize the member data variables here */
1286    mGetCachedResultsRspParams = NULL;
1287    mChannels = NULL;
1288    mMaxChannels = 0;
1289    mNumChannelsPtr = NULL;
1290
1291    mRequestId = id;
1292    memset(&mHandler, 0,sizeof(mHandler));
1293}
1294
1295GScanCommand::~GScanCommand()
1296{
1297    unregisterVendorHandler(mVendor_id, mSubcmd);
1298}
1299
1300
1301/* This function implements creation of Vendor command */
1302int GScanCommand::create() {
1303    int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
1304    if (ret < 0) {
1305        return ret;
1306    }
1307
1308    /* Insert the oui in the msg */
1309    ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
1310    if (ret < 0)
1311        goto out;
1312    /* Insert the subcmd in the msg */
1313    ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
1314    if (ret < 0)
1315        goto out;
1316
1317     ALOGV("%s: mVendor_id = %d, Subcmd = %d.",
1318        __FUNCTION__, mVendor_id, mSubcmd);
1319out:
1320    return ret;
1321}
1322
1323int GScanCommand::requestResponse()
1324{
1325    return WifiCommand::requestResponse(mMsg);
1326}
1327
1328int GScanCommand::handleResponse(WifiEvent &reply) {
1329    int i = 0;
1330    int ret = WIFI_SUCCESS;
1331    u32 val;
1332
1333    WifiVendorCommand::handleResponse(reply);
1334
1335    struct nlattr *tbVendor[
1336        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
1337    nla_parse(tbVendor, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
1338                (struct nlattr *)mVendorData,mDataLen, NULL);
1339
1340    switch(mSubcmd)
1341    {
1342        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS:
1343        {
1344            if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS]) {
1345                ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS"
1346                    " not found", __FUNCTION__);
1347                ret = WIFI_ERROR_INVALID_ARGS;
1348                break;
1349            }
1350            val = nla_get_u32(tbVendor[
1351                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS]);
1352
1353            val = val > (unsigned int)mMaxChannels ?
1354                    (unsigned int)mMaxChannels : val;
1355            *mNumChannelsPtr = val;
1356
1357            /* Extract the list of channels. */
1358            if (*mNumChannelsPtr > 0 ) {
1359                if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS]) {
1360                    ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS"
1361                        " not found", __FUNCTION__);
1362                    ret = WIFI_ERROR_INVALID_ARGS;
1363                    break;
1364                }
1365                nla_memcpy(mChannels,
1366                    tbVendor[
1367                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS],
1368                    sizeof(wifi_channel) * (*mNumChannelsPtr));
1369            }
1370            char buf[256];
1371            size_t len = 0;
1372            for (i = 0; i < *mNumChannelsPtr && len < sizeof(buf); i++) {
1373                 len +=  snprintf(buf + len, sizeof(buf) - len, "%u ",
1374                                  *(mChannels + i));
1375            }
1376            ALOGV("%s: Num Channels %d: List of valid channels are: %s",
1377                  __FUNCTION__, *mNumChannelsPtr, buf);
1378
1379        }
1380        break;
1381        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS:
1382        {
1383            wifi_request_id id;
1384            u32 numResults = 0;
1385            int firstScanIdInPatch = -1;
1386
1387            if (!tbVendor[
1388                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) {
1389                ALOGE("%s: GSCAN_RESULTS_REQUEST_ID not"
1390                    "found", __FUNCTION__);
1391                ret = WIFI_ERROR_INVALID_ARGS;
1392                break;
1393            }
1394            id = nla_get_u32(
1395                    tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
1396                    );
1397            /* If this is not for us, just ignore it. */
1398            if (id != mRequestId) {
1399                ALOGV("%s: Event has Req. ID:%d <> ours:%d",
1400                    __FUNCTION__, id, mRequestId);
1401                break;
1402            }
1403            if (!tbVendor[
1404                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) {
1405                ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not"
1406                    "found", __FUNCTION__);
1407                ret = WIFI_ERROR_INVALID_ARGS;
1408                break;
1409            }
1410            /* Read num of cached scan results in this data chunk. Note that
1411             * this value doesn't represent the number of unique gscan scan Ids
1412             * since the first scan id in this new chunk could be similar to
1413             * the last scan id in the previous chunk.
1414             */
1415            numResults = nla_get_u32(tbVendor[
1416                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]);
1417            ALOGV("%s: num Cached results in this fragment:%d",
1418                       __FUNCTION__, numResults);
1419
1420            if (!mGetCachedResultsRspParams) {
1421                ALOGE("%s: mGetCachedResultsRspParams is NULL, exit.",
1422                    __FUNCTION__);
1423                ret = WIFI_ERROR_INVALID_ARGS;
1424                break;
1425            }
1426
1427            /* To support fragmentation from firmware, monitor the
1428             * MORE_DATA flag and cache results until MORE_DATA = 0.
1429             */
1430            if (!tbVendor[
1431                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) {
1432                ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA "
1433                    "not found", __FUNCTION__);
1434                ret = WIFI_ERROR_INVALID_ARGS;
1435                break;
1436            } else {
1437                mGetCachedResultsRspParams->more_data = nla_get_u8(
1438                    tbVendor[
1439                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]);
1440            }
1441
1442            /* No data in this chunk so skip this chunk */
1443            if (numResults == 0) {
1444                return NL_SKIP;
1445            }
1446
1447            if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID]) {
1448                ALOGE("GSCAN_CACHED_RESULTS_SCAN_ID not found");
1449                ret = WIFI_ERROR_INVALID_ARGS;
1450                break;
1451            }
1452
1453            /* Get the first Scan-Id in this chuck of cached results. */
1454            firstScanIdInPatch = nla_get_u32(tbVendor[
1455                    QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID]);
1456
1457            ALOGV("More data: %d, firstScanIdInPatch: %d, lastProcessedScanId: %d",
1458                mGetCachedResultsRspParams->more_data, firstScanIdInPatch,
1459                mGetCachedResultsRspParams->lastProcessedScanId);
1460
1461            if (numResults) {
1462                if (firstScanIdInPatch !=
1463                    mGetCachedResultsRspParams->lastProcessedScanId) {
1464                    /* New result scan Id block, update the starting index. */
1465                    mGetCachedResultsRspParams->cachedResultsStartingIndex++;
1466                }
1467
1468                ret = gscan_get_cached_results(
1469                                    mGetCachedResultsRspParams->cached_results,
1470                                    tbVendor);
1471                /* If a parsing error occurred, exit and proceed for cleanup. */
1472                if (ret)
1473                    break;
1474            }
1475        }
1476        break;
1477        default:
1478            /* Error case should not happen print log */
1479            ALOGE("%s: Wrong GScan subcmd response received %d",
1480                __FUNCTION__, mSubcmd);
1481    }
1482
1483    /* A parsing error occurred, do the cleanup of gscan result lists. */
1484    if (ret) {
1485        switch(mSubcmd)
1486        {
1487            case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS:
1488            {
1489                ALOGE("%s: Parsing error, free CachedResultsRspParams",
1490                    __FUNCTION__);
1491                freeRspParams(eGScanGetCachedResultsRspParams);
1492            }
1493            break;
1494            default:
1495                ALOGE("%s: Wrong GScan subcmd received %d", __FUNCTION__, mSubcmd);
1496        }
1497    }
1498    return NL_SKIP;
1499}
1500
1501/* Called to parse and extract cached results. */
1502int GScanCommand:: gscan_get_cached_results(
1503                                      wifi_cached_scan_results *cached_results,
1504                                      struct nlattr **tb_vendor)
1505{
1506    u32 j = 0;
1507    struct nlattr *scanResultsInfo, *wifiScanResultsInfo;
1508    int rem = 0, remResults = 0;
1509    u32 len = 0, numScanResults = 0;
1510    u32 i = mGetCachedResultsRspParams->cachedResultsStartingIndex;
1511    ALOGV("%s: starting counter: %d", __FUNCTION__, i);
1512
1513    for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[
1514               QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST]),
1515               rem = nla_len(tb_vendor[
1516               QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST]);
1517           nla_ok(scanResultsInfo, rem) && i < mGetCachedResultsRspParams->max;
1518           scanResultsInfo = nla_next(scanResultsInfo, &(rem)))
1519       {
1520           struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
1521           nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
1522           (struct nlattr *) nla_data(scanResultsInfo),
1523                   nla_len(scanResultsInfo), NULL);
1524
1525           if (!
1526               tb2[
1527                   QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID
1528                   ])
1529           {
1530               ALOGE("%s: GSCAN_CACHED_RESULTS_SCAN_ID"
1531                   " not found", __FUNCTION__);
1532               return WIFI_ERROR_INVALID_ARGS;
1533           }
1534           cached_results[i].scan_id =
1535               nla_get_u32(
1536               tb2[
1537                   QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID
1538                   ]);
1539
1540           if (!
1541               tb2[
1542                   QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_FLAGS
1543                   ])
1544           {
1545               ALOGE("%s: GSCAN_CACHED_RESULTS_FLAGS "
1546                   "not found", __FUNCTION__);
1547               return WIFI_ERROR_INVALID_ARGS;
1548           }
1549           cached_results[i].flags =
1550               nla_get_u32(
1551               tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_FLAGS]);
1552
1553           if (!tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED])
1554           {
1555               ALOGI("%s: GSCAN_RESULTS_BUCKETS_SCANNED"
1556                   "not found", __FUNCTION__);
1557           } else {
1558               cached_results[i].buckets_scanned = nla_get_u32(
1559                       tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED]);
1560           }
1561
1562           if (!
1563               tb2[
1564                   QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
1565                   ])
1566           {
1567               ALOGE("%s: RESULTS_NUM_RESULTS_AVAILABLE "
1568                   "not found", __FUNCTION__);
1569               return WIFI_ERROR_INVALID_ARGS;
1570           }
1571           numScanResults =
1572               nla_get_u32(
1573               tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]);
1574
1575           if (mGetCachedResultsRspParams->lastProcessedScanId !=
1576                                        cached_results[i].scan_id) {
1577               j = 0; /* reset wifi_scan_result counter */
1578               cached_results[i].num_results = 0;
1579               ALOGV("parsing: *lastProcessedScanId [%d] !="
1580                     " cached_results[%d].scan_id:%d, j:%d "
1581                     "numScanResults: %d",
1582                     mGetCachedResultsRspParams->lastProcessedScanId, i,
1583                     cached_results[i].scan_id, j, numScanResults);
1584               mGetCachedResultsRspParams->lastProcessedScanId =
1585                   cached_results[i].scan_id;
1586               mGetCachedResultsRspParams->wifiScanResultsStartingIndex = 0;
1587               /* Increment the number of cached scan results received */
1588               mGetCachedResultsRspParams->num_cached_results++;
1589           } else {
1590               j = mGetCachedResultsRspParams->wifiScanResultsStartingIndex;
1591               ALOGV("parsing: *lastProcessedScanId [%d] == "
1592                     "cached_results[%d].scan_id:%d, j:%d "
1593                     "numScanResults:%d",
1594                     mGetCachedResultsRspParams->lastProcessedScanId, i,
1595                     cached_results[i].scan_id, j, numScanResults);
1596           }
1597
1598           ALOGV("%s: scan_id %d ", __FUNCTION__,
1599            cached_results[i].scan_id);
1600           ALOGV("%s: flags  %u ", __FUNCTION__,
1601            cached_results[i].flags);
1602
1603           for (wifiScanResultsInfo = (struct nlattr *) nla_data(tb2[
1604                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]),
1605                remResults = nla_len(tb2[
1606                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]);
1607                nla_ok(wifiScanResultsInfo, remResults);
1608                wifiScanResultsInfo = nla_next(wifiScanResultsInfo, &(remResults)))
1609           {
1610                struct nlattr *tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
1611                nla_parse(tb3, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
1612                        (struct nlattr *) nla_data(wifiScanResultsInfo),
1613                        nla_len(wifiScanResultsInfo), NULL);
1614                if (j < MAX_AP_CACHE_PER_SCAN) {
1615                    if (!
1616                        tb3[
1617                           QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
1618                           ])
1619                    {
1620                        ALOGE("%s: "
1621                            "RESULTS_SCAN_RESULT_TIME_STAMP not found",
1622                            __FUNCTION__);
1623                        return WIFI_ERROR_INVALID_ARGS;
1624                    }
1625                    cached_results[i].results[j].ts =
1626                        nla_get_u64(
1627                        tb3[
1628                            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
1629                            ]);
1630                    if (!
1631                        tb3[
1632                            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID
1633                            ])
1634                    {
1635                        ALOGE("%s: "
1636                            "RESULTS_SCAN_RESULT_SSID not found",
1637                            __FUNCTION__);
1638                        return WIFI_ERROR_INVALID_ARGS;
1639                    }
1640                    len = nla_len(tb3[
1641                            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]);
1642                    len =
1643                        sizeof(cached_results[i].results[j].ssid) <= len ?
1644                        sizeof(cached_results[i].results[j].ssid) : len;
1645                    memcpy((void *)&cached_results[i].results[j].ssid,
1646                        nla_data(
1647                        tb3[
1648                        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]),
1649                        len);
1650                    if (!
1651                        tb3[
1652                            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID
1653                            ])
1654                    {
1655                        ALOGE("%s: "
1656                            "RESULTS_SCAN_RESULT_BSSID not found",
1657                            __FUNCTION__);
1658                        return WIFI_ERROR_INVALID_ARGS;
1659                    }
1660                    len = nla_len(
1661                        tb3[
1662                        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]);
1663                    len =
1664                        sizeof(cached_results[i].results[j].bssid) <= len ?
1665                        sizeof(cached_results[i].results[j].bssid) : len;
1666                    memcpy(&cached_results[i].results[j].bssid,
1667                        nla_data(
1668                        tb3[
1669                        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]),
1670                        len);
1671                    if (!
1672                        tb3[
1673                            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL
1674                            ])
1675                    {
1676                        ALOGE("%s: "
1677                            "RESULTS_SCAN_RESULT_CHANNEL not found",
1678                            __FUNCTION__);
1679                        return WIFI_ERROR_INVALID_ARGS;
1680                    }
1681                    cached_results[i].results[j].channel =
1682                        nla_get_u32(
1683                        tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]);
1684                    if (!
1685                        tb3[
1686                            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI
1687                            ])
1688                    {
1689                        ALOGE("%s: "
1690                            "RESULTS_SCAN_RESULT_RSSI not found",
1691                            __FUNCTION__);
1692                        return WIFI_ERROR_INVALID_ARGS;
1693                    }
1694                    cached_results[i].results[j].rssi =
1695                        get_s32(
1696                        tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]);
1697                    if (!
1698                        tb3[
1699                            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT
1700                            ])
1701                    {
1702                        ALOGE("%s: "
1703                            "RESULTS_SCAN_RESULT_RTT not found",
1704                            __FUNCTION__);
1705                        return WIFI_ERROR_INVALID_ARGS;
1706                    }
1707                    cached_results[i].results[j].rtt =
1708                        nla_get_u32(
1709                        tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]);
1710                    if (!
1711                        tb3[
1712                            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD
1713                        ])
1714                    {
1715                        ALOGE("%s: "
1716                            "RESULTS_SCAN_RESULT_RTT_SD not found",
1717                            __FUNCTION__);
1718                        return WIFI_ERROR_INVALID_ARGS;
1719                    }
1720                    cached_results[i].results[j].rtt_sd =
1721                        nla_get_u32(
1722                        tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]);
1723#ifdef QC_HAL_DEBUG
1724                    /* Enable these prints for debugging if needed. */
1725                    ALOGD("%s: ts  %" PRId64, __FUNCTION__,
1726                        cached_results[i].results[j].ts);
1727                    ALOGD("%s: SSID  %s ", __FUNCTION__,
1728                        cached_results[i].results[j].ssid);
1729                    ALOGD("%s: BSSID: %02x:%02x:%02x:%02x:%02x:%02x \n",
1730                        __FUNCTION__, cached_results[i].results[j].bssid[0],
1731                        cached_results[i].results[j].bssid[1],
1732                        cached_results[i].results[j].bssid[2],
1733                        cached_results[i].results[j].bssid[3],
1734                        cached_results[i].results[j].bssid[4],
1735                        cached_results[i].results[j].bssid[5]);
1736                    ALOGD("%s: channel %d ", __FUNCTION__,
1737                        cached_results[i].results[j].channel);
1738                    ALOGD("%s: rssi  %d ", __FUNCTION__,
1739                        cached_results[i].results[j].rssi);
1740                    ALOGD("%s: rtt  %" PRId64, __FUNCTION__,
1741                        cached_results[i].results[j].rtt);
1742                    ALOGD("%s: rtt_sd  %" PRId64, __FUNCTION__,
1743                        cached_results[i].results[j].rtt_sd);
1744#endif
1745                    /* Increment loop index for next record */
1746                    j++;
1747                    /* For this scan id, update the wifiScanResultsStartingIndex
1748                    * and number of cached results parsed so far.
1749                    */
1750                    mGetCachedResultsRspParams->wifiScanResultsStartingIndex = j;
1751                    cached_results[i].num_results++;
1752                } else {
1753                    /* We already parsed and stored up to max wifi_scan_results
1754                     * specified by the caller. Now, continue to loop over NL
1755                     * entries in order to properly update NL parsing pointer
1756                     * so it points to the next scan_id results.
1757                     */
1758                    ALOGD("%s: loop index:%d > max num"
1759                        " of wifi_scan_results:%d for gscan cached results"
1760                        " bucket:%d. Dummy loop", __FUNCTION__,
1761                        j, MAX_AP_CACHE_PER_SCAN, i);
1762                }
1763           }
1764           ALOGV("%s: cached_results[%d].num_results: %d ", __FUNCTION__,
1765            i, cached_results[i].num_results);
1766           /* Increment loop index for next cached scan result record */
1767           i++;
1768       }
1769       /* Increment starting index of filling cached results received */
1770       if (mGetCachedResultsRspParams->num_cached_results)
1771           mGetCachedResultsRspParams->cachedResultsStartingIndex =
1772               mGetCachedResultsRspParams->num_cached_results - 1;
1773    return WIFI_SUCCESS;
1774}
1775
1776/* Set the GSCAN BSSID Hotlist. */
1777wifi_error wifi_set_epno_list(wifi_request_id id,
1778                                wifi_interface_handle iface,
1779                                const wifi_epno_params *epno_params,
1780                                wifi_epno_handler handler)
1781{
1782    int i, ret = 0, num_networks;
1783    GScanCommand *gScanCommand;
1784    struct nlattr *nlData, *nlPnoParamList;
1785    interface_info *ifaceInfo = getIfaceInfo(iface);
1786    wifi_handle wifiHandle = getWifiHandle(iface);
1787    hal_info *info = getHalInfo(wifiHandle);
1788    gscan_event_handlers* event_handlers;
1789    GScanCommandEventHandler *gScanSetPnoListCmdEventHandler;
1790
1791    event_handlers = (gscan_event_handlers*)info->gscan_handlers;
1792    gScanSetPnoListCmdEventHandler =
1793        event_handlers->gScanSetPnoListCmdEventHandler;
1794
1795    if (!(info->supported_feature_set & WIFI_FEATURE_HAL_EPNO)) {
1796        ALOGE("%s: Enhanced PNO is not supported by the driver",
1797            __FUNCTION__);
1798        return WIFI_ERROR_NOT_SUPPORTED;
1799    }
1800
1801    /* Wi-Fi HAL doesn't need to check if a similar request to set ePNO
1802     * list was made earlier. If wifi_set_epno_list() is called while
1803     * another one is running, the request will be sent down to driver and
1804     * firmware. If the new request is successfully honored, then Wi-Fi HAL
1805     * will use the new request id for the gScanSetPnoListCmdEventHandler
1806     * object.
1807     */
1808
1809    gScanCommand =
1810        new GScanCommand(
1811                    wifiHandle,
1812                    id,
1813                    OUI_QCA,
1814                    QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST);
1815    if (gScanCommand == NULL) {
1816        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
1817        return WIFI_ERROR_UNKNOWN;
1818    }
1819
1820    /* Create the NL message. */
1821    ret = gScanCommand->create();
1822    if (ret < 0) {
1823        ALOGE("%s: Failed to create the NL msg. Error:%d", __FUNCTION__, ret);
1824        goto cleanup;
1825    }
1826
1827    /* Set the interface Id of the message. */
1828    ret = gScanCommand->set_iface_id(ifaceInfo->name);
1829    if (ret < 0) {
1830        ALOGE("%s: Failed to set iface id. Error:%d", __FUNCTION__, ret);
1831        goto cleanup;
1832    }
1833
1834    /* Add the vendor specific attributes for the NL command. */
1835    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1836    if (!nlData) {
1837        ALOGE("%s: Failed to add attribute NL80211_ATTR_VENDOR_DATA. Error:%d",
1838            __FUNCTION__, ret);
1839        goto cleanup;
1840    }
1841
1842    num_networks = (unsigned int)epno_params->num_networks > MAX_EPNO_NETWORKS ?
1843                   MAX_EPNO_NETWORKS : epno_params->num_networks;
1844    if (gScanCommand->put_u32(
1845            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
1846            id) ||
1847        gScanCommand->put_u32(
1848            QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI,
1849            epno_params->min5GHz_rssi) ||
1850        gScanCommand->put_u32(
1851            QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI,
1852            epno_params->min24GHz_rssi) ||
1853        gScanCommand->put_u32(
1854            QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX,
1855            epno_params->initial_score_max) ||
1856        gScanCommand->put_u32(
1857            QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS,
1858            epno_params->current_connection_bonus) ||
1859        gScanCommand->put_u32(
1860            QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS,
1861            epno_params->same_network_bonus) ||
1862        gScanCommand->put_u32(
1863            QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS,
1864            epno_params->secure_bonus) ||
1865        gScanCommand->put_u32(
1866            QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS,
1867            epno_params->band5GHz_bonus) ||
1868        gScanCommand->put_u32(
1869            QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS,
1870            num_networks))
1871    {
1872        ALOGE("%s: Failed to add vendor atributes. Error:%d", __FUNCTION__, ret);
1873        goto cleanup;
1874    }
1875
1876    /* Add the vendor specific attributes for the NL command. */
1877    nlPnoParamList =
1878        gScanCommand->attr_start(
1879                QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST);
1880    if (!nlPnoParamList) {
1881        ALOGE("%s: Failed to add attr. PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST. "
1882            "Error:%d", __FUNCTION__, ret);
1883        goto cleanup;
1884    }
1885
1886    /* Add nested NL attributes for ePno List. */
1887    for (i = 0; i < num_networks; i++) {
1888        wifi_epno_network pnoNetwork = epno_params->networks[i];
1889        struct nlattr *nlPnoNetwork = gScanCommand->attr_start(i);
1890        if (!nlPnoNetwork) {
1891            ALOGE("%s: Failed attr_start for nlPnoNetwork. Error:%d",
1892                __FUNCTION__, ret);
1893            goto cleanup;
1894        }
1895        if (gScanCommand->put_string(
1896                QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID,
1897                pnoNetwork.ssid) ||
1898            gScanCommand->put_u8(
1899                QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS,
1900                pnoNetwork.flags) ||
1901            gScanCommand->put_u8(
1902                QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT,
1903                pnoNetwork.auth_bit_field))
1904        {
1905            ALOGE("%s: Failed to add PNO_SET_LIST_PARAM_EPNO_NETWORK_*. "
1906                "Error:%d", __FUNCTION__, ret);
1907            goto cleanup;
1908        }
1909        gScanCommand->attr_end(nlPnoNetwork);
1910    }
1911
1912    gScanCommand->attr_end(nlPnoParamList);
1913
1914    gScanCommand->attr_end(nlData);
1915
1916    GScanCallbackHandler callbackHandler;
1917    memset(&callbackHandler, 0, sizeof(callbackHandler));
1918    callbackHandler.on_pno_network_found = handler.on_network_found;
1919
1920    /* Create an object of the event handler class to take care of the
1921      * asychronous events on the north-bound.
1922      */
1923    if (gScanSetPnoListCmdEventHandler == NULL) {
1924        gScanSetPnoListCmdEventHandler = new GScanCommandEventHandler(
1925                            wifiHandle,
1926                            id,
1927                            OUI_QCA,
1928                            QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST,
1929                            callbackHandler);
1930        if (gScanSetPnoListCmdEventHandler == NULL) {
1931            ALOGE("%s: Error instantiating "
1932                "gScanSetPnoListCmdEventHandler.", __FUNCTION__);
1933            ret = WIFI_ERROR_UNKNOWN;
1934            goto cleanup;
1935        }
1936        event_handlers->gScanSetPnoListCmdEventHandler =
1937            gScanSetPnoListCmdEventHandler;
1938    } else {
1939        gScanSetPnoListCmdEventHandler->setCallbackHandler(callbackHandler);
1940    }
1941
1942    ret = gScanCommand->requestResponse();
1943    if (ret != 0) {
1944        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
1945        goto cleanup;
1946    }
1947
1948    if (gScanSetPnoListCmdEventHandler != NULL) {
1949        gScanSetPnoListCmdEventHandler->set_request_id(id);
1950        gScanSetPnoListCmdEventHandler->enableEventHandling();
1951    }
1952
1953cleanup:
1954    delete gScanCommand;
1955    /* Disable Event Handling if ret != 0 */
1956    if (ret && gScanSetPnoListCmdEventHandler) {
1957        ALOGI("%s: Error ret:%d, disable event handling",
1958            __FUNCTION__, ret);
1959        gScanSetPnoListCmdEventHandler->disableEventHandling();
1960    }
1961    return (wifi_error)ret;
1962}
1963
1964/* Reset the ePNO list - no ePNO networks should be matched after this */
1965wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface)
1966{
1967    int ret = 0;
1968    GScanCommand *gScanCommand;
1969    struct nlattr *nlData;
1970    interface_info *ifaceInfo = getIfaceInfo(iface);
1971    wifi_handle wifiHandle = getWifiHandle(iface);
1972    hal_info *info = getHalInfo(wifiHandle);
1973
1974    if (!(info->supported_feature_set & WIFI_FEATURE_HAL_EPNO)) {
1975        ALOGE("%s: Enhanced PNO is not supported by the driver",
1976            __FUNCTION__);
1977        return WIFI_ERROR_NOT_SUPPORTED;
1978    }
1979
1980    gScanCommand = new GScanCommand(wifiHandle,
1981                                    id,
1982                                    OUI_QCA,
1983                                    QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST);
1984    if (gScanCommand == NULL) {
1985        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
1986        return WIFI_ERROR_UNKNOWN;
1987    }
1988
1989    /* Create the NL message. */
1990    ret = gScanCommand->create();
1991    if (ret < 0) {
1992        ALOGE("%s: Failed to create the NL msg. Error:%d", __FUNCTION__, ret);
1993        goto cleanup;
1994    }
1995
1996    /* Set the interface Id of the message. */
1997    ret = gScanCommand->set_iface_id(ifaceInfo->name);
1998    if (ret < 0) {
1999        ALOGE("%s: Failed to set iface id. Error:%d", __FUNCTION__, ret);
2000        goto cleanup;
2001    }
2002
2003    /* Add the vendor specific attributes for the NL command. */
2004    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2005    if (!nlData) {
2006        ALOGE("%s: Failed to add attribute NL80211_ATTR_VENDOR_DATA. Error:%d",
2007            __FUNCTION__, ret);
2008        goto cleanup;
2009    }
2010
2011    if (gScanCommand->put_u32(
2012            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
2013            id) ||
2014        gScanCommand->put_u32(
2015            QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS,
2016            EPNO_NO_NETWORKS))
2017    {
2018        ALOGE("%s: Failed to add vendor atributes Error:%d", __FUNCTION__, ret);
2019        goto cleanup;
2020    }
2021
2022    gScanCommand->attr_end(nlData);
2023
2024    ret = gScanCommand->requestResponse();
2025    if (ret != 0) {
2026        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
2027    }
2028
2029cleanup:
2030    delete gScanCommand;
2031    return (wifi_error)ret;
2032}
2033
2034/* Set the ePNO Passpoint List. */
2035wifi_error wifi_set_passpoint_list(wifi_request_id id,
2036                                   wifi_interface_handle iface, int num,
2037                                   wifi_passpoint_network *networks,
2038                                   wifi_passpoint_event_handler handler)
2039{
2040    int i, ret = 0;
2041    GScanCommand *gScanCommand;
2042    struct nlattr *nlData, *nlPasspointNetworksParamList;
2043    interface_info *ifaceInfo = getIfaceInfo(iface);
2044    wifi_handle wifiHandle = getWifiHandle(iface);
2045    hal_info *info = getHalInfo(wifiHandle);
2046    gscan_event_handlers* event_handlers;
2047    GScanCommandEventHandler *gScanPnoSetPasspointListCmdEventHandler;
2048
2049    event_handlers = (gscan_event_handlers*)info->gscan_handlers;
2050    gScanPnoSetPasspointListCmdEventHandler =
2051        event_handlers->gScanPnoSetPasspointListCmdEventHandler;
2052
2053    if (!(info->supported_feature_set & WIFI_FEATURE_HAL_EPNO)) {
2054        ALOGE("%s: Enhanced PNO is not supported by the driver",
2055            __FUNCTION__);
2056        return WIFI_ERROR_NOT_SUPPORTED;
2057    }
2058
2059    /* Wi-Fi HAL doesn't need to check if a similar request to set ePNO
2060     * passpoint list was made earlier. If wifi_set_passpoint_list() is called
2061     * while another one is running, the request will be sent down to driver and
2062     * firmware. If the new request is successfully honored, then Wi-Fi HAL
2063     * will use the new request id for the
2064     * gScanPnoSetPasspointListCmdEventHandler object.
2065     */
2066    gScanCommand =
2067        new GScanCommand(
2068                    wifiHandle,
2069                    id,
2070                    OUI_QCA,
2071                    QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST);
2072    if (gScanCommand == NULL) {
2073        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
2074        return WIFI_ERROR_UNKNOWN;
2075    }
2076
2077    /* Create the NL message. */
2078    ret = gScanCommand->create();
2079    if (ret < 0) {
2080        ALOGE("%s: Failed to create the NL msg. Error:%d", __FUNCTION__, ret);
2081        goto cleanup;
2082    }
2083
2084    /* Set the interface Id of the message. */
2085    ret = gScanCommand->set_iface_id(ifaceInfo->name);
2086    if (ret < 0) {
2087        ALOGE("%s: Failed to set iface id. Error:%d", __FUNCTION__, ret);
2088        goto cleanup;
2089    }
2090
2091    /* Add the vendor specific attributes for the NL command. */
2092    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2093    if (!nlData) {
2094        ALOGE("%s: Failed to add attribute NL80211_ATTR_VENDOR_DATA. Error:%d",
2095            __FUNCTION__, ret);
2096        goto cleanup;
2097    }
2098
2099    if (gScanCommand->put_u32(
2100            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
2101            id) ||
2102        gScanCommand->put_u32(
2103            QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM,
2104            num))
2105    {
2106        ALOGE("%s: Failed to add vendor atributes. Error:%d", __FUNCTION__, ret);
2107        goto cleanup;
2108    }
2109
2110    /* Add the vendor specific attributes for the NL command. */
2111    nlPasspointNetworksParamList =
2112        gScanCommand->attr_start(
2113            QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY);
2114    if (!nlPasspointNetworksParamList) {
2115        ALOGE("%s: Failed attr_start for PASSPOINT_LIST_PARAM_NETWORK_ARRAY. "
2116            "Error:%d", __FUNCTION__, ret);
2117        goto cleanup;
2118    }
2119
2120    /* Add nested NL attributes for Passpoint List param. */
2121    for (i = 0; i < num; i++) {
2122        wifi_passpoint_network passpointNetwork = networks[i];
2123        struct nlattr *nlPasspointNetworkParam = gScanCommand->attr_start(i);
2124        if (!nlPasspointNetworkParam) {
2125            ALOGE("%s: Failed attr_start for nlPasspointNetworkParam. "
2126                "Error:%d", __FUNCTION__, ret);
2127            goto cleanup;
2128        }
2129        if (gScanCommand->put_u32(
2130                QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID,
2131                passpointNetwork.id) ||
2132            gScanCommand->put_string(
2133                QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM,
2134                passpointNetwork.realm) ||
2135            gScanCommand->put_bytes(
2136         QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID,
2137                (char*)passpointNetwork.roamingConsortiumIds,
2138                16 * sizeof(int64_t)) ||
2139            gScanCommand->put_bytes(
2140            QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN,
2141                (char*)passpointNetwork.plmn, 3 * sizeof(u8)))
2142        {
2143            ALOGE("%s: Failed to add PNO_PASSPOINT_NETWORK_PARAM_ROAM_* attr. "
2144                "Error:%d", __FUNCTION__, ret);
2145            goto cleanup;
2146        }
2147        gScanCommand->attr_end(nlPasspointNetworkParam);
2148    }
2149
2150    gScanCommand->attr_end(nlPasspointNetworksParamList);
2151
2152    gScanCommand->attr_end(nlData);
2153
2154    GScanCallbackHandler callbackHandler;
2155    memset(&callbackHandler, 0, sizeof(callbackHandler));
2156    callbackHandler.on_passpoint_network_found =
2157                        handler.on_passpoint_network_found;
2158
2159    /* Create an object of the event handler class to take care of the
2160      * asychronous events on the north-bound.
2161      */
2162    if (gScanPnoSetPasspointListCmdEventHandler == NULL) {
2163        gScanPnoSetPasspointListCmdEventHandler = new GScanCommandEventHandler(
2164                        wifiHandle,
2165                        id,
2166                        OUI_QCA,
2167                        QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST,
2168                        callbackHandler);
2169        if (gScanPnoSetPasspointListCmdEventHandler == NULL) {
2170            ALOGE("%s: Error instantiating "
2171                "gScanPnoSetPasspointListCmdEventHandler.", __FUNCTION__);
2172            ret = WIFI_ERROR_UNKNOWN;
2173            goto cleanup;
2174        }
2175        event_handlers->gScanPnoSetPasspointListCmdEventHandler =
2176            gScanPnoSetPasspointListCmdEventHandler;
2177    } else {
2178        gScanPnoSetPasspointListCmdEventHandler->setCallbackHandler(callbackHandler);
2179    }
2180
2181    ret = gScanCommand->requestResponse();
2182    if (ret != 0) {
2183        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
2184        goto cleanup;
2185    }
2186
2187    if (gScanPnoSetPasspointListCmdEventHandler != NULL) {
2188        gScanPnoSetPasspointListCmdEventHandler->set_request_id(id);
2189        gScanPnoSetPasspointListCmdEventHandler->enableEventHandling();
2190    }
2191
2192cleanup:
2193    delete gScanCommand;
2194    /* Disable Event Handling if ret != 0 */
2195    if (ret && gScanPnoSetPasspointListCmdEventHandler) {
2196        ALOGI("%s: Error ret:%d, disable event handling",
2197            __FUNCTION__, ret);
2198        gScanPnoSetPasspointListCmdEventHandler->disableEventHandling();
2199    }
2200    return (wifi_error)ret;
2201}
2202
2203wifi_error wifi_reset_passpoint_list(wifi_request_id id,
2204                            wifi_interface_handle iface)
2205{
2206    int ret = 0;
2207    GScanCommand *gScanCommand;
2208    struct nlattr *nlData;
2209    interface_info *ifaceInfo = getIfaceInfo(iface);
2210    wifi_handle wifiHandle = getWifiHandle(iface);
2211    hal_info *info = getHalInfo(wifiHandle);
2212    gscan_event_handlers* event_handlers;
2213    GScanCommandEventHandler *gScanPnoSetPasspointListCmdEventHandler;
2214
2215    event_handlers = (gscan_event_handlers*)info->gscan_handlers;
2216    gScanPnoSetPasspointListCmdEventHandler =
2217        event_handlers->gScanPnoSetPasspointListCmdEventHandler;
2218
2219    if (!(info->supported_feature_set & WIFI_FEATURE_HAL_EPNO)) {
2220        ALOGE("%s: Enhanced PNO is not supported by the driver",
2221            __FUNCTION__);
2222        return WIFI_ERROR_NOT_SUPPORTED;
2223    }
2224
2225    if (gScanPnoSetPasspointListCmdEventHandler == NULL ||
2226        (gScanPnoSetPasspointListCmdEventHandler->isEventHandlingEnabled() ==
2227         false)) {
2228        ALOGE("wifi_reset_passpoint_list: ePNO passpoint_list isn't set. "
2229            "Nothing to do. Exit.");
2230        return WIFI_ERROR_NOT_AVAILABLE;
2231    }
2232
2233    gScanCommand = new GScanCommand(
2234                    wifiHandle,
2235                    id,
2236                    OUI_QCA,
2237                    QCA_NL80211_VENDOR_SUBCMD_PNO_RESET_PASSPOINT_LIST);
2238
2239    if (gScanCommand == NULL) {
2240        ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
2241        return WIFI_ERROR_UNKNOWN;
2242    }
2243
2244    /* Create the NL message. */
2245    ret = gScanCommand->create();
2246    if (ret < 0) {
2247        ALOGE("%s: Failed to create the NL msg. Error:%d", __FUNCTION__, ret);
2248        goto cleanup;
2249    }
2250
2251    /* Set the interface Id of the message. */
2252    ret = gScanCommand->set_iface_id(ifaceInfo->name);
2253    if (ret < 0) {
2254        ALOGE("%s: Failed to set iface id. Error:%d", __FUNCTION__, ret);
2255        goto cleanup;
2256    }
2257
2258    /* Add the vendor specific attributes for the NL command. */
2259    nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2260    if (!nlData) {
2261        ALOGE("%s: Failed to add attribute NL80211_ATTR_VENDOR_DATA. Error:%d",
2262            __FUNCTION__, ret);
2263        goto cleanup;
2264    }
2265
2266    ret = gScanCommand->put_u32(
2267            QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID, id);
2268    if (ret < 0) {
2269        ALOGE("%s: Failed to add vendor data attributes. Error:%d",
2270            __FUNCTION__, ret);
2271        goto cleanup;
2272    }
2273
2274    gScanCommand->attr_end(nlData);
2275
2276    ret = gScanCommand->requestResponse();
2277    if (ret != 0) {
2278        ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
2279    }
2280
2281    /* Disable Event Handling. */
2282    if (gScanPnoSetPasspointListCmdEventHandler) {
2283        gScanPnoSetPasspointListCmdEventHandler->disableEventHandling();
2284    }
2285
2286cleanup:
2287    delete gScanCommand;
2288    return (wifi_error)ret;
2289}
2290
2291int GScanCommand::allocCachedResultsTemp(int max,
2292                                     wifi_cached_scan_results *cached_results)
2293{
2294    /* Alloc memory for "max" number of cached results. */
2295    mGetCachedResultsRspParams->cached_results =
2296        (wifi_cached_scan_results*)
2297        malloc(max * sizeof(wifi_cached_scan_results));
2298    if (!mGetCachedResultsRspParams->cached_results) {
2299        ALOGE("%s: Failed to allocate memory for "
2300              "mGetCachedResultsRspParams->cached_results.",
2301              __FUNCTION__);
2302        return WIFI_ERROR_OUT_OF_MEMORY;
2303    }
2304    memset(mGetCachedResultsRspParams->cached_results, 0,
2305           max * sizeof(wifi_cached_scan_results));
2306
2307    mGetCachedResultsRspParams->max = max;
2308
2309    return WIFI_SUCCESS;
2310}
2311
2312/*
2313 * Allocates memory for the subCmd response struct and initializes status = -1
2314 */
2315int GScanCommand::allocRspParams(eGScanRspRarams cmd)
2316{
2317    int ret = 0;
2318    switch(cmd)
2319    {
2320        case eGScanGetCachedResultsRspParams:
2321            mGetCachedResultsRspParams = (GScanGetCachedResultsRspParams *)
2322                malloc(sizeof(GScanGetCachedResultsRspParams));
2323            if (!mGetCachedResultsRspParams)
2324                ret = -1;
2325            else {
2326                mGetCachedResultsRspParams->num_cached_results = 0;
2327                mGetCachedResultsRspParams->more_data = false;
2328                mGetCachedResultsRspParams->cachedResultsStartingIndex = -1;
2329                mGetCachedResultsRspParams->lastProcessedScanId = -1;
2330                mGetCachedResultsRspParams->wifiScanResultsStartingIndex = -1;
2331                mGetCachedResultsRspParams->max = 0;
2332                mGetCachedResultsRspParams->cached_results = NULL;
2333            }
2334        break;
2335        default:
2336            ALOGD("%s: Wrong request for alloc.", __FUNCTION__);
2337            ret = -1;
2338    }
2339    return ret;
2340}
2341
2342void GScanCommand::freeRspParams(eGScanRspRarams cmd)
2343{
2344    switch(cmd)
2345    {
2346        case eGScanGetCachedResultsRspParams:
2347            if (mGetCachedResultsRspParams) {
2348                if (mGetCachedResultsRspParams->cached_results) {
2349                    free(mGetCachedResultsRspParams->cached_results);
2350                    mGetCachedResultsRspParams->cached_results = NULL;
2351                }
2352                free(mGetCachedResultsRspParams);
2353                mGetCachedResultsRspParams = NULL;
2354            }
2355        break;
2356        default:
2357            ALOGD("%s: Wrong request for free.", __FUNCTION__);
2358    }
2359}
2360
2361wifi_error GScanCommand::copyCachedScanResults(
2362                                      int *numResults,
2363                                      wifi_cached_scan_results *cached_results)
2364{
2365    wifi_error ret = WIFI_SUCCESS;
2366    int i;
2367    wifi_cached_scan_results *cachedResultRsp;
2368
2369    if (mGetCachedResultsRspParams && cached_results)
2370    {
2371        /* Populate the number of parsed cached results. */
2372        *numResults = mGetCachedResultsRspParams->num_cached_results;
2373
2374        for (i = 0; i < *numResults; i++) {
2375            cachedResultRsp = &mGetCachedResultsRspParams->cached_results[i];
2376            cached_results[i].scan_id = cachedResultRsp->scan_id;
2377            cached_results[i].flags = cachedResultRsp->flags;
2378            cached_results[i].num_results = cachedResultRsp->num_results;
2379            cached_results[i].buckets_scanned = cachedResultRsp->buckets_scanned;
2380
2381            if (!cached_results[i].num_results) {
2382                ALOGI("Error: cached_results[%d].num_results=0", i);
2383                continue;
2384            }
2385
2386            ALOGV("copyCachedScanResults: "
2387                "cached_results[%d].num_results : %d",
2388                i, cached_results[i].num_results);
2389
2390            memcpy(cached_results[i].results,
2391                cachedResultRsp->results,
2392                cached_results[i].num_results * sizeof(wifi_scan_result));
2393        }
2394    } else {
2395        ALOGE("%s: mGetCachedResultsRspParams is NULL", __FUNCTION__);
2396        *numResults = 0;
2397        ret = WIFI_ERROR_INVALID_ARGS;
2398    }
2399    return ret;
2400}
2401
2402void GScanCommand::setMaxChannels(int max_channels) {
2403    mMaxChannels = max_channels;
2404}
2405
2406void GScanCommand::setChannels(int *channels) {
2407    mChannels = channels;
2408}
2409
2410void GScanCommand::setNumChannelsPtr(int *num_channels) {
2411    mNumChannelsPtr = num_channels;
2412}
2413