/*
* 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.
*/
#include "sync.h"
#define LOG_TAG "WifiHAL"
#include <utils/Log.h>
#include <time.h>
#include "common.h"
#include "cpp_bindings.h"
#include "gscancommand.h"
#include "gscan_event_handler.h"
#define GSCAN_EVENT_WAIT_TIME_SECONDS 4
/* Used to handle gscan command events from driver/firmware. */
GScanCommandEventHandler *GScanStartCmdEventHandler = NULL;
GScanCommandEventHandler *GScanSetBssidHotlistCmdEventHandler = NULL;
GScanCommandEventHandler *GScanSetSignificantChangeCmdEventHandler = NULL;
/* Implementation of the API functions exposed in gscan.h */
wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
int band, int max_channels, wifi_channel *channels, int *num_channels)
{
int requestId, ret = 0;
GScanCommand *gScanCommand;
struct nlattr *nlData;
interface_info *ifaceInfo = getIfaceInfo(handle);
wifi_handle wifiHandle = getWifiHandle(handle);
if (channels == NULL) {
ALOGE("%s: NULL channels pointer provided. Exit.",
__func__);
return WIFI_ERROR_INVALID_ARGS;
}
/* No request id from caller, so generate one and pass it on to the driver.
* Generate one randomly.
*/
srand( time(NULL) );
requestId = rand();
gScanCommand = new GScanCommand(
wifiHandle,
requestId,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS);
if (gScanCommand == NULL) {
ALOGE("%s: Error GScanCommand NULL", __func__);
return WIFI_ERROR_UNKNOWN;
}
/* Create the NL message. */
ret = gScanCommand->create();
if (ret < 0)
goto cleanup;
/* Set the interface Id of the message. */
ret = gScanCommand->set_iface_id(ifaceInfo->name);
if (ret < 0)
goto cleanup;
/* Add the vendor specific attributes for the NL command. */
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
if (!nlData)
goto cleanup;
if (gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
requestId) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND,
band) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS,
max_channels) )
{
goto cleanup;
}
gScanCommand->attr_end(nlData);
/* Populate the input received from caller/framework. */
gScanCommand->setMaxChannels(max_channels);
gScanCommand->setChannels(channels);
gScanCommand->setNumChannelsPtr(num_channels);
/* Send the msg and wait for a response. */
ret = gScanCommand->requestResponse();
if (ret) {
ALOGE("%s: Error %d happened. ", __func__, ret);
}
cleanup:
ALOGI("%s: Delete object.", __func__);
delete gScanCommand;
return (wifi_error)ret;
}
void get_gscan_capabilities_cb(int status, wifi_gscan_capabilities capa)
{
ALOGD("%s: Status = %d.", __func__, status);
ALOGD("%s: Capabilities. max_ap_cache_per_scan:%d, "
"max_bssid_history_entries:%d, max_hotlist_aps:%d, "
"max_rssi_sample_size:%d, max_scan_buckets:%d, "
"max_scan_cache_size:%d, max_scan_reporting_threshold:%d, "
"max_significant_wifi_change_aps:%d.",
__func__, capa.max_ap_cache_per_scan,
capa.max_bssid_history_entries,
capa.max_hotlist_aps, capa.max_rssi_sample_size,
capa.max_scan_buckets,
capa.max_scan_cache_size, capa.max_scan_reporting_threshold,
capa.max_significant_wifi_change_aps);
}
wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
wifi_gscan_capabilities *capabilities)
{
int requestId, ret = 0;
GScanCommand *gScanCommand;
struct nlattr *nlData;
wifi_gscan_capabilities tCapabilities;
interface_info *ifaceInfo = getIfaceInfo(handle);
wifi_handle wifiHandle = getWifiHandle(handle);
if (capabilities == NULL) {
ALOGE("%s: NULL capabilities pointer provided. Exit.",
__func__);
return WIFI_ERROR_INVALID_ARGS;
}
/* No request id from caller, so generate one and pass it on to the driver.
* Generate it randomly.
*/
srand(time(NULL));
requestId = rand();
gScanCommand = new GScanCommand(
wifiHandle,
requestId,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CAPABILITIES);
if (gScanCommand == NULL) {
ALOGE("%s: Error GScanCommand NULL", __func__);
return WIFI_ERROR_UNKNOWN;
}
GScanCallbackHandler callbackHandler;
memset(&callbackHandler, 0, sizeof(callbackHandler));
callbackHandler.get_capabilities = get_gscan_capabilities_cb;
ret = gScanCommand->setCallbackHandler(callbackHandler);
if (ret < 0)
goto cleanup;
/* Create the NL message. */
ret = gScanCommand->create();
if (ret < 0)
goto cleanup;
/* Set the interface Id of the message. */
ret = gScanCommand->set_iface_id(ifaceInfo->name);
if (ret < 0)
goto cleanup;
/* Add the vendor specific attributes for the NL command. */
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
if (!nlData)
goto cleanup;
ret = gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
requestId);
if (ret < 0)
goto cleanup;
gScanCommand->attr_end(nlData);
ret = gScanCommand->allocRspParams(eGScanGetCapabilitiesRspParams);
if (ret != 0) {
ALOGE("%s: Failed to allocate memory fo response struct. Error:%d",
__func__, ret);
goto cleanup;
}
gScanCommand->waitForRsp(true);
ret = gScanCommand->requestEvent();
if (ret != 0) {
ALOGE("%s: requestEvent Error:%d",__func__, ret);
goto cleanup;
}
gScanCommand->getGetCapabilitiesRspParams(capabilities, (u32 *)&ret);
cleanup:
gScanCommand->freeRspParams(eGScanGetCapabilitiesRspParams);
ALOGI("%s: Delete object.", __func__);
delete gScanCommand;
return (wifi_error)ret;
}
void start_gscan_cb(int status)
{
ALOGD("%s: Status = %d.", __func__, status);
}
wifi_error wifi_start_gscan(wifi_request_id id,
wifi_interface_handle iface,
wifi_scan_cmd_params params,
wifi_scan_result_handler handler)
{
int ret = 0;
u32 i, j;
GScanCommand *gScanCommand;
struct nlattr *nlData;
interface_info *ifaceInfo = getIfaceInfo(iface);
wifi_handle wifiHandle = getWifiHandle(iface);
u32 num_scan_buckets, numChannelSpecs;
wifi_scan_bucket_spec bucketSpec;
struct nlattr *nlBuckectSpecList;
/* Check if a similar request to start gscan was made earlier.
* Right now we don't differentiate between the case where (i) the new
* Request Id is different from the current one vs (ii) case where both
* new and Request IDs are the same.
*/
if (GScanStartCmdEventHandler) {
if (id == GScanStartCmdEventHandler->get_request_id()) {
ALOGE("wifi_start_gscan(): GSCAN Start for request Id %d is still "
"running. Exit", id);
return WIFI_ERROR_TOO_MANY_REQUESTS;
} else {
ALOGE("wifi_start_gscan(): GSCAN Start for a different request "
"Id %d is requested. Not supported. Exit", id);
return WIFI_ERROR_NOT_SUPPORTED;
}
}
gScanCommand = new GScanCommand(
wifiHandle,
id,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_START);
if (gScanCommand == NULL) {
ALOGE("wifi_start_gscan(): Error GScanCommand NULL");
return WIFI_ERROR_UNKNOWN;
}
GScanCallbackHandler callbackHandler;
memset(&callbackHandler, 0, sizeof(callbackHandler));
callbackHandler.start = start_gscan_cb;
ret = gScanCommand->setCallbackHandler(callbackHandler);
if (ret < 0)
goto cleanup;
/* Create the NL message. */
ret = gScanCommand->create();
if (ret < 0)
goto cleanup;
/* Set the interface Id of the message. */
ret = gScanCommand->set_iface_id(ifaceInfo->name);
if (ret < 0)
goto cleanup;
/* Add the vendor specific attributes for the NL command. */
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
if (!nlData)
goto cleanup;
num_scan_buckets = (unsigned int)params.num_buckets > MAX_BUCKETS ?
MAX_BUCKETS : params.num_buckets;
if (gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
id) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_BASE_PERIOD,
params.base_period) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN,
params.max_ap_per_scan) ||
gScanCommand->put_u8(
QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD,
params.report_threshold) ||
gScanCommand->put_u8(
QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS,
num_scan_buckets))
{
goto cleanup;
}
nlBuckectSpecList =
gScanCommand->attr_start(QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC);
/* Add NL attributes for scan bucket specs . */
for (i = 0; i < num_scan_buckets; i++) {
bucketSpec = params.buckets[i];
numChannelSpecs = (unsigned int)bucketSpec.num_channels > MAX_CHANNELS ?
MAX_CHANNELS : bucketSpec.num_channels;
struct nlattr *nlBucketSpec = gScanCommand->attr_start(i);
if (gScanCommand->put_u8(
QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_INDEX,
bucketSpec.bucket) ||
gScanCommand->put_u8(
QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BAND,
bucketSpec.band) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_PERIOD,
bucketSpec.period) ||
gScanCommand->put_u8(
QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_REPORT_EVENTS,
bucketSpec.report_events) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS,
numChannelSpecs))
{
goto cleanup;
}
struct nlattr *nl_channelSpecList =
gScanCommand->attr_start(QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC);
/* Add NL attributes for scan channel specs . */
for (j = 0; j < numChannelSpecs; j++) {
struct nlattr *nl_channelSpec = gScanCommand->attr_start(j);
wifi_scan_channel_spec channel_spec = bucketSpec.channels[j];
if ( gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_CHANNEL,
channel_spec.channel) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_DWELL_TIME,
channel_spec.dwellTimeMs) ||
gScanCommand->put_u8(
QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_PASSIVE,
channel_spec.passive) )
{
goto cleanup;
}
gScanCommand->attr_end(nl_channelSpec);
}
gScanCommand->attr_end(nl_channelSpecList);
gScanCommand->attr_end(nlBucketSpec);
}
gScanCommand->attr_end(nlBuckectSpecList);
gScanCommand->attr_end(nlData);
ret = gScanCommand->allocRspParams(eGScanStartRspParams);
if (ret != 0) {
ALOGE("wifi_start_gscan(): Failed to allocate memory to the response "
"struct. Error:%d", ret);
goto cleanup;
}
/* Set the callback handler functions for related events. */
callbackHandler.on_scan_results_available =
handler.on_scan_results_available;
callbackHandler.on_full_scan_result = handler.on_full_scan_result;
callbackHandler.on_scan_event = handler.on_scan_event;
/* Create an object to handle the related events from firmware/driver. */
GScanStartCmdEventHandler = new GScanCommandEventHandler(
wifiHandle,
id,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_START,
callbackHandler);
if (GScanStartCmdEventHandler == NULL) {
ALOGE("wifi_start_gscan(): Error GScanStartCmdEventHandler NULL");
ret = WIFI_ERROR_UNKNOWN;
goto cleanup;
}
gScanCommand->waitForRsp(true);
ret = gScanCommand->requestEvent();
if (ret != 0) {
ALOGE("wifi_start_gscan(): requestEvent Error:%d", ret);
goto cleanup;
}
gScanCommand->getStartGScanRspParams((u32 *)&ret);
if (ret != 0)
{
goto cleanup;
}
cleanup:
gScanCommand->freeRspParams(eGScanStartRspParams);
ALOGI("wifi_start_gscan(): Delete object.");
delete gScanCommand;
/* Delete the command event handler object if ret != 0 */
if (ret && GScanStartCmdEventHandler) {
ALOGI("wifi_start_gscan(): Error ret:%d, delete event handler object.",
ret);
delete GScanStartCmdEventHandler;
GScanStartCmdEventHandler = NULL;
}
return (wifi_error)ret;
}
void stop_gscan_cb(int status)
{
ALOGD("%s: Status = %d.", __func__, status);
}
wifi_error wifi_stop_gscan(wifi_request_id id,
wifi_interface_handle iface)
{
int ret = 0;
GScanCommand *gScanCommand;
struct nlattr *nlData;
interface_info *ifaceInfo = getIfaceInfo(iface);
wifi_handle wifiHandle = getWifiHandle(iface);
ALOGI("Stopping GScan, halHandle = %p", wifiHandle);
if (GScanStartCmdEventHandler) {
if (id != GScanStartCmdEventHandler->get_request_id()) {
ALOGE("wifi_stop_gscan: GSCAN Stop requested for request Id %d "
"not matching that of existing GScan Start:%d. Exit",
id, GScanStartCmdEventHandler->get_request_id());
return WIFI_ERROR_INVALID_REQUEST_ID;
}
} else {
ALOGE("wifi_stop_gscan: GSCAN isn't running or already stopped. "
"Nothing to do. Exit");
return WIFI_ERROR_NOT_AVAILABLE;
}
gScanCommand = new GScanCommand(
wifiHandle,
id,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_STOP);
if (gScanCommand == NULL) {
ALOGE("%s: Error GScanCommand NULL", __func__);
return WIFI_ERROR_UNKNOWN;
}
GScanCallbackHandler callbackHandler;
memset(&callbackHandler, 0, sizeof(callbackHandler));
callbackHandler.stop = stop_gscan_cb;
ret = gScanCommand->setCallbackHandler(callbackHandler);
if (ret < 0)
goto cleanup;
/* Create the NL message. */
ret = gScanCommand->create();
if (ret < 0)
goto cleanup;
/* Set the interface Id of the message. */
ret = gScanCommand->set_iface_id(ifaceInfo->name);
if (ret < 0)
goto cleanup;
/* Add the vendor specific attributes for the NL command. */
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
if (!nlData)
goto cleanup;
ret = gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
id);
if (ret < 0)
goto cleanup;
gScanCommand->attr_end(nlData);
ret = gScanCommand->allocRspParams(eGScanStopRspParams);
if (ret != 0) {
ALOGE("%s: Failed to allocate memory to the response struct. "
"Error:%d", __func__, ret);
goto cleanup;
}
gScanCommand->waitForRsp(true);
ret = gScanCommand->requestEvent();
if (ret != 0) {
ALOGE("%s: requestEvent Error:%d",__func__, ret);
goto cleanup;
}
gScanCommand->getStopGScanRspParams((u32 *)&ret);
if (ret != 0)
{
goto cleanup;
}
/* Delete different GSCAN event handlers for the specified Request ID. */
if (GScanStartCmdEventHandler) {
delete GScanStartCmdEventHandler;
GScanStartCmdEventHandler = NULL;
}
cleanup:
gScanCommand->freeRspParams(eGScanStopRspParams);
ALOGI("%s: Delete object.", __func__);
delete gScanCommand;
return (wifi_error)ret;
}
void set_bssid_hotlist_cb(int status)
{
ALOGD("%s: Status = %d.", __func__, status);
}
/* Set the GSCAN BSSID Hotlist. */
wifi_error wifi_set_bssid_hotlist(wifi_request_id id,
wifi_interface_handle iface,
wifi_bssid_hotlist_params params,
wifi_hotlist_ap_found_handler handler)
{
int i, numAp, ret = 0;
GScanCommand *gScanCommand;
struct nlattr *nlData, *nlApThresholdParamList;
interface_info *ifaceInfo = getIfaceInfo(iface);
wifi_handle wifiHandle = getWifiHandle(iface);
ALOGD("Setting GScan BSSID Hotlist, halHandle = %p", wifiHandle);
/* Check if a similar request to set bssid hotlist was made earlier.
* Right now we don't differentiate between the case where (i) the new
* Request Id is different from the current one vs (ii) case where both
* new and Request IDs are the same.
*/
if (GScanSetBssidHotlistCmdEventHandler)
if (id == GScanSetBssidHotlistCmdEventHandler->get_request_id()) {
ALOGE("%s: GSCAN Set BSSID Hotlist for request Id %d is still"
"running. Exit", __func__, id);
return WIFI_ERROR_TOO_MANY_REQUESTS;
} else {
ALOGD("%s: GSCAN Set BSSID Hotlist for a different Request Id:%d"
"is requested. Not supported. Exit", __func__, id);
return WIFI_ERROR_NOT_SUPPORTED;
}
gScanCommand =
new GScanCommand(
wifiHandle,
id,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST);
if (gScanCommand == NULL) {
ALOGE("%s: Error GScanCommand NULL", __func__);
return WIFI_ERROR_UNKNOWN;
}
GScanCallbackHandler callbackHandler;
memset(&callbackHandler, 0, sizeof(callbackHandler));
callbackHandler.set_bssid_hotlist = set_bssid_hotlist_cb,
ret = gScanCommand->setCallbackHandler(callbackHandler);
if (ret < 0)
goto cleanup;
/* Create the NL message. */
ret = gScanCommand->create();
if (ret < 0)
goto cleanup;
/* Set the interface Id of the message. */
ret = gScanCommand->set_iface_id(ifaceInfo->name);
if (ret < 0)
goto cleanup;
/* Add the vendor specific attributes for the NL command. */
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
if (!nlData)
goto cleanup;
numAp = (unsigned int)params.num_ap > MAX_HOTLIST_APS ? MAX_HOTLIST_APS : params.num_ap;
if (gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
id) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_NUM_AP,
numAp))
{
goto cleanup;
}
/* Add the vendor specific attributes for the NL command. */
nlApThresholdParamList =
gScanCommand->attr_start(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM);
if (!nlApThresholdParamList)
goto cleanup;
/* Add nested NL attributes for AP Threshold Param. */
for (i = 0; i < numAp; i++) {
ap_threshold_param apThreshold = params.ap[i];
struct nlattr *nlApThresholdParam = gScanCommand->attr_start(i);
if (!nlApThresholdParam)
goto cleanup;
if (gScanCommand->put_addr(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_BSSID,
apThreshold.bssid) ||
gScanCommand->put_s32(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_LOW,
apThreshold.low) ||
gScanCommand->put_s32(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH,
apThreshold.high) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_CHANNEL,
apThreshold.channel))
{
goto cleanup;
}
gScanCommand->attr_end(nlApThresholdParam);
}
gScanCommand->attr_end(nlApThresholdParamList);
gScanCommand->attr_end(nlData);
ret = gScanCommand->allocRspParams(eGScanSetBssidHotlistRspParams);
if (ret != 0) {
ALOGE("%s: Failed to allocate memory to the response struct. "
"Error:%d", __func__, ret);
goto cleanup;
}
callbackHandler.on_hotlist_ap_found = handler.on_hotlist_ap_found;
/* Create an object of the event handler class to take care of the
* asychronous events on the north-bound.
*/
GScanSetBssidHotlistCmdEventHandler = new GScanCommandEventHandler(
wifiHandle,
id,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST,
callbackHandler);
if (GScanSetBssidHotlistCmdEventHandler == NULL) {
ALOGE("%s: Error instantiating GScanSetBssidHotlistCmdEventHandler.",
__func__);
ret = WIFI_ERROR_UNKNOWN;
goto cleanup;
}
ALOGD("%s: Handler object was created for HOTLIST_AP_FOUND.", __func__);
gScanCommand->waitForRsp(true);
ret = gScanCommand->requestEvent();
if (ret != 0) {
ALOGE("%s: requestEvent Error:%d",__func__, ret);
goto cleanup;
}
gScanCommand->getSetBssidHotlistRspParams((u32 *)&ret);
if (ret != 0)
{
goto cleanup;
}
cleanup:
gScanCommand->freeRspParams(eGScanSetBssidHotlistRspParams);
ALOGI("%s: Delete object. ", __func__);
delete gScanCommand;
/* Delete the command event handler object if ret != 0 */
if (ret && GScanSetBssidHotlistCmdEventHandler) {
delete GScanSetBssidHotlistCmdEventHandler;
GScanSetBssidHotlistCmdEventHandler = NULL;
}
return (wifi_error)ret;
}
void reset_bssid_hotlist_cb(int status)
{
ALOGD("%s: Status = %d.", __func__, status);
}
wifi_error wifi_reset_bssid_hotlist(wifi_request_id id,
wifi_interface_handle iface)
{
int ret = 0;
GScanCommand *gScanCommand;
struct nlattr *nlData;
interface_info *ifaceInfo = getIfaceInfo(iface);
wifi_handle wifiHandle = getWifiHandle(iface);
ALOGE("Resetting GScan BSSID Hotlist, halHandle = %p", wifiHandle);
if (GScanSetBssidHotlistCmdEventHandler) {
if (id != GScanSetBssidHotlistCmdEventHandler->get_request_id()) {
ALOGE("%s: GSCAN Reset Hotlist BSSID requested for request Id %d"
"not matching that of existing GScan Set Hotlist BSSID:%d. "
"Exit", __func__, id,
GScanSetBssidHotlistCmdEventHandler->get_request_id());
return WIFI_ERROR_INVALID_REQUEST_ID;
}
}
gScanCommand = new GScanCommand(
wifiHandle,
id,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_BSSID_HOTLIST);
if (gScanCommand == NULL) {
ALOGE("%s: Error GScanCommand NULL", __func__);
return WIFI_ERROR_UNKNOWN;
}
GScanCallbackHandler callbackHandler;
memset(&callbackHandler, 0, sizeof(callbackHandler));
callbackHandler.reset_bssid_hotlist = reset_bssid_hotlist_cb;
ret = gScanCommand->setCallbackHandler(callbackHandler);
if (ret < 0)
goto cleanup;
/* Create the NL message. */
ret = gScanCommand->create();
if (ret < 0)
goto cleanup;
/* Set the interface Id of the message. */
ret = gScanCommand->set_iface_id(ifaceInfo->name);
if (ret < 0)
goto cleanup;
/* Add the vendor specific attributes for the NL command. */
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
if (!nlData)
goto cleanup;
ret = gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID, id);
if (ret < 0)
goto cleanup;
gScanCommand->attr_end(nlData);
ret = gScanCommand->allocRspParams(eGScanResetBssidHotlistRspParams);
if (ret != 0) {
ALOGE("%s: Failed to allocate memory to the response struct. "
"Error:%d", __func__, ret);
goto cleanup;
}
gScanCommand->waitForRsp(true);
ret = gScanCommand->requestEvent();
if (ret != 0) {
ALOGE("%s: requestEvent Error:%d",__func__, ret);
goto cleanup;
}
gScanCommand->getResetBssidHotlistRspParams((u32 *)&ret);
if (ret != 0)
{
goto cleanup;
}
if (GScanSetBssidHotlistCmdEventHandler) {
delete GScanSetBssidHotlistCmdEventHandler;
GScanSetBssidHotlistCmdEventHandler = NULL;
}
cleanup:
gScanCommand->freeRspParams(eGScanResetBssidHotlistRspParams);
ALOGI("%s: Delete object.", __func__);
delete gScanCommand;
return (wifi_error)ret;
}
void set_significant_change_cb(int status)
{
ALOGD("%s: Status = %d.", __func__, status);
}
/* Set the GSCAN Significant AP Change list. */
wifi_error wifi_set_significant_change_handler(wifi_request_id id,
wifi_interface_handle iface,
wifi_significant_change_params params,
wifi_significant_change_handler handler)
{
int i, numAp, ret = 0;
GScanCommand *gScanCommand;
struct nlattr *nlData, *nlApThresholdParamList;
interface_info *ifaceInfo = getIfaceInfo(iface);
wifi_handle wifiHandle = getWifiHandle(iface);
ALOGE("Setting GScan Significant Change, halHandle = %p", wifiHandle);
/* Check if a similar request to set significant change was made earlier.
* Right now we don't differentiate between the case where (i) the new
* Request Id is different from the current one vs (ii) both new and
* Request Ids are the same.
*/
if (GScanSetSignificantChangeCmdEventHandler)
if (id == GScanSetSignificantChangeCmdEventHandler->get_request_id()) {
ALOGE("%s: GSCAN Set Significant Change for request Id %d is still"
"running. Exit", __func__, id);
return WIFI_ERROR_TOO_MANY_REQUESTS;
} else {
ALOGE("%s: GSCAN Set Significant Change for a different Request "
"Id:%d is requested. Not supported. Exit", __func__, id);
return WIFI_ERROR_NOT_SUPPORTED;
}
gScanCommand = new GScanCommand(
wifiHandle,
id,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE);
if (gScanCommand == NULL) {
ALOGE("%s: Error GScanCommand NULL", __func__);
return WIFI_ERROR_UNKNOWN;
}
GScanCallbackHandler callbackHandler;
memset(&callbackHandler, 0, sizeof(callbackHandler));
callbackHandler.set_significant_change = set_significant_change_cb;
ret = gScanCommand->setCallbackHandler(callbackHandler);
if (ret < 0)
goto cleanup;
/* Create the NL message. */
ret = gScanCommand->create();
if (ret < 0)
goto cleanup;
/* Set the interface Id of the message. */
ret = gScanCommand->set_iface_id(ifaceInfo->name);
if (ret < 0)
goto cleanup;
/* Add the vendor specific attributes for the NL command. */
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
if (!nlData)
goto cleanup;
numAp = (unsigned int)params.num_ap > MAX_SIGNIFICANT_CHANGE_APS ?
MAX_SIGNIFICANT_CHANGE_APS : params.num_ap;
if (gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
id) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE,
params.rssi_sample_size) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE,
params.lost_ap_sample_size) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING,
params.min_breaching) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP,
numAp))
{
goto cleanup;
}
/* Add the vendor specific attributes for the NL command. */
nlApThresholdParamList =
gScanCommand->attr_start(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM);
if (!nlApThresholdParamList)
goto cleanup;
/* Add nested NL attributes for AP Threshold Param list. */
for (i = 0; i < numAp; i++) {
ap_threshold_param apThreshold = params.ap[i];
struct nlattr *nlApThresholdParam = gScanCommand->attr_start(i);
if (!nlApThresholdParam)
goto cleanup;
if ( gScanCommand->put_addr(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_BSSID,
apThreshold.bssid) ||
gScanCommand->put_s32(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_LOW,
apThreshold.low) ||
gScanCommand->put_s32(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH,
apThreshold.high) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_CHANNEL,
apThreshold.channel) )
{
goto cleanup;
}
gScanCommand->attr_end(nlApThresholdParam);
}
gScanCommand->attr_end(nlApThresholdParamList);
gScanCommand->attr_end(nlData);
ret = gScanCommand->allocRspParams(eGScanSetSignificantChangeRspParams);
if (ret != 0) {
ALOGE("%s: Failed to allocate memory to the response struct. "
"Error:%d", __func__, ret);
goto cleanup;
}
callbackHandler.on_significant_change = handler.on_significant_change;
/* Create an object of the event handler class to take care of the
* asychronous events on the north-bound.
*/
GScanSetSignificantChangeCmdEventHandler = new GScanCommandEventHandler(
wifiHandle,
id,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE,
callbackHandler);
if (GScanSetSignificantChangeCmdEventHandler == NULL) {
ALOGE("%s: Error in instantiating, "
"GScanSetSignificantChangeCmdEventHandler.",
__func__);
ret = WIFI_ERROR_UNKNOWN;
goto cleanup;
}
ALOGD("%s: Event handler object was created for SIGNIFICANT_CHANGE.",
__func__);
gScanCommand->waitForRsp(true);
ret = gScanCommand->requestEvent();
if (ret != 0) {
ALOGE("%s: requestEvent Error:%d",__func__, ret);
goto cleanup;
}
gScanCommand->getSetSignificantChangeRspParams((u32 *)&ret);
if (ret != 0)
{
goto cleanup;
}
cleanup:
gScanCommand->freeRspParams(eGScanSetSignificantChangeRspParams);
ALOGI("%s: Delete object.", __func__);
/* Delete the command event handler object if ret != 0 */
if (ret && GScanSetSignificantChangeCmdEventHandler) {
delete GScanSetSignificantChangeCmdEventHandler;
GScanSetSignificantChangeCmdEventHandler = NULL;
}
delete gScanCommand;
return (wifi_error)ret;
}
void reset_significant_change_cb(int status)
{
ALOGD("%s: Status = %d.", __func__, status);
}
/* Clear the GSCAN Significant AP change list. */
wifi_error wifi_reset_significant_change_handler(wifi_request_id id,
wifi_interface_handle iface)
{
int ret = 0;
GScanCommand *gScanCommand;
struct nlattr *nlData;
interface_info *ifaceInfo = getIfaceInfo(iface);
wifi_handle wifiHandle = getWifiHandle(iface);
ALOGD("Resetting GScan Significant Change, halHandle = %p", wifiHandle);
if (GScanSetSignificantChangeCmdEventHandler) {
if (id != GScanSetSignificantChangeCmdEventHandler->get_request_id()) {
ALOGE("%s: GSCAN Reset Significant Change requested for request "
"Id %d not matching that of existing GScan Set Hotlist "
"BSSID:%d. Exit", __func__, id,
GScanSetSignificantChangeCmdEventHandler->get_request_id());
return WIFI_ERROR_INVALID_REQUEST_ID;
}
}
gScanCommand =
new GScanCommand
(
wifiHandle,
id,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SIGNIFICANT_CHANGE);
if (gScanCommand == NULL) {
ALOGE("%s: Error GScanCommand NULL", __func__);
return WIFI_ERROR_UNKNOWN;
}
GScanCallbackHandler callbackHandler;
memset(&callbackHandler, 0, sizeof(callbackHandler));
callbackHandler.reset_significant_change = reset_significant_change_cb;
ret = gScanCommand->setCallbackHandler(callbackHandler);
if (ret < 0)
goto cleanup;
/* Create the NL message. */
ret = gScanCommand->create();
if (ret < 0)
goto cleanup;
/* Set the interface Id of the message. */
ret = gScanCommand->set_iface_id(ifaceInfo->name);
if (ret < 0)
goto cleanup;
/* Add the vendor specific attributes for the NL command. */
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
if (!nlData)
goto cleanup;
ret = gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
id);
if (ret < 0)
goto cleanup;
gScanCommand->attr_end(nlData);
ret = gScanCommand->allocRspParams(eGScanResetSignificantChangeRspParams);
if (ret != 0) {
ALOGE("%s: Failed to allocate memory to the response struct. "
"Error:%d", __func__, ret);
goto cleanup;
}
gScanCommand->waitForRsp(true);
ret = gScanCommand->requestEvent();
if (ret != 0) {
ALOGE("%s: requestEvent Error:%d",__func__, ret);
goto cleanup;
}
gScanCommand->getResetSignificantChangeRspParams((u32 *)&ret);
if (ret != 0)
{
goto cleanup;
}
if (GScanSetSignificantChangeCmdEventHandler) {
delete GScanSetSignificantChangeCmdEventHandler;
GScanSetSignificantChangeCmdEventHandler = NULL;
}
cleanup:
gScanCommand->freeRspParams(eGScanResetSignificantChangeRspParams);
ALOGI("%s: Delete object.", __func__);
delete gScanCommand;
return (wifi_error)ret;
}
void get_gscan_cached_results_cb(u8 moreData, u32 numResults)
{
ALOGD("%s: More data = %d.", __func__, moreData);
ALOGD("%s: Number of cached results = %d.", __func__, numResults);
}
/* Get the GSCAN cached scan results. */
wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface,
byte flush, int max,
wifi_scan_result *results,
int *num)
{
int requestId, ret = 0;
wifi_scan_result *result = results;
u32 j = 0;
int i = 0;
u8 moreData = 0;
u16 waitTime = GSCAN_EVENT_WAIT_TIME_SECONDS;
GScanCommand *gScanCommand;
struct nlattr *nlData;
interface_info *ifaceInfo = getIfaceInfo(iface);
wifi_handle wifiHandle = getWifiHandle(iface);
if (results == NULL) {
ALOGE("%s: NULL results pointer provided. Exit.",
__func__);
return WIFI_ERROR_INVALID_ARGS;
}
/* No request id from caller, so generate one and pass it on to the driver. */
/* Generate it randomly */
srand(time(NULL));
requestId = rand();
ALOGE("Getting GScan Cached Results, halHandle = %p", wifiHandle);
gScanCommand = new GScanCommand(
wifiHandle,
requestId,
OUI_QCA,
QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS);
if (gScanCommand == NULL) {
ALOGE("%s: Error GScanCommand NULL", __func__);
return WIFI_ERROR_UNKNOWN;
}
GScanCallbackHandler callbackHandler;
memset(&callbackHandler, 0, sizeof(callbackHandler));
callbackHandler.get_cached_results = get_gscan_cached_results_cb;
ret = gScanCommand->setCallbackHandler(callbackHandler);
if (ret < 0)
goto cleanup;
/* Create the NL message. */
ret = gScanCommand->create();
if (ret < 0)
goto cleanup;
/* Set the interface Id of the message. */
ret = gScanCommand->set_iface_id(ifaceInfo->name);
if (ret < 0)
goto cleanup;
/* Add the vendor specific attributes for the NL command. */
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
if (!nlData)
goto cleanup;
if (ret < 0)
goto cleanup;
if (gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
requestId) ||
gScanCommand->put_u8(
QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH,
flush) ||
gScanCommand->put_u32(
QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX,
max))
{
goto cleanup;
}
gScanCommand->attr_end(nlData);
ret = gScanCommand->allocRspParams(eGScanGetCachedResultsRspParams);
if (ret != 0) {
ALOGE("%s: Failed to allocate memory fo response struct. Error:%d",
__func__, ret);
goto cleanup;
}
gScanCommand->waitForRsp(true);
ret = gScanCommand->requestEvent();
if (ret != 0) {
ALOGE("%s: requestEvent Error:%d",__func__, ret);
goto cleanup;
}
/* Read more data flag and number of results of retrieved cached results
* from driver/firmware.
* If more data is 0 or numResults >= max, return with results populated.
* Otherwise, loop in 4s wait for next results fragment(s).
*/
ret = gScanCommand->getGetCachedResultsRspParams(max,
(u8 *)&moreData,
num,
results);
while (!ret && moreData && (*num < max)) {
int res = gScanCommand->timed_wait(waitTime);
if (res == ETIMEDOUT) {
ALOGE("%s: Time out happened.", __func__);
/*Proceed to cleanup & return whatever data avaiable at this time*/
goto cleanup;
}
ALOGD("%s: Command invoked return value:%d",__func__, res);
/* Read the moreData and numResults again and possibly append new
* cached results to the list.
*/
ret = gScanCommand->getGetCachedResultsRspParams(max,
(u8 *)&moreData,
num,
results);
}
if (!ret) {
for(i=0; i< *num; i++)
{
ALOGI("HAL: Result : %d\n", i+1);
ALOGI("HAL: ts %lld \n", result->ts);
ALOGI("HAL: SSID %s \n", result->ssid);
ALOGI("HAL: 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]);
ALOGI("HAL: channel %d \n", result->channel);
ALOGI("HAL: rssi %d \n", result->rssi);
ALOGI("HAL: rtt %lld \n", result->rtt);
ALOGI("HAL: rtt_sd %lld \n", result->rtt_sd);
ALOGI("HAL: beacon period %d \n",
result->beacon_period);
ALOGI("HAL: capability %d \n", result->capability);
ALOGI("HAL: IE length %d \n", result->ie_length);
ALOGI("HAL: IE Data \n");
hexdump(result->ie_data, result->ie_length);
result = (wifi_scan_result *)
((u8 *)&results[i] + sizeof(wifi_scan_result) +
result->ie_length);
}
}
cleanup:
gScanCommand->freeRspParams(eGScanGetCachedResultsRspParams);
ALOGI("%s: Delete object.", __func__);
delete gScanCommand;
return (wifi_error)ret;
}
GScanCommand::GScanCommand(wifi_handle handle, int id, u32 vendor_id,
u32 subcmd)
: WifiVendorCommand(handle, id, vendor_id, subcmd)
{
ALOGD("GScanCommand %p constructed", this);
/* Initialize the member data variables here */
mStartGScanRspParams = NULL;
mStopGScanRspParams = NULL;
mSetBssidHotlistRspParams = NULL;
mResetBssidHotlistRspParams = NULL;
mSetSignificantChangeRspParams = NULL;
mResetSignificantChangeRspParams = NULL;
mGetCapabilitiesRspParams = NULL;
mGetCachedResultsRspParams = NULL;
mGetCachedResultsNumResults = 0;
mChannels = NULL;
mMaxChannels = 0;
mNumChannelsPtr = NULL;
mWaitforRsp = false;
mRequestId = id;
memset(&mHandler, 0,sizeof(mHandler));
}
GScanCommand::~GScanCommand()
{
ALOGD("GScanCommand %p destructor", this);
unregisterVendorHandler(mVendor_id, mSubcmd);
}
/* This function implements creation of Vendor command */
int GScanCommand::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;
ALOGI("%s: mVendor_id = %d, Subcmd = %d.",
__func__, mVendor_id, mSubcmd);
out:
return ret;
}
/* Callback handlers registered for nl message send */
static int error_handler_gscan(struct sockaddr_nl *nla, struct nlmsgerr *err,
void *arg)
{
struct sockaddr_nl *tmp;
int *ret = (int *)arg;
tmp = nla;
*ret = err->error;
ALOGE("%s: Error code:%d (%s)", __func__, *ret, strerror(-(*ret)));
return NL_STOP;
}
/* Callback handlers registered for nl message send */
static int ack_handler_gscan(struct nl_msg *msg, void *arg)
{
int *ret = (int *)arg;
struct nl_msg * a;
ALOGE("%s: called", __func__);
a = msg;
*ret = 0;
return NL_STOP;
}
/* Callback handlers registered for nl message send */
static int finish_handler_gscan(struct nl_msg *msg, void *arg)
{
int *ret = (int *)arg;
struct nl_msg * a;
ALOGE("%s: called", __func__);
a = msg;
*ret = 0;
return NL_SKIP;
}
/*
* Override base class requestEvent and implement little differently here.
* This will send the request message.
* We don't wait for any response back in case of gscan as it is asynchronous,
* thus no wait for condition.
*/
int GScanCommand::requestEvent()
{
int res = -1;
struct nl_cb *cb;
ALOGD("%s: Entry.", __func__);
cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb) {
ALOGE("%s: Callback allocation failed",__func__);
res = -1;
goto out;
}
/* Send message */
ALOGE("%s:Handle:%p Socket Value:%p", __func__, mInfo, mInfo->cmd_sock);
res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
if (res < 0)
goto out;
res = 1;
nl_cb_err(cb, NL_CB_CUSTOM, error_handler_gscan, &res);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_gscan, &res);
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_gscan, &res);
/* Err is populated as part of finish_handler. */
while (res > 0){
nl_recvmsgs(mInfo->cmd_sock, cb);
}
ALOGD("%s: Msg sent, res=%d, mWaitForRsp=%d", __func__, res, mWaitforRsp);
/* Only wait for the asynchronous event if HDD returns success, res=0 */
if (!res && (mWaitforRsp == true)) {
struct timespec abstime;
abstime.tv_sec = 4;
abstime.tv_nsec = 0;
res = mCondition.wait(abstime);
if (res == ETIMEDOUT)
{
ALOGE("%s: Time out happened.", __func__);
}
ALOGD("%s: Command invoked return value:%d, mWaitForRsp=%d",
__func__, res, mWaitforRsp);
}
out:
/* Free the VendorData */
if (mVendorData) {
free(mVendorData);
}
mVendorData = NULL;
/* Cleanup the mMsg */
mMsg.destroy();
return res;
}
int GScanCommand::requestResponse()
{
ALOGD("%s: request a response", __func__);
return WifiCommand::requestResponse(mMsg);
}
int GScanCommand::handleResponse(WifiEvent &reply) {
ALOGI("Received a GScan response message from Driver");
u32 status;
int i = 0;
WifiVendorCommand::handleResponse(reply);
switch(mSubcmd)
{
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS:
{
struct nlattr *tb_vendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
(struct nlattr *)mVendorData,mDataLen, NULL);
if (tb_vendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS]) {
u32 val;
val = nla_get_u32(
tb_vendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS]);
ALOGD("%s: Num channels : %d", __func__, val);
val = val > (unsigned int)mMaxChannels ?
(unsigned int)mMaxChannels : val;
*mNumChannelsPtr = val;
/* Extract the list of channels. */
if (*mNumChannelsPtr > 0 &&
tb_vendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS]) {
nla_memcpy(mChannels,
tb_vendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS],
sizeof(wifi_channel) * (*mNumChannelsPtr));
}
ALOGD("%s: Get valid channels response received.",
__func__);
ALOGD("%s: Num channels : %d",
__func__, *mNumChannelsPtr);
ALOGD("%s: List of valid channels is: ", __func__);
for(i = 0; i < *mNumChannelsPtr; i++)
{
ALOGD("%u", *(mChannels + i));
}
}
}
break;
default :
ALOGE("%s: Wrong GScan subcmd response received %d",
__func__, mSubcmd);
}
return NL_SKIP;
}
/* Called to parse and extract cached results. */
static int gscan_get_cached_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;
ALOGE("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_get_cached_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_get_cached_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_get_cached_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_get_cached_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_get_cached_results: RESULTS_SCAN_RESULT_RSSI "
"not found");
return WIFI_ERROR_INVALID_ARGS;
}
results[i].rssi =
nla_get_u32(
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]);
if (!
tb2[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT
])
{
ALOGE("gscan_get_cached_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_get_cached_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]);
ALOGE("gscan_get_cached_results: ts %lld ", results[i].ts);
ALOGE("gscan_get_cached_results: SSID %s ", results[i].ssid);
ALOGE("gscan_get_cached_results: "
"BSSID: %02x:%02x:%02x:%02x:%02x:%02x \n",
results[i].bssid[0], results[i].bssid[1], results[i].bssid[2],
results[i].bssid[3], results[i].bssid[4], results[i].bssid[5]);
ALOGE("gscan_get_cached_results: channel %d ", results[i].channel);
ALOGE("gscan_get_cached_results: rssi %d ", results[i].rssi);
ALOGE("gscan_get_cached_results: rtt %lld ", results[i].rtt);
ALOGE("gscan_get_cached_results: rtt_sd %lld ", results[i].rtt_sd);
/* Increment loop index for next record */
i++;
}
ALOGE("%s: Exited the for loop", __func__);
return WIFI_SUCCESS;
}
/* This function will be the main handler for incoming (from driver) GSscan_SUBCMD.
* Calls the appropriate callback handler after parsing the vendor data.
*/
int GScanCommand::handleEvent(WifiEvent &event)
{
ALOGI("Got a GSCAN Event message from the Driver.");
unsigned i = 0;
u32 status;
int ret = WIFI_SUCCESS;
WifiVendorCommand::handleEvent(event);
struct nlattr *tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
nla_parse(tbVendor, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
(struct nlattr *)mVendorData,
mDataLen, NULL);
switch(mSubcmd)
{
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_START:
{
if (mStartGScanRspParams){
mStartGScanRspParams->status =
nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS]);
if (mHandler.start)
(*mHandler.start)(mStartGScanRspParams->status);
}
waitForRsp(false);
}
break;
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_STOP:
{
if (mStopGScanRspParams){
mStopGScanRspParams->status =
nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS]);
if (mHandler.stop)
(*mHandler.stop)(mStopGScanRspParams->status);
}
waitForRsp(false);
}
break;
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST:
{
if (mSetBssidHotlistRspParams){
mSetBssidHotlistRspParams->status =
nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS]);
if (mHandler.set_bssid_hotlist)
(*mHandler.set_bssid_hotlist)
(mSetBssidHotlistRspParams->status);
}
waitForRsp(false);
}
break;
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_BSSID_HOTLIST:
{
if (mResetBssidHotlistRspParams){
mResetBssidHotlistRspParams->status =
nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS]);
if (mHandler.reset_bssid_hotlist)
(*mHandler.reset_bssid_hotlist)
(mResetBssidHotlistRspParams->status);
}
waitForRsp(false);
}
break;
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE:
{
if (mSetSignificantChangeRspParams){
mSetSignificantChangeRspParams->status =
nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS]);
if (mHandler.set_significant_change)
(*mHandler.set_significant_change)
(mSetSignificantChangeRspParams->status);
}
waitForRsp(false);
}
break;
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SIGNIFICANT_CHANGE:
{
if (mResetSignificantChangeRspParams){
mResetSignificantChangeRspParams->status =
nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS]);
if (mHandler.reset_significant_change)
(*mHandler.reset_significant_change)
(mResetSignificantChangeRspParams->status);
}
waitForRsp(false);
}
break;
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CAPABILITIES:
{
if (!mGetCapabilitiesRspParams){
ALOGE("%s: mGetCapabilitiesRspParams ptr is NULL. Exit. ",
__func__);
break;
}
if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS]) {
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS "
"not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
}
mGetCapabilitiesRspParams->status =
nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS]);
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE
]) {
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_"
"CAPABILITIES_MAX_SCAN_CACHE_SIZE not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
}
mGetCapabilitiesRspParams->capabilities.max_scan_cache_size =
nla_get_u32(tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE]);
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS
]) {
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX"
"_SCAN_BUCKETS not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
}
mGetCapabilitiesRspParams->capabilities.max_scan_buckets =
nla_get_u32(tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS]
);
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN
]) {
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX"
"_AP_CACHE_PER_SCAN not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
}
mGetCapabilitiesRspParams->capabilities.max_ap_cache_per_scan =
nla_get_u32(tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN]);
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE
]) {
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX"
"_RSSI_SAMPLE_SIZE not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
}
mGetCapabilitiesRspParams->capabilities.max_rssi_sample_size =
nla_get_u32(tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE]);
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD
]) {
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_"
"MAX_SCAN_REPORTING_THRESHOLD not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
}
mGetCapabilitiesRspParams->capabilities.max_scan_reporting_threshold =
nla_get_u32(tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD
]);
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_APS
]) {
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_"
"MAX_HOTLIST_APS not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
}
mGetCapabilitiesRspParams->capabilities.max_hotlist_aps =
nla_get_u32(tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_APS]);
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS
]) {
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX"
"_SIGNIFICANT_WIFI_CHANGE_APS not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
}
mGetCapabilitiesRspParams->capabilities.max_significant_wifi_change_aps =
nla_get_u32(tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS]);
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES
]) {
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX"
"_BSSID_HISTORY_ENTRIES not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
}
mGetCapabilitiesRspParams->capabilities.max_bssid_history_entries =
nla_get_u32(tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES
]);
/* Call the call back handler func. */
if (mHandler.get_capabilities)
(*mHandler.get_capabilities)
(mGetCapabilitiesRspParams->status,
mGetCapabilitiesRspParams->capabilities);
waitForRsp(false);
}
break;
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS:
{
wifi_request_id id;
u32 resultsBufSize = 0;
u32 numResults = 0;
u32 startingIndex, sizeOfObtainedScanResults;
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) {
ALOGE("%s: GSCAN_RESULTS_REQUEST_ID not"
"found", __func__);
break;
}
id = nla_get_u32(
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]
);
ALOGE("%s: Event has Req. ID:%d, ours:%d",
__func__, id, mRequestId);
/* If this is not for us, just ignore it. */
if (id != mRequestId) {
ALOGE("%s: Event has Req. ID:%d <> ours:%d",
__func__, id, mRequestId);
break;
}
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) {
ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not"
"found", __func__);
break;
}
numResults = nla_get_u32(tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]);
ALOGE("%s: number of results:%d", __func__,
numResults);
if (!mGetCachedResultsRspParams) {
ALOGE("%s: mGetCachedResultsRspParams is NULL, exit.",
__func__);
break;
}
/* Get the memory size of previous fragments, if any. */
sizeOfObtainedScanResults = mGetCachedResultsNumResults *
sizeof(wifi_scan_result);
mGetCachedResultsNumResults += numResults;
resultsBufSize += mGetCachedResultsNumResults *
sizeof(wifi_scan_result);
/* Check if this chunck of cached scan results is a continuation of
* a previous one, i.e., a new results fragment.
*/
if (mGetCachedResultsRspParams->more_data) {
mGetCachedResultsRspParams->results = (wifi_scan_result *)
realloc (mGetCachedResultsRspParams->results,
resultsBufSize);
} else {
mGetCachedResultsRspParams->results = (wifi_scan_result *)
malloc (resultsBufSize);
}
ALOGE("%s: Total num of cached results received: %d. \n",
__func__, mGetCachedResultsNumResults);
if (!mGetCachedResultsRspParams->results) {
ALOGE("%s: Failed to alloc memory for results array. Exit.\n",
__func__);
ret = WIFI_ERROR_OUT_OF_MEMORY;
break;
}
ALOGD("(u8 *)mGetCachedResultsRspParams->results : %p "
"resultsBufSize :%d oldSizeResults : %d . \n",
(u8 *)mGetCachedResultsRspParams->results,
resultsBufSize, sizeOfObtainedScanResults);
/* Initialize the newly allocated memory area with 0. */
memset((u8 *)mGetCachedResultsRspParams->results +
sizeOfObtainedScanResults,
0,
resultsBufSize - sizeOfObtainedScanResults);
/* To support fragmentation from firmware, monitor the
* MORE_DTATA flag and cache results until MORE_DATA = 0.
*/
if (!tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) {
ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA "
"not found", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
break;
} else {
mGetCachedResultsRspParams->more_data = nla_get_u8(
tbVendor[
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]);
ALOGE("%s: More data = %d. \n", __func__,
mGetCachedResultsRspParams->more_data);
}
mGetCachedResultsRspParams->num_results =
mGetCachedResultsNumResults;
if (numResults) {
ALOGD("%s: Extract cached results received.\n", __func__);
startingIndex =
mGetCachedResultsNumResults - numResults;
ALOGD("%s: starting_index:%d",
__func__, startingIndex);
ret = gscan_get_cached_results(numResults,
mGetCachedResultsRspParams->results,
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 (mHandler.get_cached_results) {
(*mHandler.get_cached_results)
(mGetCachedResultsRspParams->more_data,
mGetCachedResultsRspParams->num_results);
}
waitForRsp(false);
}
break;
default:
/* Error case should not happen print log */
ALOGE("%s: Wrong GScan subcmd received %d", __func__, mSubcmd);
}
/* A parsing error occurred, do the cleanup of gscan result lists. */
if (ret) {
switch(mSubcmd)
{
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS:
{
freeRspParams(eGScanGetCachedResultsRspParams);
}
break;
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CAPABILITIES:
break;
default:
ALOGE("%s: Wrong GScan subcmd received %d", __func__, mSubcmd);
}
}
return NL_SKIP;
}
int GScanCommand::setCallbackHandler(GScanCallbackHandler nHandler)
{
int res = 0;
mHandler = nHandler;
res = registerVendorHandler(mVendor_id, mSubcmd);
if (res != 0) {
/* Error case: should not happen, so print a log when it does. */
ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
__func__, mVendor_id, mSubcmd);
}
return res;
}
/*
* Allocates memory for the subCmd response struct and initializes status = -1
*/
int GScanCommand::allocRspParams(eGScanRspRarams cmd)
{
int ret = 0;
switch(cmd)
{
case eGScanStartRspParams:
mStartGScanRspParams = (GScanStartRspParams *)
malloc(sizeof(GScanStartRspParams));
if (!mStartGScanRspParams)
ret = -1;
else
mStartGScanRspParams->status = -1;
break;
case eGScanStopRspParams:
mStopGScanRspParams = (GScanStopRspParams *)
malloc(sizeof(GScanStopRspParams));
if (!mStopGScanRspParams)
ret = -1;
else
mStopGScanRspParams->status = -1;
break;
case eGScanSetBssidHotlistRspParams:
mSetBssidHotlistRspParams = (GScanSetBssidHotlistRspParams *)
malloc(sizeof(GScanSetBssidHotlistRspParams));
if (!mSetBssidHotlistRspParams)
ret = -1;
else
mSetBssidHotlistRspParams->status = -1;
break;
case eGScanResetBssidHotlistRspParams:
mResetBssidHotlistRspParams = (GScanResetBssidHotlistRspParams *)
malloc(sizeof(GScanResetBssidHotlistRspParams));
if (!mResetBssidHotlistRspParams)
ret = -1;
else
mResetBssidHotlistRspParams->status = -1;
break;
case eGScanSetSignificantChangeRspParams:
mSetSignificantChangeRspParams =
(GScanSetSignificantChangeRspParams *)
malloc(sizeof(GScanSetSignificantChangeRspParams));
if (!mSetSignificantChangeRspParams)
ret = -1;
else
mSetSignificantChangeRspParams->status = -1;
break;
case eGScanResetSignificantChangeRspParams:
mResetSignificantChangeRspParams =
(GScanResetSignificantChangeRspParams *)
malloc(sizeof(GScanResetSignificantChangeRspParams));
if (!mResetSignificantChangeRspParams)
ret = -1;
else
mResetSignificantChangeRspParams->status = -1;
break;
case eGScanGetCapabilitiesRspParams:
mGetCapabilitiesRspParams = (GScanGetCapabilitiesRspParams *)
malloc(sizeof(GScanGetCapabilitiesRspParams));
if (!mGetCapabilitiesRspParams)
ret = -1;
else {
memset(&mGetCapabilitiesRspParams->capabilities, 0,
sizeof(wifi_gscan_capabilities));
mGetCapabilitiesRspParams->status = -1;
}
break;
case eGScanGetCachedResultsRspParams:
mGetCachedResultsRspParams = (GScanGetCachedResultsRspParams *)
malloc(sizeof(GScanGetCachedResultsRspParams));
if (!mGetCachedResultsRspParams)
ret = -1;
else {
mGetCachedResultsRspParams->num_results = 0;
mGetCachedResultsRspParams->more_data = false;
mGetCachedResultsRspParams->results = NULL;
}
break;
default:
ALOGD("%s: Wrong request for alloc.", __func__);
ret = -1;
}
return ret;
}
void GScanCommand::freeRspParams(eGScanRspRarams cmd)
{
switch(cmd)
{
case eGScanStartRspParams:
if (mStartGScanRspParams) {
free(mStartGScanRspParams);
mStartGScanRspParams = NULL;
}
break;
case eGScanStopRspParams:
if (mStopGScanRspParams) {
free(mStopGScanRspParams);
mStopGScanRspParams = NULL;
}
break;
case eGScanSetBssidHotlistRspParams:
if (mSetBssidHotlistRspParams) {
free(mSetBssidHotlistRspParams);
mSetBssidHotlistRspParams = NULL;
}
break;
case eGScanResetBssidHotlistRspParams:
if (mResetBssidHotlistRspParams) {
free(mResetBssidHotlistRspParams);
mResetBssidHotlistRspParams = NULL;
}
break;
case eGScanSetSignificantChangeRspParams:
if (mSetSignificantChangeRspParams) {
free(mSetSignificantChangeRspParams);
mSetSignificantChangeRspParams = NULL;
}
break;
case eGScanResetSignificantChangeRspParams:
if (mResetSignificantChangeRspParams) {
free(mResetSignificantChangeRspParams);
mResetSignificantChangeRspParams = NULL;
}
break;
case eGScanGetCapabilitiesRspParams:
if (mGetCapabilitiesRspParams) {
free(mGetCapabilitiesRspParams);
mGetCapabilitiesRspParams = NULL;
}
break;
case eGScanGetCachedResultsRspParams:
if (mGetCachedResultsRspParams) {
if (mGetCachedResultsRspParams->results) {
free(mGetCachedResultsRspParams->results);
mGetCachedResultsRspParams->results = NULL;
}
free(mGetCachedResultsRspParams);
mGetCachedResultsRspParams = NULL;
}
break;
default:
ALOGD("%s: Wrong request for free.", __func__);
}
}
wifi_error GScanCommand::getGetCachedResultsRspParams(
int max,
u8 *moreData,
int *numResults,
wifi_scan_result *results)
{
wifi_error ret = WIFI_SUCCESS;
if (mGetCachedResultsRspParams && results)
{
*moreData = mGetCachedResultsRspParams->more_data;
*numResults = mGetCachedResultsRspParams->num_results > (unsigned int)max ?
max : mGetCachedResultsRspParams->num_results;
memcpy(results,
mGetCachedResultsRspParams->results,
*numResults * sizeof(wifi_scan_result));
} else {
ALOGD("%s: mGetCachedResultsRspParams is NULL", __func__);
ret = WIFI_ERROR_INVALID_ARGS;
}
return ret;
}
void GScanCommand::getGetCapabilitiesRspParams(
wifi_gscan_capabilities *capabilities,
u32 *status)
{
if (mGetCapabilitiesRspParams && capabilities)
{
*status = mGetCapabilitiesRspParams->status;
memcpy(capabilities,
&mGetCapabilitiesRspParams->capabilities,
sizeof(wifi_gscan_capabilities));
} else {
ALOGD("%s: mGetCapabilitiesRspParams is NULL", __func__);
}
}
void GScanCommand::getStartGScanRspParams(u32 *status)
{
if (mStartGScanRspParams)
{
*status = mStartGScanRspParams->status;
} else {
ALOGD("%s: mStartGScanRspParams is NULL", __func__);
}
}
void GScanCommand::getStopGScanRspParams(u32 *status)
{
if (mStopGScanRspParams)
{
*status = mStopGScanRspParams->status;
} else {
ALOGD("%s: mStopGScanRspParams is NULL", __func__);
}
}
void GScanCommand::getSetBssidHotlistRspParams(u32 *status)
{
if (mSetBssidHotlistRspParams)
{
*status = mSetBssidHotlistRspParams->status;
} else {
ALOGD("%s: mSetBssidHotlistRspParams is NULL", __func__);
}
}
void GScanCommand::getResetBssidHotlistRspParams(u32 *status)
{
if (mResetBssidHotlistRspParams)
{
*status = mResetBssidHotlistRspParams->status;
} else {
ALOGD("%s: mResetBssidHotlistRspParams is NULL", __func__);
}
}
void GScanCommand::getSetSignificantChangeRspParams(u32 *status)
{
if (mSetSignificantChangeRspParams)
{
*status = mSetSignificantChangeRspParams->status;
} else {
ALOGD("%s: mSetSignificantChangeRspParams is NULL", __func__);
}
}
void GScanCommand::getResetSignificantChangeRspParams(u32 *status)
{
if (mResetSignificantChangeRspParams)
{
*status = mResetSignificantChangeRspParams->status;
} else {
ALOGD("%s: mResetSignificantChangeRspParams is NULL", __func__);
}
}
int GScanCommand::timed_wait(u16 wait_time)
{
struct timespec absTime;
int res;
absTime.tv_sec = wait_time;
absTime.tv_nsec = 0;
return mCondition.wait(absTime);
}
void GScanCommand::waitForRsp(bool wait)
{
mWaitforRsp = wait;
}
void GScanCommand::setMaxChannels(int max_channels) {
mMaxChannels = max_channels;
}
void GScanCommand::setChannels(int *channels) {
mChannels = channels;
}
void GScanCommand::setNumChannelsPtr(int *num_channels) {
mNumChannelsPtr = num_channels;
}