/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG  "WifiHAL"

#include <utils/Log.h>
#include "gscan_event_handler.h"
#include "vendor_definitions.h"

/* This function implements creation of Vendor command event handler. */
int GScanCommandEventHandler::create() {
    int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
    if (ret < 0) {
        return ret;
    }

    /* Insert the oui in the msg */
    ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
    if (ret < 0)
        goto out;

    /* Insert the subcmd in the msg */
    ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
    if (ret < 0)
        goto out;
out:
    return ret;
}

int GScanCommandEventHandler::get_request_id()
{
    return mRequestId;
}

void GScanCommandEventHandler::set_request_id(int request_id)
{
    mRequestId = request_id;
}

void GScanCommandEventHandler::enableEventHandling()
{
    mEventHandlingEnabled = true;
}

void GScanCommandEventHandler::disableEventHandling()
{
    mEventHandlingEnabled = false;
}

bool GScanCommandEventHandler::isEventHandlingEnabled()
{
    return mEventHandlingEnabled;
}

void GScanCommandEventHandler::setCallbackHandler(GScanCallbackHandler handler)
{
    mHandler = handler;
}

GScanCommandEventHandler::GScanCommandEventHandler(wifi_handle handle, int id,
                                                u32 vendor_id,
                                                u32 subcmd,
                                                GScanCallbackHandler handler)
        : WifiVendorCommand(handle, id, vendor_id, subcmd)
{
    int ret = 0;
    mRequestId = id;
    mHandler = handler;
    mSubCommandId = subcmd;
    mHotlistApFoundResults = NULL;
    mHotlistApFoundNumResults = 0;
    mHotlistApFoundMoreData = false;
    mHotlistApLostResults = NULL;
    mHotlistApLostNumResults = 0;
    mHotlistApLostMoreData = false;
    mSignificantChangeResults = NULL;
    mSignificantChangeNumResults = 0;
    mSignificantChangeMoreData = false;
    mHotlistSsidFoundNumResults = 0;
    mHotlistSsidFoundMoreData = false;
    mHotlistSsidLostNumResults = 0;
    mHotlistSsidLostMoreData = false;
    mHotlistSsidFoundResults = NULL;
    mHotlistSsidLostResults = NULL;
    mPnoNetworkFoundResults = NULL;
    mPnoNetworkFoundNumResults = 0;
    mPnoNetworkFoundMoreData = false;
    mPasspointNetworkFoundResult = NULL;
    mPasspointAnqp = NULL;
    mPasspointAnqpLen = 0;
    mPasspointNetId = -1;
    mEventHandlingEnabled = false;

    switch(mSubCommandId)
    {
        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_START:
        {
            /* Register handlers for northbound asychronous scan events. */
            ret = registerVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE) ||
                  registerVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT) ||
                  registerVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT);
            if (ret)
                ALOGE("%s: Error in registering handler for "
                    "GSCAN_START. \n", __FUNCTION__);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE:
        {
            ret = registerVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE);
            if (ret)
                ALOGE("%s: Error in registering handler for "
                    "GSCAN_SIGNIFICANT_CHANGE. \n", __FUNCTION__);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST:
        {
            ret = registerVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND);
            if (ret)
                ALOGE("%s: Error in registering handler for"
                    " GSCAN_HOTLIST_AP_FOUND. \n", __FUNCTION__);

            ret = registerVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST);
            if (ret)
                ALOGE("%s: Error in registering handler for"
                    " GSCAN_HOTLIST_AP_LOST. \n", __FUNCTION__);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST:
        {
            ret = registerVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND);
            if (ret)
                ALOGE("%s: Error in registering handler for"
                    " PNO_NETWORK_FOUND. \n", __FUNCTION__);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST:
        {
            ret = registerVendorHandler(mVendor_id,
                QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND);
            if (ret)
                ALOGE("%s: Error in registering handler for"
                    " PNO_PASSPOINT_NETWORK_FOUND. \n", __FUNCTION__);
        }
        break;
    }
}

GScanCommandEventHandler::~GScanCommandEventHandler()
{
    switch(mSubCommandId)
    {
        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_START:
        {
            /* Unregister event handlers. */
            unregisterVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE);
            unregisterVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT);
            unregisterVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE:
        {
            unregisterVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST:
        {
            unregisterVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND);
            unregisterVendorHandler(mVendor_id,
                    QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST:
        {
            unregisterVendorHandler(mVendor_id,
                QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST:
        {
            unregisterVendorHandler(mVendor_id,
                QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND);
        }
        break;
    }
}

wifi_error GScanCommandEventHandler::gscan_parse_hotlist_ap_results(
                                            u32 num_results,
                                            wifi_scan_result *results,
                                            u32 starting_index,
                                            struct nlattr **tb_vendor)
{
    u32 i = starting_index;
    struct nlattr *scanResultsInfo;
    int rem = 0;
    u32 len = 0;
    ALOGV("gscan_parse_hotlist_ap_results: starting counter: %d", i);

    for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]),
            rem = nla_len(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST
            ]);
                nla_ok(scanResultsInfo, rem);
                scanResultsInfo = nla_next(scanResultsInfo, &(rem)))
    {
        struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
        nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
        (struct nlattr *) nla_data(scanResultsInfo),
                nla_len(scanResultsInfo), NULL);

        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                ])
        {
            ALOGE("gscan_parse_hotlist_ap_results: "
                "RESULTS_SCAN_RESULT_TIME_STAMP not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].ts =
            nla_get_u64(
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                ]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID
                ])
        {
            ALOGE("gscan_parse_hotlist_ap_results: "
                "RESULTS_SCAN_RESULT_SSID not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        len = nla_len(tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]);
        len =
            sizeof(results->ssid) <= len ? sizeof(results->ssid) : len;
        memcpy((void *)&results[i].ssid,
            nla_data(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID
                ])
        {
            ALOGE("gscan_parse_hotlist_ap_results: "
                "RESULTS_SCAN_RESULT_BSSID not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        len = nla_len(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]);
        len =
            sizeof(results->bssid) <= len ? sizeof(results->bssid) : len;
        memcpy(&results[i].bssid,
            nla_data(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), len);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL
                ])
        {
            ALOGE("gscan_parse_hotlist_ap_results: "
                "RESULTS_SCAN_RESULT_CHANNEL not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].channel =
            nla_get_u32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI
                ])
        {
            ALOGE("gscan_parse_hotlist_ap_results: "
                "RESULTS_SCAN_RESULT_RSSI not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].rssi =
            get_s32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT
                ])
        {
            ALOGE("gscan_parse_hotlist_ap_results: "
                "RESULTS_SCAN_RESULT_RTT not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].rtt =
            nla_get_u32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD
            ])
        {
            ALOGE("gscan_parse_hotlist_ap_results: "
                "RESULTS_SCAN_RESULT_RTT_SD not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].rtt_sd =
            nla_get_u32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]);

        ALOGV("gscan_parse_hotlist_ap_results: ts %" PRId64 " SSID  %s "
              "BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel %d rssi %d "
              "rtt %" PRId64" rtt_sd %" PRId64,
              results[i].ts, results[i].ssid,
              results[i].bssid[0], results[i].bssid[1], results[i].bssid[2],
              results[i].bssid[3], results[i].bssid[4], results[i].bssid[5],
              results[i].channel, results[i].rssi, results[i].rtt,
              results[i].rtt_sd);
        /* Increment loop index for next record */
        i++;
    }
    return WIFI_SUCCESS;
}

static wifi_error gscan_get_significant_change_results(u32 num_results,
                                    wifi_significant_change_result **results,
                                    u32 starting_index,
                                    struct nlattr **tb_vendor)
{
    u32 i = starting_index;
    int j;
    int rem = 0;
    u32 len = 0;
    char rssi_buf[1024]; //TODO: sizeof buf
    int rem_size;
    struct nlattr *scanResultsInfo;

    for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]),
            rem = nla_len(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]);
        nla_ok(scanResultsInfo, rem);
        scanResultsInfo = nla_next(scanResultsInfo, &(rem)))
    {
        struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
        nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
            (struct nlattr *) nla_data(scanResultsInfo),
                nla_len(scanResultsInfo), NULL);
        if (!
            tb2[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID
            ])
        {
            ALOGE("gscan_get_significant_change_results: "
                "SIGNIFICANT_CHANGE_RESULT_BSSID not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        len = nla_len(
            tb2[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID]
            );
        len =
            sizeof(results[i]->bssid) <= len ? sizeof(results[i]->bssid) : len;
        memcpy(&results[i]->bssid[0],
            nla_data(
            tb2[
        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID]),
            len);

        if (!
            tb2[
        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL
                ])
        {
            ALOGE("gscan_get_significant_change_results: "
                "SIGNIFICANT_CHANGE_RESULT_CHANNEL not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i]->channel =
            nla_get_u32(
            tb2[
        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL]);

        if (!
            tb2[
        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI
            ])
        {
            ALOGE("gscan_get_significant_change_results: "
                "SIGNIFICANT_CHANGE_RESULT_NUM_RSSI not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i]->num_rssi =
            nla_get_u32(
            tb2[
        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI]);

        if (!
            tb2[
        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST
            ])
        {
            ALOGE("gscan_get_significant_change_results: "
                "SIGNIFICANT_CHANGE_RESULT_RSSI_LIST not found");
            return WIFI_ERROR_INVALID_ARGS;
        }

        memcpy(&(results[i]->rssi[0]),
            nla_data(
            tb2[
        QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST]
            ), results[i]->num_rssi * sizeof(wifi_rssi));

        ALOGV("significant_change_result:%d, BSSID:"
            "%02x:%02x:%02x:%02x:%02x:%02x channel:%d  num_rssi:%d ",
            i, results[i]->bssid[0], results[i]->bssid[1], results[i]->bssid[2],
            results[i]->bssid[3], results[i]->bssid[4], results[i]->bssid[5],
            results[i]->channel, results[i]->num_rssi);

        rem_size = sizeof(rssi_buf);
        char *dst = rssi_buf;
        for (j = 0; j < results[i]->num_rssi && rem_size > 0; j++) {
            len = snprintf(dst, rem_size, "rssi[%d]:%d, ", j, results[i]->rssi[j]);
            dst += len;
            rem_size -= len;
        }
        ALOGV("RSSI LIST: %s", rssi_buf);

        /* Increment loop index to prase next record. */
        i++;
    }
    return WIFI_SUCCESS;
}

wifi_error GScanCommandEventHandler::gscan_parse_hotlist_ssid_results(
                                            u32 num_results,
                                            wifi_scan_result *results,
                                            u32 starting_index,
                                            struct nlattr **tb_vendor)
{
    u32 i = starting_index;
    struct nlattr *scanResultsInfo;
    int rem = 0;
    u32 len = 0;

    for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]),
            rem = nla_len(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST
            ]);
                nla_ok(scanResultsInfo, rem);
                scanResultsInfo = nla_next(scanResultsInfo, &(rem)))
    {
        struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
        nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
        (struct nlattr *) nla_data(scanResultsInfo),
                nla_len(scanResultsInfo), NULL);

        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                ])
        {
            ALOGE("gscan_parse_hotlist_ssid_results: "
                "RESULTS_SCAN_RESULT_TIME_STAMP not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].ts =
            nla_get_u64(
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                ]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID
                ])
        {
            ALOGE("gscan_parse_hotlist_ssid_results: "
                "RESULTS_SCAN_RESULT_SSID not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        len = nla_len(tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]);
        len =
            sizeof(results->ssid) <= len ? sizeof(results->ssid) : len;
        memcpy((void *)&results[i].ssid,
            nla_data(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID
                ])
        {
            ALOGE("gscan_parse_hotlist_ssid_results: "
                "RESULTS_SCAN_RESULT_BSSID not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        len = nla_len(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]);
        len =
            sizeof(results->bssid) <= len ? sizeof(results->bssid) : len;
        memcpy(&results[i].bssid,
            nla_data(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), len);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL
                ])
        {
            ALOGE("gscan_parse_hotlist_ssid_results: "
                "RESULTS_SCAN_RESULT_CHANNEL not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].channel =
            nla_get_u32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI
                ])
        {
            ALOGE("gscan_parse_hotlist_ssid_results: "
                "RESULTS_SCAN_RESULT_RSSI not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].rssi =
            get_s32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT
                ])
        {
            ALOGE("gscan_parse_hotlist_ssid_results: "
                "RESULTS_SCAN_RESULT_RTT not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].rtt =
            nla_get_u32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD
            ])
        {
            ALOGE("gscan_parse_hotlist_ssid_results: "
                "RESULTS_SCAN_RESULT_RTT_SD not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].rtt_sd =
            nla_get_u32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]);

        ALOGV("gscan_parse_hotlist_ssid_results: ts %" PRId64 " SSID  %s "
              "BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel %d rssi %d "
              "rtt %" PRId64 " rtt_sd %" PRId64,
              results[i].ts, results[i].ssid,
              results[i].bssid[0], results[i].bssid[1], results[i].bssid[2],
              results[i].bssid[3], results[i].bssid[4], results[i].bssid[5],
              results[i].channel, results[i].rssi, results[i].rtt,
              results[i].rtt_sd);
        /* Increment loop index for next record */
        i++;
    }
    return WIFI_SUCCESS;
}

wifi_error GScanCommandEventHandler::gscan_parse_passpoint_network_result(
            struct nlattr **tb_vendor)
{
    struct nlattr *scanResultsInfo, *wifiScanResultsInfo;
    u32 resultsBufSize = 0;
    u32 len = 0;
    int rem = 0;

    for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST]),
            rem = nla_len(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST
            ]);
                nla_ok(scanResultsInfo, rem);
                scanResultsInfo = nla_next(scanResultsInfo, &(rem)))
    {
        struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
        nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
        (struct nlattr *) nla_data(scanResultsInfo),
                nla_len(scanResultsInfo), NULL);

        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID
                ])
        {
            ALOGE("%s: GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID not found",
                  __FUNCTION__);
            return WIFI_ERROR_INVALID_ARGS;
        }
        mPasspointNetId =
            nla_get_u32(
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID
                ]);

        for (wifiScanResultsInfo = (struct nlattr *) nla_data(tb2[
             QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]),
             rem = nla_len(tb2[
             QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST
             ]);
             nla_ok(wifiScanResultsInfo, rem);
             wifiScanResultsInfo = nla_next(wifiScanResultsInfo, &(rem)))
        {
            struct nlattr *tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
            nla_parse(tb3, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
            (struct nlattr *) nla_data(wifiScanResultsInfo),
                     nla_len(wifiScanResultsInfo), NULL);

            resultsBufSize = sizeof(wifi_scan_result);
            if (!
                tb3[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH
                ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_IE_LENGTH not found", __FUNCTION__);
                return WIFI_ERROR_INVALID_ARGS;
            }
            resultsBufSize +=
                nla_get_u32(
                tb3[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH]);

            /* Allocate the appropriate memory for mPasspointNetworkFoundResult */
            mPasspointNetworkFoundResult = (wifi_scan_result *)
                                malloc (resultsBufSize);

            if (!mPasspointNetworkFoundResult) {
                ALOGE("%s: Failed to alloc memory for result struct. Exit.\n",
                    __FUNCTION__);
                return WIFI_ERROR_OUT_OF_MEMORY;
            }
            memset(mPasspointNetworkFoundResult, 0, resultsBufSize);

            mPasspointNetworkFoundResult->ie_length =
                nla_get_u32(
                tb3[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH]);

            if (!
                tb3[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                    ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_TIME_STAMP not found",
                      __FUNCTION__);
                return WIFI_ERROR_INVALID_ARGS;
            }
            mPasspointNetworkFoundResult->ts =
                nla_get_u64(
                tb3[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                    ]);
            if (!
                tb3[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID
                    ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_SSID not found", __FUNCTION__);
                return WIFI_ERROR_INVALID_ARGS;
            }
             len = nla_len(tb3[
                     QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]);
             len =
                 sizeof(mPasspointNetworkFoundResult->ssid) <= len ?
                 sizeof(mPasspointNetworkFoundResult->ssid) : len;
             memcpy((void *)&(mPasspointNetworkFoundResult->ssid[0]),
                 nla_data(
                 tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len);
             if (!
                 tb3[
                     QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID
                     ])
             {
                 ALOGE("%s: RESULTS_SCAN_RESULT_BSSID not found", __FUNCTION__);
                 return WIFI_ERROR_INVALID_ARGS;
             }
             len = nla_len(
                 tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]);
             len =
                 sizeof(mPasspointNetworkFoundResult->bssid) <= len ?
                 sizeof(mPasspointNetworkFoundResult->bssid) : len;
             memcpy(&(mPasspointNetworkFoundResult->bssid[0]),
                 nla_data(
                 tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]),
                 len);
             if (!
                 tb3[
                     QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL
                     ])
             {
                 ALOGE("%s: RESULTS_SCAN_RESULT_CHANNEL not found", __FUNCTION__);
                 return WIFI_ERROR_INVALID_ARGS;
             }
             mPasspointNetworkFoundResult->channel =
                 nla_get_u32(
                 tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]);
             if (!
                 tb3[
                     QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI
                     ])
             {
                 ALOGE("%s: RESULTS_SCAN_RESULT_RSSI not found", __FUNCTION__);
                 return WIFI_ERROR_INVALID_ARGS;
             }
             mPasspointNetworkFoundResult->rssi =
                 get_s32(
                 tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]);
             if (!
                 tb3[
                     QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT
                     ])
             {
                 ALOGE("%s: RESULTS_SCAN_RESULT_RTT not found", __FUNCTION__);
                 return WIFI_ERROR_INVALID_ARGS;
             }
             mPasspointNetworkFoundResult->rtt =
                 nla_get_u32(
                 tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]);
             if (!
                 tb3[
                     QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD
                 ])
             {
                 ALOGE("%s: RESULTS_SCAN_RESULT_RTT_SD not found", __FUNCTION__);
                 return WIFI_ERROR_INVALID_ARGS;
             }
             mPasspointNetworkFoundResult->rtt_sd =
                 nla_get_u32(
                 tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]);

             if (!
                 tb3[
                 QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD])
             {
                 ALOGE("%s: RESULTS_SCAN_RESULT_BEACON_PERIOD not found",
                     __FUNCTION__);
                 return WIFI_ERROR_INVALID_ARGS;
             }
             mPasspointNetworkFoundResult->beacon_period =
                 nla_get_u16(
                 tb3[
                 QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD]);

             if (!
                 tb3[
                     QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY
                     ])
             {
                 ALOGE("%s: RESULTS_SCAN_RESULT_CAPABILITY not found", __FUNCTION__);
                 return WIFI_ERROR_INVALID_ARGS;
             }
             mPasspointNetworkFoundResult->capability =
                 nla_get_u16(
                 tb3[
                 QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY]);

             if (!
                 tb3[
                     QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA
                 ])
             {
                 ALOGE("%s: RESULTS_SCAN_RESULT_IE_DATA not found", __FUNCTION__);
                 return WIFI_ERROR_INVALID_ARGS;
             }
             memcpy(&(mPasspointNetworkFoundResult->ie_data[0]),
                 nla_data(tb3[
                     QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA]),
                 mPasspointNetworkFoundResult->ie_length);

             ALOGV("%s: ts: %" PRId64 " SSID: %s "
                   "BSSID: %02x:%02x:%02x:%02x:%02x:%02x  channel: %d  rssi: %d"
                   " rtt: % " PRId64 " rtt_sd  %" PRId64 " ie_length  %u ",
                   __FUNCTION__, mPasspointNetworkFoundResult->ts,
                   mPasspointNetworkFoundResult->ssid,
                   mPasspointNetworkFoundResult->bssid[0],
                   mPasspointNetworkFoundResult->bssid[1],
                   mPasspointNetworkFoundResult->bssid[2],
                   mPasspointNetworkFoundResult->bssid[3],
                   mPasspointNetworkFoundResult->bssid[4],
                   mPasspointNetworkFoundResult->bssid[5],
                   mPasspointNetworkFoundResult->channel,
                   mPasspointNetworkFoundResult->rssi,
                   mPasspointNetworkFoundResult->rtt,
                   mPasspointNetworkFoundResult->rtt_sd,
                   mPasspointNetworkFoundResult->ie_length);
             ALOGV("%s: ie_data: ", __FUNCTION__);
             hexdump(mPasspointNetworkFoundResult->ie_data,
                     mPasspointNetworkFoundResult->ie_length);
        }

        if (!
           tb2[
               QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN
           ])
        {
            ALOGE("%s:PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN not found",
                  __FUNCTION__);
            return WIFI_ERROR_INVALID_ARGS;
        }
        mPasspointAnqpLen =
            nla_get_u32(
                tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN]);

        if (!mPasspointAnqpLen)
        {
            break;
        }
        mPasspointAnqp = (u8 *) malloc (mPasspointAnqpLen);
        if (!mPasspointAnqp) {
            ALOGE("%s: Failed to alloc memory for result struct. Exit.\n",
                  __FUNCTION__);
            return WIFI_ERROR_OUT_OF_MEMORY;
        }

        memset(mPasspointAnqp, 0, mPasspointAnqpLen);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP
            ])
            {
            ALOGE("%s: RESULTS_PASSPOINT_MATCH_ANQP not found", __FUNCTION__);
            return WIFI_ERROR_INVALID_ARGS;
        }
        memcpy(&(mPasspointAnqp[0]),
               nla_data(tb2[
                 QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP]),
               mPasspointAnqpLen);

        ALOGV("%s: ANQP LEN:%d, ANQP IE:", __FUNCTION__, mPasspointAnqpLen);
        hexdump((char*)mPasspointAnqp, mPasspointAnqpLen);

        /* expecting only one result break out after the first loop */
        break;
    }
    return WIFI_SUCCESS;
}

wifi_error GScanCommandEventHandler::gscan_parse_pno_network_results(
                                            u32 num_results,
                                            wifi_scan_result *results,
                                            u32 starting_index,
                                            struct nlattr **tb_vendor)
{
    u32 i = starting_index;
    struct nlattr *scanResultsInfo;
    int rem = 0;
    u32 len = 0;

    for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]),
            rem = nla_len(tb_vendor[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST
            ]);
                nla_ok(scanResultsInfo, rem);
                scanResultsInfo = nla_next(scanResultsInfo, &(rem)))
    {
        struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
        nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
        (struct nlattr *) nla_data(scanResultsInfo),
                nla_len(scanResultsInfo), NULL);

        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                ])
        {
            ALOGE("gscan_parse_pno_network_results: "
                "RESULTS_SCAN_RESULT_TIME_STAMP not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].ts =
            nla_get_u64(
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                ]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID
                ])
        {
            ALOGE("gscan_parse_pno_network_results: "
                "RESULTS_SCAN_RESULT_SSID not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        len = nla_len(tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]);
        len =
            sizeof(results->ssid) <= len ? sizeof(results->ssid) : len;
        memcpy((void *)&results[i].ssid,
            nla_data(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID
                ])
        {
            ALOGE("gscan_parse_pno_network_results: "
                "RESULTS_SCAN_RESULT_BSSID not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        len = nla_len(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]);
        len =
            sizeof(results->bssid) <= len ? sizeof(results->bssid) : len;
        memcpy(&results[i].bssid,
            nla_data(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), len);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL
                ])
        {
            ALOGE("gscan_parse_pno_network_results: "
                "RESULTS_SCAN_RESULT_CHANNEL not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].channel =
            nla_get_u32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI
                ])
        {
            ALOGE("gscan_parse_pno_network_results: "
                "RESULTS_SCAN_RESULT_RSSI not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].rssi =
            get_s32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT
                ])
        {
            ALOGE("gscan_parse_pno_network_results: "
                "RESULTS_SCAN_RESULT_RTT not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].rtt =
            nla_get_u32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]);
        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD
            ])
        {
            ALOGE("gscan_parse_pno_network_results: "
                "RESULTS_SCAN_RESULT_RTT_SD not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].rtt_sd =
            nla_get_u32(
            tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]);

        if (!
            tb2[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD])
        {
            ALOGE("gscan_parse_pno_network_results: "
                "RESULTS_SCAN_RESULT_BEACON_PERIOD not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].beacon_period =
            nla_get_u16(
            tb2[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD]);

        if (!
            tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY
                ])
        {
            ALOGE("gscan_parse_pno_network_results: "
                "RESULTS_SCAN_RESULT_CAPABILITY not found");
            return WIFI_ERROR_INVALID_ARGS;
        }
        results[i].capability =
            nla_get_u16(
            tb2[
            QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY]);

        ALOGV("gscan_parse_pno_network_results: ts %" PRId64 " SSID  %s "
              "BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel %d rssi %d "
              "rtt %" PRId64 " rtt_sd %" PRId64,
              results[i].ts, results[i].ssid,
              results[i].bssid[0], results[i].bssid[1], results[i].bssid[2],
              results[i].bssid[3], results[i].bssid[4], results[i].bssid[5],
              results[i].channel, results[i].rssi, results[i].rtt,
              results[i].rtt_sd);
        /* Increment loop index for next record */
        i++;
    }
    return WIFI_SUCCESS;
}

/* This function will be the main handler for incoming (from driver)
 * GScan_SUBCMD. Calls the appropriate callback handler after parsing
 * the vendor data.
 */
int GScanCommandEventHandler::handleEvent(WifiEvent &event)
{
    unsigned i=0;
    int ret = WIFI_SUCCESS;
    wifi_scan_result *result = NULL;
    struct nlattr *tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];

    if (mEventHandlingEnabled == false)
    {
        ALOGV("%s:Discarding event: %d",
              __FUNCTION__, mSubcmd);
        return NL_SKIP;
    }

    WifiVendorCommand::handleEvent(event);

    nla_parse(tbVendor, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
                        (struct nlattr *)mVendorData,
                        mDataLen, NULL);

    switch(mSubcmd)
    {
        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT:
        {
            wifi_request_id reqId;
            u32 len = 0;
            u32 resultsBufSize = 0;
            u32 lengthOfInfoElements = 0;
            u32 buckets_scanned = 0;

            ALOGV("Event QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT "
                "received.");
            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID])
            {
                ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Exit.",
                    __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            reqId = nla_get_u32(
                    tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
                    );
            /* If event has a different request_id, ignore that and use the
             *  request_id value which we're maintaining.
             */
            if (reqId != mRequestId) {
#ifdef QC_HAL_DEBUG
                ALOGE("%s: Event has Req. ID:%d <> Ours:%d, continue...",
                    __FUNCTION__, reqId, mRequestId);
#endif
                reqId = mRequestId;
            }

            /* Parse and extract the results. */
            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH
                ])
            {
                ALOGE("%s:RESULTS_SCAN_RESULT_IE_LENGTH not found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            lengthOfInfoElements =
                nla_get_u32(
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH]);

            ALOGV("%s: RESULTS_SCAN_RESULT_IE_LENGTH =%d",
                __FUNCTION__, lengthOfInfoElements);

            resultsBufSize =
                lengthOfInfoElements + sizeof(wifi_scan_result);
            result = (wifi_scan_result *) malloc (resultsBufSize);
            if (!result) {
                ALOGE("%s: Failed to alloc memory for result struct. Exit.\n",
                    __FUNCTION__);
                ret = WIFI_ERROR_OUT_OF_MEMORY;
                break;
            }
            memset(result, 0, resultsBufSize);

            result->ie_length = lengthOfInfoElements;

            /* Extract and fill out the wifi_scan_result struct. */
            if (!
            tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_TIME_STAMP not found",
                    __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            result->ts =
                nla_get_u64(
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP
                    ]);

            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID
                    ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_SSID not found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            len = nla_len(tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]);
            len =
                sizeof(result->ssid) <= len ? sizeof(result->ssid) : len;
            memcpy((void *)&result->ssid,
                nla_data(
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len);

            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID
                    ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_BSSID not found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            len = nla_len(
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]);
            len =
                sizeof(result->bssid) <= len ? sizeof(result->bssid) : len;
            memcpy(&result->bssid,
                nla_data(
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), len);

            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL
                    ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_CHANNEL not found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            result->channel =
                nla_get_u32(
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]);

            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI
                    ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_RSSI not found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            result->rssi =
                get_s32(
                tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]
                );

            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT
                    ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_RTT not found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            result->rtt =
                nla_get_u32(
                tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]);

            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD
                ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_RTT_SD not found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            result->rtt_sd =
                nla_get_u32(
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]);

            if (!
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_BEACON_PERIOD not found",
                    __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            result->beacon_period =
                nla_get_u16(
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD]);

            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY
                    ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_CAPABILITY not found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            result->capability =
                nla_get_u16(
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY]);

            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA
                ])
            {
                ALOGE("%s: RESULTS_SCAN_RESULT_IE_DATA not found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            memcpy(&(result->ie_data[0]),
                nla_data(tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA]),
                lengthOfInfoElements);
            if (!
                tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED
                    ])
            {
                ALOGD("%s: RESULTS_BUCKETS_SCANNED not found", __FUNCTION__);
            } else {
                buckets_scanned = get_u32(tbVendor[
                           QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED]);
            }
#ifdef QC_HAL_DEBUG
            ALOGD("handleEvent:FULL_SCAN_RESULTS: ts  %" PRId64, result->ts);
            ALOGD("handleEvent:FULL_SCAN_RESULTS: SSID  %s ", result->ssid) ;
            ALOGD("handleEvent:FULL_SCAN_RESULTS: "
                "BSSID: %02x:%02x:%02x:%02x:%02x:%02x \n",
                result->bssid[0], result->bssid[1], result->bssid[2],
                result->bssid[3], result->bssid[4], result->bssid[5]);
            ALOGD("handleEvent:FULL_SCAN_RESULTS: channel %d ",
                result->channel);
            ALOGD("handleEvent:FULL_SCAN_RESULTS: rssi  %d ", result->rssi);
            ALOGD("handleEvent:FULL_SCAN_RESULTS: rtt  %" PRId64, result->rtt);
            ALOGD("handleEvent:FULL_SCAN_RESULTS: rtt_sd  %" PRId64,
                result->rtt_sd);
            ALOGD("handleEvent:FULL_SCAN_RESULTS: beacon period  %d ",
                result->beacon_period);
            ALOGD("handleEvent:FULL_SCAN_RESULTS: capability  %d ",
                result->capability);
            ALOGD("handleEvent:FULL_SCAN_RESULTS: IE length  %d ",
                result->ie_length);

            ALOGD("%s: Invoking the callback. \n", __FUNCTION__);
#endif
            if (mHandler.on_full_scan_result) {
                (*mHandler.on_full_scan_result)(reqId, result, buckets_scanned);
                /* Reset flag and num counter. */
                free(result);
                result = NULL;
            }
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE:
        {
            wifi_request_id id;

#ifdef QC_HAL_DEBUG
            ALOGV("Event "
                    "QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE "
                    "received.");
#endif

            if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) {
                ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID"
                        "not found. Exit", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            id = nla_get_u32(
                    tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
                             );
            /* If this is not for us, then ignore it. */
            if (id != mRequestId) {
                ALOGE("%s: Event has Req. ID:%d <> ours:%d",
                        __FUNCTION__, id, mRequestId);
                break;
            }

            /* Invoke the callback func to report the number of results. */
            ALOGV("%s: Calling on_scan_event handler", __FUNCTION__);
            (*mHandler.on_scan_event)(id, WIFI_SCAN_THRESHOLD_NUM_SCANS);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND:
        {
            wifi_request_id id;
            u32 resultsBufSize = 0;
            u32 numResults = 0;
            u32 startingIndex, sizeOfObtainedResults;

            id = nla_get_u32(
                    tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
                    );
            /* If this is not for us, just ignore it. */
            if (id != mRequestId) {
                ALOGE("%s: Event has Req. ID:%d <> ours:%d",
                    __FUNCTION__, id, mRequestId);
                break;
            }
            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) {
                ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found",
                    __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            numResults = nla_get_u32(tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]);
            ALOGV("%s: number of results:%d", __FUNCTION__, numResults);

            /* Get the memory size of previous fragments, if any. */
            sizeOfObtainedResults = mHotlistApFoundNumResults *
                          sizeof(wifi_scan_result);

            mHotlistApFoundNumResults += numResults;
            resultsBufSize += mHotlistApFoundNumResults *
                                            sizeof(wifi_scan_result);

            /* Check if this chunck of scan results is a continuation of
             * a previous one.
             */
            if (mHotlistApFoundMoreData) {
                mHotlistApFoundResults = (wifi_scan_result *)
                            realloc (mHotlistApFoundResults, resultsBufSize);
            } else {
                mHotlistApFoundResults = (wifi_scan_result *)
                            malloc (resultsBufSize);
            }

            if (!mHotlistApFoundResults) {
                ALOGE("%s: Failed to alloc memory for results array. Exit.\n",
                    __FUNCTION__);
                ret = WIFI_ERROR_OUT_OF_MEMORY;
                break;
            }
            /* Initialize the newly allocated memory area with 0. */
            memset((u8 *)mHotlistApFoundResults + sizeOfObtainedResults, 0,
                    resultsBufSize - sizeOfObtainedResults);

            ALOGV("%s: Num of AP FOUND results = %d. \n", __FUNCTION__,
                                            mHotlistApFoundNumResults);

            /* To support fragmentation from firmware, monitor the
             * MORE_DATA flag and cache results until MORE_DATA = 0.
             * Only then we can pass on the results to framework through
             * the callback function.
             */
            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) {
                ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA not"
                    " found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            } else {
                mHotlistApFoundMoreData = nla_get_u8(
                    tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]);
                ALOGE("%s: More data = %d. \n",
                    __FUNCTION__, mHotlistApFoundMoreData);
            }

            ALOGV("%s: Extract hotlist_ap_found results.\n", __FUNCTION__);
            startingIndex = mHotlistApFoundNumResults - numResults;
            ALOGV("%s: starting_index:%d",
                __FUNCTION__, startingIndex);
            ret = gscan_parse_hotlist_ap_results(numResults,
                                                mHotlistApFoundResults,
                                                startingIndex,
                                                tbVendor);
            /* If a parsing error occurred, exit and proceed for cleanup. */
            if (ret)
                break;
            /* Send the results if no more result data fragments are expected */
            if (!mHotlistApFoundMoreData) {
                (*mHandler.on_hotlist_ap_found)(id,
                                                mHotlistApFoundNumResults,
                                                mHotlistApFoundResults);
                /* Reset flag and num counter. */
                free(mHotlistApFoundResults);
                mHotlistApFoundResults = NULL;
                mHotlistApFoundMoreData = false;
                mHotlistApFoundNumResults = 0;
            }
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST:
        {
            wifi_request_id id;
            u32 resultsBufSize = 0;
            u32 numResults = 0;
            u32 startingIndex, sizeOfObtainedResults;

            id = nla_get_u32(
                    tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
                    );
            /* If this is not for us, just ignore it. */
            if (id != mRequestId) {
                ALOGE("%s: Event has Req. ID:%d <> ours:%d",
                    __FUNCTION__, id, mRequestId);
                break;
            }
            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) {
                ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found",
                    __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            numResults = nla_get_u32(tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]);
            ALOGV("%s: number of results:%d", __FUNCTION__, numResults);

            /* Get the memory size of previous fragments, if any. */
            sizeOfObtainedResults = mHotlistApLostNumResults *
                          sizeof(wifi_scan_result);

            mHotlistApLostNumResults += numResults;
            resultsBufSize += mHotlistApLostNumResults *
                                            sizeof(wifi_scan_result);

            /* Check if this chunck of scan results is a continuation of
             * a previous one.
             */
            if (mHotlistApLostMoreData) {
                mHotlistApLostResults = (wifi_scan_result *)
                            realloc (mHotlistApLostResults, resultsBufSize);
            } else {
                mHotlistApLostResults = (wifi_scan_result *)
                            malloc (resultsBufSize);
            }

            if (!mHotlistApLostResults) {
                ALOGE("%s: Failed to alloc memory for results array. Exit.\n",
                    __FUNCTION__);
                ret = WIFI_ERROR_OUT_OF_MEMORY;
                break;
            }
            /* Initialize the newly allocated memory area with 0. */
            memset((u8 *)mHotlistApLostResults + sizeOfObtainedResults, 0,
                    resultsBufSize - sizeOfObtainedResults);

            ALOGV("%s: Num of AP Lost results = %d. \n", __FUNCTION__,
                                            mHotlistApLostNumResults);

            /* To support fragmentation from firmware, monitor the
             * MORE_DATA flag and cache results until MORE_DATA = 0.
             * Only then we can pass on the results to framework through
             * the callback function.
             */
            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) {
                ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA not"
                    " found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            } else {
                mHotlistApLostMoreData = nla_get_u8(
                    tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]);
                ALOGV("%s: More data = %d. \n",
                    __FUNCTION__, mHotlistApLostMoreData);
            }

            ALOGV("%s: Extract hotlist_ap_Lost results.\n", __FUNCTION__);
            startingIndex = mHotlistApLostNumResults - numResults;
            ALOGV("%s: starting_index:%d",
                __FUNCTION__, startingIndex);
            ret = gscan_parse_hotlist_ap_results(numResults,
                                                mHotlistApLostResults,
                                                startingIndex,
                                                tbVendor);
            /* If a parsing error occurred, exit and proceed for cleanup. */
            if (ret)
                break;
            /* Send the results if no more result data fragments are expected */
            if (!mHotlistApLostMoreData) {
                (*mHandler.on_hotlist_ap_lost)(id,
                                               mHotlistApLostNumResults,
                                               mHotlistApLostResults);
                /* Reset flag and num counter. */
                free(mHotlistApLostResults);
                mHotlistApLostResults = NULL;
                mHotlistApLostMoreData = false;
                mHotlistApLostNumResults = 0;
            }
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE:
        {
            wifi_request_id reqId;
            u32 numResults = 0, sizeOfObtainedResults;
            u32 startingIndex, index = 0;
            struct nlattr *scanResultsInfo;
            int rem = 0;

            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID])
            {
                ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Exit.",
                    __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            reqId = nla_get_u32(
                    tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
                    );
            /* If this is not for us, just ignore it. */
            if (reqId != mRequestId) {
                ALOGE("%s: Event has Req. ID:%d <> ours:%d",
                    __FUNCTION__, reqId, mRequestId);
                break;
            }
            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE])
            {
                ALOGE("%s: ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found."
                    "Exit.", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            numResults = nla_get_u32(tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]);
            /* Get the memory size of previous fragments, if any. */
            sizeOfObtainedResults = sizeof(wifi_significant_change_result *) *
                                mSignificantChangeNumResults;

            index = mSignificantChangeNumResults;
            mSignificantChangeNumResults += numResults;
            /*
             * Check if this chunck of wifi_significant_change results is a
             * continuation of a previous one.
             */
            if (mSignificantChangeMoreData) {
                mSignificantChangeResults =
                    (wifi_significant_change_result **)
                        realloc (mSignificantChangeResults,
                        sizeof(wifi_significant_change_result *) *
                                mSignificantChangeNumResults);
            } else {
                mSignificantChangeResults =
                    (wifi_significant_change_result **)
                        malloc (sizeof(wifi_significant_change_result *) *
                                mSignificantChangeNumResults);
            }

            if (!mSignificantChangeResults) {
                ALOGE("%s: Failed to alloc memory for results array. Exit.\n",
                    __FUNCTION__);
                ret = WIFI_ERROR_OUT_OF_MEMORY;
                break;
            }
            /* Initialize the newly allocated memory area with 0. */
            memset((u8 *)mSignificantChangeResults + sizeOfObtainedResults, 0,
                    sizeof(wifi_significant_change_result *) *
                                numResults);
            ALOGV("%s: mSignificantChangeMoreData = %d",
                    __FUNCTION__, mSignificantChangeMoreData);

            for (scanResultsInfo = (struct nlattr *) nla_data(tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]),
                rem = nla_len(tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]);
                nla_ok(scanResultsInfo, rem);
                scanResultsInfo = nla_next(scanResultsInfo, &(rem)))
            {
                u32 num_rssi = 0;
                u32 resultsBufSize = 0;
                struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
                nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
                    (struct nlattr *) nla_data(scanResultsInfo),
                    nla_len(scanResultsInfo), NULL);
                if (!tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI
                    ])
                {
                    ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_"
                        "SIGNIFICANT_CHANGE_RESULT_NUM_RSSI not found. "
                        "Exit.", __FUNCTION__);
                    ret = WIFI_ERROR_INVALID_ARGS;
                    break;
                }
                num_rssi = nla_get_u32(tb2[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI
                        ]);
                resultsBufSize = sizeof(wifi_significant_change_result) +
                            num_rssi * sizeof(wifi_rssi);
                mSignificantChangeResults[index] =
                    (wifi_significant_change_result *) malloc (resultsBufSize);

                if (!mSignificantChangeResults[index]) {
                    ALOGE("%s: Failed to alloc memory for results array Exit",
                        __FUNCTION__);
                    ret = WIFI_ERROR_OUT_OF_MEMORY;
                    break;
                }
                /* Initialize the newly allocated memory area with 0. */
                memset((u8 *)mSignificantChangeResults[index],
                        0, resultsBufSize);

                ALOGV("%s: For Significant Change results[%d], num_rssi:%d\n",
                    __FUNCTION__, index, num_rssi);
                index++;
            }

            ALOGV("%s: Extract significant change results.\n", __FUNCTION__);
            startingIndex =
                mSignificantChangeNumResults - numResults;
            ret = gscan_get_significant_change_results(numResults,
                                                mSignificantChangeResults,
                                                startingIndex,
                                                tbVendor);
            /* If a parsing error occurred, exit and proceed for cleanup. */
            if (ret)
                break;
            /* To support fragmentation from firmware, monitor the
             * MORE_DATA flag and cache results until MORE_DATA = 0.
             * Only then we can pass on the results to framework through
             * the callback function.
             */
            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) {
                ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA not"
                    " found. Stop parsing and exit.", __FUNCTION__);
                break;
            }
            mSignificantChangeMoreData = nla_get_u8(
                tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]);
            ALOGV("%s: More data = %d. \n",
                __FUNCTION__, mSignificantChangeMoreData);

            /* Send the results if no more result fragments are expected */
            if (!mSignificantChangeMoreData) {
                ALOGV("%s: Invoking the callback. \n", __FUNCTION__);
                (*mHandler.on_significant_change)(reqId,
                                              mSignificantChangeNumResults,
                                              mSignificantChangeResults);
                if (mSignificantChangeResults) {
                    /* Reset flag and num counter. */
                    for (index = 0; index < mSignificantChangeNumResults;
                         index++)
                    {
                        free(mSignificantChangeResults[index]);
                        mSignificantChangeResults[index] = NULL;
                    }
                    free(mSignificantChangeResults);
                    mSignificantChangeResults = NULL;
                }
                mSignificantChangeNumResults = 0;
                mSignificantChangeMoreData = false;
            }
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT:
        {
            wifi_scan_event scanEvent;
            wifi_request_id reqId;

            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID])
            {
                ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Exit.",
                    __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            reqId = nla_get_u32(
                    tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
                    );
            /* If this is not for us, just ignore it. */
            if (reqId != mRequestId) {
                ALOGE("%s: Event has Req. ID:%d <> ours:%d",
                    __FUNCTION__, reqId, mRequestId);
                break;
            }

            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_TYPE]) {
                ALOGE("%s: GSCAN_RESULTS_SCAN_EVENT_TYPE not"
                    " found. Stop parsing and exit.", __FUNCTION__);
                break;
            }
            scanEvent = (wifi_scan_event) nla_get_u8(tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_TYPE]);

            ALOGV("%s: Scan event type: %d\n", __FUNCTION__, scanEvent);
            /* Send the results if no more result fragments are expected. */
            (*mHandler.on_scan_event)(reqId, scanEvent);
        }
        break;

        case QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND:
        {
            wifi_request_id id;
            u32 resultsBufSize = 0;
            u32 numResults = 0;
            u32 startingIndex, sizeOfObtainedResults;

            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID])
            {
                /* RequestId is not provided by FW/Driver for this event */
                ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Continue.",
                    __FUNCTION__);
                id = mRequestId; /* Use the saved mRequestId instead. */
            } else {
                id = nla_get_u32(
                        tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
                        );
                /* If this is not for us, use the saved requestId */
                if (id != mRequestId) {
                    ALOGE("%s: Event has Req. ID:%d <> ours:%d",
                        __FUNCTION__, id, mRequestId);
                    id = mRequestId;
                }
            }

            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) {
                ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found",
                    __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            numResults = nla_get_u32(tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]);
            ALOGV("%s: number of results:%d", __FUNCTION__, numResults);

            /* Get the memory size of previous fragments, if any. */
            sizeOfObtainedResults = mPnoNetworkFoundNumResults *
                          sizeof(wifi_scan_result);

            mPnoNetworkFoundNumResults += numResults;
            resultsBufSize += mPnoNetworkFoundNumResults *
                                            sizeof(wifi_scan_result);

            /* Check if this chunck of scan results is a continuation of
             * a previous one.
             */
            if (mPnoNetworkFoundMoreData) {
                mPnoNetworkFoundResults = (wifi_scan_result *)
                            realloc (mPnoNetworkFoundResults, resultsBufSize);
            } else {
                mPnoNetworkFoundResults = (wifi_scan_result *)
                            malloc (resultsBufSize);
            }

            if (!mPnoNetworkFoundResults) {
                ALOGE("%s: Failed to alloc memory for results array. Exit.\n",
                    __FUNCTION__);
                ret = WIFI_ERROR_OUT_OF_MEMORY;
                break;
            }
            /* Initialize the newly allocated memory area with 0. */
            memset((u8 *)mPnoNetworkFoundResults + sizeOfObtainedResults, 0,
                    resultsBufSize - sizeOfObtainedResults);

            ALOGV("%s: Num of AP FOUND results = %d. \n", __FUNCTION__,
                                            mPnoNetworkFoundNumResults);

            /* To support fragmentation from firmware, monitor the
             * MORE_DATA flag and cache results until MORE_DATA = 0.
             * Only then we can pass on the results to framework through
             * the callback function.
             */
            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) {
                ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA not"
                    " found", __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            } else {
                mPnoNetworkFoundMoreData = nla_get_u8(
                    tbVendor[
                    QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]);
                ALOGV("%s: More data = %d. \n",
                    __FUNCTION__, mPnoNetworkFoundMoreData);
            }

            ALOGV("%s: Extract PNO_NETWORK_FOUND results.\n", __FUNCTION__);
            startingIndex = mPnoNetworkFoundNumResults - numResults;
            ALOGV("%s: starting_index:%d",
                __FUNCTION__, startingIndex);
            ret = gscan_parse_pno_network_results(numResults,
                                                mPnoNetworkFoundResults,
                                                startingIndex,
                                                tbVendor);
            /* If a parsing error occurred, exit and proceed for cleanup. */
            if (ret)
                break;
            /* Send the results if no more result data fragments are expected */
            if (!mPnoNetworkFoundMoreData) {
                (*mHandler.on_pno_network_found)(id,
                                                mPnoNetworkFoundNumResults,
                                                mPnoNetworkFoundResults);
                /* Reset flag and num counter. */
                if (mPnoNetworkFoundResults) {
                    free(mPnoNetworkFoundResults);
                    mPnoNetworkFoundResults = NULL;
                }
                mPnoNetworkFoundMoreData = false;
                mPnoNetworkFoundNumResults = 0;
            }
        }
        break;
        case QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND:
        {
            wifi_request_id id;

            if (!tbVendor[
                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID])
            {
                /* RequestId is not provided by FW/Driver for this event */
                ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Continue.",
                    __FUNCTION__);
                id = mRequestId; /* Use the saved mRequestId instead. */
            } else {
                id = nla_get_u32(
                        tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
                        );
                /* If this is not for us, use the saved requestId */
                if (id != mRequestId) {
                    ALOGE("%s: Event has Req. ID:%d <> ours:%d",
                        __FUNCTION__, id, mRequestId);
                    id = mRequestId;
                }
            }

            ret = gscan_parse_passpoint_network_result(tbVendor);
            /* If a parsing error occurred, exit and proceed for cleanup. */
            if (ret)
            {
                ALOGE("%s: gscan_parse_passpoint_network_result"
                      "returned error: %d.\n", __FUNCTION__, ret);
                break;
            }
            (*mHandler.on_passpoint_network_found)(id,
                                                   mPasspointNetId,
                                                   mPasspointNetworkFoundResult,
                                                   mPasspointAnqpLen,
                                                   mPasspointAnqp);
            if (mPasspointNetworkFoundResult)
            {
                free(mPasspointNetworkFoundResult);
                mPasspointNetworkFoundResult = NULL;
            }
            if (mPasspointAnqp)
            {
                free(mPasspointAnqp);
                mPasspointAnqp = NULL;
            }
            mPasspointNetId = -1;
            mPasspointAnqpLen = 0;
        }
        break;
        default:
            /* Error case should not happen print log */
            ALOGE("%s: Wrong GScan subcmd received %d", __FUNCTION__, mSubcmd);
    }

    /* A parsing error occurred, do the cleanup of gscan result lists. */
    if (ret) {
        switch(mSubcmd)
        {
            case QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT:
            {
                free(result);
                result = NULL;
            }
            break;

            case QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND:
            {
                /* Reset flag and num counter. */
                free(mHotlistApFoundResults);
                mHotlistApFoundResults = NULL;
                mHotlistApFoundMoreData = false;
                mHotlistApFoundNumResults = 0;
            }
            break;

            case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE:
            {
                if (mSignificantChangeResults) {
                    for (i = 0; i < mSignificantChangeNumResults; i++)
                    {
                        if (mSignificantChangeResults[i]) {
                            free(mSignificantChangeResults[i]);
                            mSignificantChangeResults[i] = NULL;
                        }
                    }
                    free(mSignificantChangeResults);
                    mSignificantChangeResults = NULL;
                }
                mSignificantChangeNumResults = 0;
                mSignificantChangeMoreData = false;
            }
            break;

            case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE:
            break;

            case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT:
            break;

            case QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST:
            {
                /* Reset flag and num counter. */
                free(mHotlistApLostResults);
                mHotlistApLostResults = NULL;
                mHotlistApLostMoreData = false;
                mHotlistApLostNumResults = 0;
            }
            break;

            case QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND:
            {
                /* Reset flag and num counter. */
                if (mPnoNetworkFoundResults) {
                    free(mPnoNetworkFoundResults);
                    mPnoNetworkFoundResults = NULL;
                }
                mPnoNetworkFoundMoreData = false;
                mPnoNetworkFoundNumResults = 0;
            }
            break;

            case QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND:
            {
                if (mPasspointNetworkFoundResult)
                {
                    free(mPasspointNetworkFoundResult);
                    mPasspointNetworkFoundResult = NULL;
                }
                if (mPasspointAnqp)
                {
                    free(mPasspointAnqp);
                    mPasspointAnqp = NULL;
                }
                mPasspointNetId = -1;
                mPasspointAnqpLen = 0;
            }
            break;

            default:
                ALOGE("%s: Parsing err handler: wrong GScan subcmd "
                    "received %d", __FUNCTION__, mSubcmd);
        }
    }
    return NL_SKIP;
}