2293 lines
84 KiB
C++
2293 lines
84 KiB
C++
/*
|
|
* 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 <errno.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "common.h"
|
|
#include "cpp_bindings.h"
|
|
#include "gscancommand.h"
|
|
#include "gscan_event_handler.h"
|
|
#include "vendor_definitions.h"
|
|
|
|
#define GSCAN_EVENT_WAIT_TIME_SECONDS 4
|
|
#define WIFI_SCANNING_MAC_OUI_LENGTH 3
|
|
#define EPNO_NO_NETWORKS 0
|
|
|
|
/* BSSID blacklist */
|
|
typedef struct {
|
|
int num_bssid; // number of blacklisted BSSIDs
|
|
mac_addr bssids[MAX_BLACKLIST_BSSID]; // blacklisted BSSIDs
|
|
} wifi_bssid_params;
|
|
|
|
/* Used to handle gscan command events from driver/firmware.*/
|
|
typedef struct gscan_event_handlers_s {
|
|
GScanCommandEventHandler *gscanStartCmdEventHandler;
|
|
GScanCommandEventHandler *gScanSetBssidHotlistCmdEventHandler;
|
|
GScanCommandEventHandler *gScanSetSignificantChangeCmdEventHandler;
|
|
GScanCommandEventHandler *gScanSetSsidHotlistCmdEventHandler;
|
|
GScanCommandEventHandler *gScanSetPnoListCmdEventHandler;
|
|
GScanCommandEventHandler *gScanPnoSetPasspointListCmdEventHandler;
|
|
} gscan_event_handlers;
|
|
|
|
wifi_error initializeGscanHandlers(hal_info *info)
|
|
{
|
|
info->gscan_handlers = (gscan_event_handlers *)malloc(sizeof(gscan_event_handlers));
|
|
if (info->gscan_handlers) {
|
|
memset(info->gscan_handlers, 0, sizeof(gscan_event_handlers));
|
|
}
|
|
else {
|
|
ALOGE("%s: Allocation of gscan event handlers failed",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return WIFI_SUCCESS;
|
|
}
|
|
|
|
wifi_error cleanupGscanHandlers(hal_info *info)
|
|
{
|
|
gscan_event_handlers* event_handlers;
|
|
if (info && info->gscan_handlers) {
|
|
event_handlers = (gscan_event_handlers*) info->gscan_handlers;
|
|
if (event_handlers->gscanStartCmdEventHandler) {
|
|
delete event_handlers->gscanStartCmdEventHandler;
|
|
}
|
|
if (event_handlers->gScanSetBssidHotlistCmdEventHandler) {
|
|
delete event_handlers->gScanSetBssidHotlistCmdEventHandler;
|
|
}
|
|
if (event_handlers->gScanSetSignificantChangeCmdEventHandler) {
|
|
delete event_handlers->gScanSetSignificantChangeCmdEventHandler;
|
|
}
|
|
if (event_handlers->gScanSetSsidHotlistCmdEventHandler) {
|
|
delete event_handlers->gScanSetSsidHotlistCmdEventHandler;
|
|
}
|
|
if (event_handlers->gScanSetPnoListCmdEventHandler) {
|
|
delete event_handlers->gScanSetPnoListCmdEventHandler;
|
|
}
|
|
if (event_handlers->gScanPnoSetPasspointListCmdEventHandler) {
|
|
delete event_handlers->gScanPnoSetPasspointListCmdEventHandler;
|
|
}
|
|
memset(event_handlers, 0, sizeof(gscan_event_handlers));
|
|
free(info->gscan_handlers);
|
|
info->gscan_handlers = NULL;
|
|
return WIFI_SUCCESS;
|
|
}
|
|
ALOGE ("%s: info or info->gscan_handlers NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* 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;
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData;
|
|
interface_info *ifaceInfo = getIfaceInfo(handle);
|
|
wifi_handle wifiHandle = getWifiHandle(handle);
|
|
|
|
/* No request id from caller, so generate one and pass it on to the driver.
|
|
* Generate one randomly.
|
|
*/
|
|
requestId = get_requestid();
|
|
ALOGV("%s: RequestId:%d band:%d max_channels:%d", __FUNCTION__,
|
|
requestId, band, max_channels);
|
|
|
|
if (channels == NULL) {
|
|
ALOGE("%s: NULL channels pointer provided. Exit.",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
|
|
gScanCommand = new GScanCommand(
|
|
wifiHandle,
|
|
requestId,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS);
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
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 != WIFI_SUCCESS)
|
|
ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
return ret;
|
|
}
|
|
|
|
wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
|
|
wifi_gscan_capabilities *capabilities)
|
|
{
|
|
wifi_handle wifiHandle = getWifiHandle(handle);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
|
|
ALOGE("%s: GSCAN is not supported by driver", __FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (capabilities == NULL) {
|
|
ALOGE("%s: NULL capabilities pointer provided. Exit.", __FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
|
|
memcpy(capabilities, &info->capa.gscan_capa, sizeof(wifi_gscan_capabilities));
|
|
|
|
return WIFI_SUCCESS;
|
|
}
|
|
|
|
wifi_error wifi_start_gscan(wifi_request_id id,
|
|
wifi_interface_handle iface,
|
|
wifi_scan_cmd_params params,
|
|
wifi_scan_result_handler handler)
|
|
{
|
|
wifi_error ret;
|
|
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;
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
gscan_event_handlers* event_handlers;
|
|
GScanCommandEventHandler *gScanStartCmdEventHandler;
|
|
|
|
event_handlers = (gscan_event_handlers*)info->gscan_handlers;
|
|
gScanStartCmdEventHandler = event_handlers->gscanStartCmdEventHandler;
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
|
|
ALOGE("%s: GSCAN is not supported by driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
ALOGV("%s: RequestId:%d ", __FUNCTION__, id);
|
|
/* Wi-Fi HAL doesn't need to check if a similar request to start gscan was
|
|
* made earlier. If start_gscan() is called while another gscan is already
|
|
* running, the request will be sent down to driver and firmware. If new
|
|
* request is successfully honored, then Wi-Fi HAL will use the new request
|
|
* id for the gScanStartCmdEventHandler object.
|
|
*/
|
|
gScanCommand = new GScanCommand(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_START);
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
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;
|
|
|
|
ALOGV("%s: Base Period:%d Max_ap_per_scan:%d "
|
|
"Threshold_percent:%d Threshold_num_scans:%d "
|
|
"num_buckets:%d", __FUNCTION__, params.base_period,
|
|
params.max_ap_per_scan, params.report_threshold_percent,
|
|
params.report_threshold_num_scans, num_scan_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_PERCENT,
|
|
params.report_threshold_percent) ||
|
|
gScanCommand->put_u8(
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS,
|
|
params.report_threshold_num_scans) ||
|
|
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;
|
|
|
|
ALOGV("%s: Index: %d Bucket Id:%d Band:%d Period:%d ReportEvent:%d "
|
|
"numChannelSpecs:%d max_period:%d base:%d step_count:%d",
|
|
__FUNCTION__, i, bucketSpec.bucket, bucketSpec.band,
|
|
bucketSpec.period, bucketSpec.report_events,
|
|
numChannelSpecs, bucketSpec.max_period,
|
|
bucketSpec.base, bucketSpec.step_count);
|
|
|
|
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) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_MAX_PERIOD,
|
|
bucketSpec.max_period) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BASE,
|
|
bucketSpec.base) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_STEP_COUNT,
|
|
bucketSpec.step_count))
|
|
{
|
|
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];
|
|
|
|
ALOGV("%s: Channel Spec Index:%d Channel:%d Dwell Time:%d "
|
|
"passive:%d", __FUNCTION__, j, channel_spec.channel,
|
|
channel_spec.dwellTimeMs, channel_spec.passive);
|
|
|
|
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);
|
|
|
|
/* Set the callback handler functions for related events. */
|
|
GScanCallbackHandler callbackHandler;
|
|
memset(&callbackHandler, 0, sizeof(callbackHandler));
|
|
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. */
|
|
if (gScanStartCmdEventHandler == NULL) {
|
|
gScanStartCmdEventHandler = new GScanCommandEventHandler(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_START,
|
|
callbackHandler);
|
|
if (gScanStartCmdEventHandler == NULL) {
|
|
ALOGE("%s: Error gScanStartCmdEventHandler NULL", __FUNCTION__);
|
|
ret = WIFI_ERROR_UNKNOWN;
|
|
goto cleanup;
|
|
}
|
|
event_handlers->gscanStartCmdEventHandler = gScanStartCmdEventHandler;
|
|
} else {
|
|
gScanStartCmdEventHandler->setCallbackHandler(callbackHandler);
|
|
}
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s : requestResponse Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (gScanStartCmdEventHandler != NULL) {
|
|
gScanStartCmdEventHandler->set_request_id(id);
|
|
gScanStartCmdEventHandler->enableEventHandling();
|
|
}
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
/* Disable Event Handling if ret != 0 */
|
|
if ((ret != WIFI_SUCCESS) && gScanStartCmdEventHandler) {
|
|
ALOGI("%s: Error ret:%d, disable event handling",
|
|
__FUNCTION__, ret);
|
|
gScanStartCmdEventHandler->disableEventHandling();
|
|
}
|
|
return ret;
|
|
|
|
}
|
|
|
|
wifi_error wifi_stop_gscan(wifi_request_id id,
|
|
wifi_interface_handle iface)
|
|
{
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData;
|
|
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
gscan_event_handlers* event_handlers;
|
|
GScanCommandEventHandler *gScanStartCmdEventHandler;
|
|
|
|
event_handlers = (gscan_event_handlers*)info->gscan_handlers;
|
|
gScanStartCmdEventHandler = event_handlers->gscanStartCmdEventHandler;
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
|
|
ALOGE("%s: GSCAN is not supported by driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (gScanStartCmdEventHandler == NULL ||
|
|
gScanStartCmdEventHandler->isEventHandlingEnabled() == false) {
|
|
ALOGE("%s: GSCAN isn't running or already stopped. "
|
|
"Nothing to do. Exit", __FUNCTION__);
|
|
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", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
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 != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
|
|
/* Disable Event Handling. */
|
|
if (gScanStartCmdEventHandler) {
|
|
gScanStartCmdEventHandler->disableEventHandling();
|
|
}
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* 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;
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData, *nlApThresholdParamList;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
gscan_event_handlers* event_handlers;
|
|
GScanCommandEventHandler *gScanSetBssidHotlistCmdEventHandler;
|
|
|
|
event_handlers = (gscan_event_handlers*)info->gscan_handlers;
|
|
gScanSetBssidHotlistCmdEventHandler =
|
|
event_handlers->gScanSetBssidHotlistCmdEventHandler;
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
|
|
ALOGE("%s: GSCAN is not supported by driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
/* Wi-Fi HAL doesn't need to check if a similar request to set bssid
|
|
* hotlist was made earlier. If set_bssid_hotlist() is called while
|
|
* another one is running, the request will be sent down to driver and
|
|
* firmware. If the new request is successfully honored, then Wi-Fi HAL
|
|
* will use the new request id for the gScanSetBssidHotlistCmdEventHandler
|
|
* object.
|
|
*/
|
|
|
|
gScanCommand =
|
|
new GScanCommand(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST);
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
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_bssid > MAX_HOTLIST_APS ?
|
|
MAX_HOTLIST_APS : params.num_bssid;
|
|
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_LOST_AP_SAMPLE_SIZE,
|
|
params.lost_ap_sample_size) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_NUM_AP,
|
|
numAp))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
ALOGV("%s: lost_ap_sample_size:%d numAp:%d", __FUNCTION__,
|
|
params.lost_ap_sample_size, numAp);
|
|
/* 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))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
ALOGV("%s: Index:%d BssId: %hhx:%hhx:%hhx:%hhx:%hhx:%hhx "
|
|
"Threshold low:%d high:%d", __FUNCTION__, i,
|
|
apThreshold.bssid[0], apThreshold.bssid[1],
|
|
apThreshold.bssid[2], apThreshold.bssid[3],
|
|
apThreshold.bssid[4], apThreshold.bssid[5],
|
|
apThreshold.low, apThreshold.high);
|
|
gScanCommand->attr_end(nlApThresholdParam);
|
|
}
|
|
|
|
gScanCommand->attr_end(nlApThresholdParamList);
|
|
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
GScanCallbackHandler callbackHandler;
|
|
memset(&callbackHandler, 0, sizeof(callbackHandler));
|
|
callbackHandler.on_hotlist_ap_found = handler.on_hotlist_ap_found;
|
|
callbackHandler.on_hotlist_ap_lost = handler.on_hotlist_ap_lost;
|
|
|
|
/* Create an object of the event handler class to take care of the
|
|
* asychronous events on the north-bound.
|
|
*/
|
|
if (gScanSetBssidHotlistCmdEventHandler == NULL) {
|
|
gScanSetBssidHotlistCmdEventHandler = new GScanCommandEventHandler(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST,
|
|
callbackHandler);
|
|
if (gScanSetBssidHotlistCmdEventHandler == NULL) {
|
|
ALOGE("%s: Error instantiating "
|
|
"gScanSetBssidHotlistCmdEventHandler.", __FUNCTION__);
|
|
ret = WIFI_ERROR_UNKNOWN;
|
|
goto cleanup;
|
|
}
|
|
event_handlers->gScanSetBssidHotlistCmdEventHandler =
|
|
gScanSetBssidHotlistCmdEventHandler;
|
|
} else {
|
|
gScanSetBssidHotlistCmdEventHandler->setCallbackHandler(callbackHandler);
|
|
}
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (gScanSetBssidHotlistCmdEventHandler != NULL) {
|
|
gScanSetBssidHotlistCmdEventHandler->set_request_id(id);
|
|
gScanSetBssidHotlistCmdEventHandler->enableEventHandling();
|
|
}
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
/* Disable Event Handling if ret != 0 */
|
|
if ((ret != WIFI_SUCCESS) && gScanSetBssidHotlistCmdEventHandler) {
|
|
ALOGI("%s: Error ret:%d, disable event handling",
|
|
__FUNCTION__, ret);
|
|
gScanSetBssidHotlistCmdEventHandler->disableEventHandling();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
wifi_error wifi_reset_bssid_hotlist(wifi_request_id id,
|
|
wifi_interface_handle iface)
|
|
{
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
gscan_event_handlers* event_handlers;
|
|
GScanCommandEventHandler *gScanSetBssidHotlistCmdEventHandler;
|
|
|
|
event_handlers = (gscan_event_handlers*)info->gscan_handlers;
|
|
gScanSetBssidHotlistCmdEventHandler =
|
|
event_handlers->gScanSetBssidHotlistCmdEventHandler;
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
|
|
ALOGE("%s: GSCAN is not supported by driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (gScanSetBssidHotlistCmdEventHandler == NULL ||
|
|
(gScanSetBssidHotlistCmdEventHandler->isEventHandlingEnabled() ==
|
|
false)) {
|
|
ALOGE("wifi_reset_bssid_hotlist: GSCAN bssid_hotlist isn't set. "
|
|
"Nothing to do. Exit");
|
|
return WIFI_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
gScanCommand = new GScanCommand(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_BSSID_HOTLIST);
|
|
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
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 != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
|
|
/* Disable Event Handling. */
|
|
if (gScanSetBssidHotlistCmdEventHandler) {
|
|
gScanSetBssidHotlistCmdEventHandler->disableEventHandling();
|
|
}
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* 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;
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData, *nlApThresholdParamList;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
gscan_event_handlers* event_handlers;
|
|
GScanCommandEventHandler *gScanSetSignificantChangeCmdEventHandler;
|
|
|
|
event_handlers = (gscan_event_handlers*)info->gscan_handlers;
|
|
gScanSetSignificantChangeCmdEventHandler =
|
|
event_handlers->gScanSetSignificantChangeCmdEventHandler;
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
|
|
ALOGE("%s: GSCAN is not supported by driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
/* Wi-Fi HAL doesn't need to check if a similar request to set significant
|
|
* change list was made earlier. If set_significant_change() is called while
|
|
* another one is running, the request will be sent down to driver and
|
|
* firmware. If the new request is successfully honored, then Wi-Fi HAL
|
|
* will use the new request id for the gScanSetSignificantChangeCmdEventHandler
|
|
* object.
|
|
*/
|
|
|
|
gScanCommand = new GScanCommand(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE);
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
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_bssid > MAX_SIGNIFICANT_CHANGE_APS ?
|
|
MAX_SIGNIFICANT_CHANGE_APS : params.num_bssid;
|
|
|
|
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;
|
|
}
|
|
|
|
ALOGV("%s: Number of AP params:%d Rssi_sample_size:%d "
|
|
"lost_ap_sample_size:%d min_breaching:%d", __FUNCTION__,
|
|
numAp, params.rssi_sample_size, params.lost_ap_sample_size,
|
|
params.min_breaching);
|
|
|
|
/* 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))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
ALOGV("%s: ap[%d].bssid:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx "
|
|
"ap[%d].low:%d ap[%d].high:%d", __FUNCTION__,
|
|
i,
|
|
apThreshold.bssid[0], apThreshold.bssid[1],
|
|
apThreshold.bssid[2], apThreshold.bssid[3],
|
|
apThreshold.bssid[4], apThreshold.bssid[5],
|
|
i, apThreshold.low, i, apThreshold.high);
|
|
gScanCommand->attr_end(nlApThresholdParam);
|
|
}
|
|
|
|
gScanCommand->attr_end(nlApThresholdParamList);
|
|
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
GScanCallbackHandler callbackHandler;
|
|
memset(&callbackHandler, 0, sizeof(callbackHandler));
|
|
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.
|
|
*/
|
|
if (gScanSetSignificantChangeCmdEventHandler == NULL) {
|
|
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.",
|
|
__FUNCTION__);
|
|
ret = WIFI_ERROR_UNKNOWN;
|
|
goto cleanup;
|
|
}
|
|
event_handlers->gScanSetSignificantChangeCmdEventHandler =
|
|
gScanSetSignificantChangeCmdEventHandler;
|
|
} else {
|
|
gScanSetSignificantChangeCmdEventHandler->setCallbackHandler(callbackHandler);
|
|
}
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (gScanSetSignificantChangeCmdEventHandler != NULL) {
|
|
gScanSetSignificantChangeCmdEventHandler->set_request_id(id);
|
|
gScanSetSignificantChangeCmdEventHandler->enableEventHandling();
|
|
}
|
|
|
|
cleanup:
|
|
/* Disable Event Handling if ret != 0 */
|
|
if ((ret != WIFI_SUCCESS) && gScanSetSignificantChangeCmdEventHandler) {
|
|
ALOGI("%s: Error ret:%d, disable event handling",
|
|
__FUNCTION__, ret);
|
|
gScanSetSignificantChangeCmdEventHandler->disableEventHandling();
|
|
}
|
|
delete gScanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Clear the GSCAN Significant AP change list. */
|
|
wifi_error wifi_reset_significant_change_handler(wifi_request_id id,
|
|
wifi_interface_handle iface)
|
|
{
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
gscan_event_handlers* event_handlers;
|
|
GScanCommandEventHandler *gScanSetSignificantChangeCmdEventHandler;
|
|
|
|
event_handlers = (gscan_event_handlers*)info->gscan_handlers;
|
|
gScanSetSignificantChangeCmdEventHandler =
|
|
event_handlers->gScanSetSignificantChangeCmdEventHandler;
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
|
|
ALOGE("%s: GSCAN is not supported by driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (gScanSetSignificantChangeCmdEventHandler == NULL ||
|
|
(gScanSetSignificantChangeCmdEventHandler->isEventHandlingEnabled() ==
|
|
false)) {
|
|
ALOGE("wifi_reset_significant_change_handler: GSCAN significant_change"
|
|
" isn't set. Nothing to do. Exit");
|
|
return WIFI_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
gScanCommand =
|
|
new GScanCommand
|
|
(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SIGNIFICANT_CHANGE);
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
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 != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
|
|
/* Disable Event Handling. */
|
|
if (gScanSetSignificantChangeCmdEventHandler) {
|
|
gScanSetSignificantChangeCmdEventHandler->disableEventHandling();
|
|
}
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Get the GSCAN cached scan results. */
|
|
wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface,
|
|
byte flush, int max,
|
|
wifi_cached_scan_results *results,
|
|
int *num)
|
|
{
|
|
int requestId, retRequestRsp = 0;
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData;
|
|
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
|
|
ALOGE("%s: GSCAN is not supported by driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
/* No request id from caller, so generate one and pass it on to the driver. */
|
|
/* Generate it randomly */
|
|
requestId = get_requestid();
|
|
|
|
if (results == NULL || num == NULL) {
|
|
ALOGE("%s: NULL pointer provided. Exit.",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
|
|
gScanCommand = new GScanCommand(
|
|
wifiHandle,
|
|
requestId,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS);
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ret = gScanCommand->allocRspParams(eGScanGetCachedResultsRspParams);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to allocate memory for response struct. Error:%d",
|
|
__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = gScanCommand->allocCachedResultsTemp(max, results);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to allocate memory for temp gscan cached list. "
|
|
"Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Clear the destination cached results list before copying results. */
|
|
memset(results, 0, max * sizeof(wifi_cached_scan_results));
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
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_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;
|
|
}
|
|
|
|
ALOGV("%s: flush:%d max:%d", __FUNCTION__, flush, max);
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
retRequestRsp = gScanCommand->requestResponse();
|
|
if (retRequestRsp != 0) {
|
|
ALOGE("%s: requestResponse Error:%d",
|
|
__FUNCTION__, retRequestRsp);
|
|
/* It's possible to get ETIMEDOUT after receiving few results from
|
|
* driver. Copy and forward them to framework.
|
|
*/
|
|
if (retRequestRsp != -ETIMEDOUT) {
|
|
/* Proceed to cleanup & return no results */
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
/* No more data, copy the parsed results into the caller's results array */
|
|
ret = gScanCommand->copyCachedScanResults(num, results);
|
|
ALOGV("%s: max: %d, num:%d", __FUNCTION__, max, *num);
|
|
|
|
if (!ret) {
|
|
/* If requestResponse returned a TIMEOUT */
|
|
if (retRequestRsp == -ETIMEDOUT) {
|
|
if (*num > 0) {
|
|
/* Mark scan results as incomplete for the last scan_id */
|
|
results[(*num)-1].flags = WIFI_SCAN_FLAG_INTERRUPTED;
|
|
ALOGV("%s: Timeout happened. Mark scan results as incomplete "
|
|
"for scan_id:%d", __FUNCTION__, results[(*num)-1].scan_id);
|
|
ret = WIFI_SUCCESS;
|
|
} else
|
|
ret = WIFI_ERROR_TIMED_OUT;
|
|
}
|
|
}
|
|
cleanup:
|
|
gScanCommand->freeRspParams(eGScanGetCachedResultsRspParams);
|
|
delete gScanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Random MAC OUI for PNO */
|
|
wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)
|
|
{
|
|
wifi_error ret;
|
|
struct nlattr *nlData;
|
|
WifiVendorCommand *vCommand = NULL;
|
|
interface_info *iinfo = getIfaceInfo(handle);
|
|
wifi_handle wifiHandle = getWifiHandle(handle);
|
|
|
|
vCommand = new WifiVendorCommand(wifiHandle, 0,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI);
|
|
if (vCommand == NULL) {
|
|
ALOGE("%s: Error vCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
/* create the message */
|
|
ret = vCommand->create();
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
ret = vCommand->set_iface_id(iinfo->name);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData)
|
|
goto cleanup;
|
|
|
|
ALOGV("%s: MAC_OUI - %02x:%02x:%02x", __FUNCTION__,
|
|
scan_oui[0], scan_oui[1], scan_oui[2]);
|
|
|
|
/* Add the fixed part of the mac_oui to the nl command */
|
|
ret = vCommand->put_bytes(
|
|
QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI,
|
|
(char *)scan_oui,
|
|
WIFI_SCANNING_MAC_OUI_LENGTH);
|
|
if (ret != WIFI_SUCCESS)
|
|
goto cleanup;
|
|
|
|
vCommand->attr_end(nlData);
|
|
|
|
ret = vCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
delete vCommand;
|
|
return ret;
|
|
}
|
|
|
|
|
|
GScanCommand::GScanCommand(wifi_handle handle, int id, u32 vendor_id,
|
|
u32 subcmd)
|
|
: WifiVendorCommand(handle, id, vendor_id, subcmd)
|
|
{
|
|
/* Initialize the member data variables here */
|
|
mGetCachedResultsRspParams = NULL;
|
|
mChannels = NULL;
|
|
mMaxChannels = 0;
|
|
mNumChannelsPtr = NULL;
|
|
|
|
mRequestId = id;
|
|
memset(&mHandler, 0,sizeof(mHandler));
|
|
}
|
|
|
|
GScanCommand::~GScanCommand()
|
|
{
|
|
unregisterVendorHandler(mVendor_id, mSubcmd);
|
|
}
|
|
|
|
|
|
/* This function implements creation of Vendor command */
|
|
wifi_error GScanCommand::create() {
|
|
wifi_error ret;
|
|
|
|
ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
|
|
if (ret != WIFI_SUCCESS)
|
|
return ret;
|
|
|
|
/* Insert the oui in the msg */
|
|
ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
|
|
if (ret != WIFI_SUCCESS)
|
|
return ret;
|
|
|
|
/* Insert the subcmd in the msg */
|
|
ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
|
|
if (ret != WIFI_SUCCESS)
|
|
return ret;
|
|
|
|
ALOGV("%s: mVendor_id = %d, Subcmd = %d.",
|
|
__FUNCTION__, mVendor_id, mSubcmd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
wifi_error GScanCommand::requestResponse()
|
|
{
|
|
return WifiCommand::requestResponse(mMsg);
|
|
}
|
|
|
|
int GScanCommand::handleResponse(WifiEvent &reply)
|
|
{
|
|
int i = 0;
|
|
wifi_error ret = WIFI_SUCCESS;
|
|
u32 val;
|
|
|
|
WifiVendorCommand::handleResponse(reply);
|
|
|
|
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_GET_VALID_CHANNELS:
|
|
{
|
|
if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS]) {
|
|
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS"
|
|
" not found", __FUNCTION__);
|
|
ret = WIFI_ERROR_INVALID_ARGS;
|
|
break;
|
|
}
|
|
val = nla_get_u32(tbVendor[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS]);
|
|
|
|
val = val > (unsigned int)mMaxChannels ?
|
|
(unsigned int)mMaxChannels : val;
|
|
*mNumChannelsPtr = val;
|
|
|
|
/* Extract the list of channels. */
|
|
if (*mNumChannelsPtr > 0 ) {
|
|
if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS]) {
|
|
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS"
|
|
" not found", __FUNCTION__);
|
|
ret = WIFI_ERROR_INVALID_ARGS;
|
|
break;
|
|
}
|
|
nla_memcpy(mChannels,
|
|
tbVendor[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS],
|
|
sizeof(wifi_channel) * (*mNumChannelsPtr));
|
|
}
|
|
char buf[256];
|
|
size_t len = 0;
|
|
for (i = 0; i < *mNumChannelsPtr && len < sizeof(buf); i++) {
|
|
len += snprintf(buf + len, sizeof(buf) - len, "%u ",
|
|
*(mChannels + i));
|
|
}
|
|
ALOGV("%s: Num Channels %d: List of valid channels are: %s",
|
|
__FUNCTION__, *mNumChannelsPtr, buf);
|
|
|
|
}
|
|
break;
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS:
|
|
{
|
|
wifi_request_id id;
|
|
u32 numResults = 0;
|
|
int firstScanIdInPatch = -1;
|
|
|
|
if (!tbVendor[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) {
|
|
ALOGE("%s: GSCAN_RESULTS_REQUEST_ID not"
|
|
"found", __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, just ignore it. */
|
|
if (id != mRequestId) {
|
|
ALOGV("%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;
|
|
}
|
|
/* Read num of cached scan results in this data chunk. Note that
|
|
* this value doesn't represent the number of unique gscan scan Ids
|
|
* since the first scan id in this new chunk could be similar to
|
|
* the last scan id in the previous chunk.
|
|
*/
|
|
numResults = nla_get_u32(tbVendor[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]);
|
|
ALOGV("%s: num Cached results in this fragment:%d",
|
|
__FUNCTION__, numResults);
|
|
|
|
if (!mGetCachedResultsRspParams) {
|
|
ALOGE("%s: mGetCachedResultsRspParams is NULL, exit.",
|
|
__FUNCTION__);
|
|
ret = WIFI_ERROR_INVALID_ARGS;
|
|
break;
|
|
}
|
|
|
|
/* To support fragmentation from firmware, monitor the
|
|
* MORE_DATA 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", __FUNCTION__);
|
|
ret = WIFI_ERROR_INVALID_ARGS;
|
|
break;
|
|
} else {
|
|
mGetCachedResultsRspParams->more_data = nla_get_u8(
|
|
tbVendor[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]);
|
|
}
|
|
|
|
/* No data in this chunk so skip this chunk */
|
|
if (numResults == 0) {
|
|
return NL_SKIP;
|
|
}
|
|
|
|
if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID]) {
|
|
ALOGE("GSCAN_CACHED_RESULTS_SCAN_ID not found");
|
|
ret = WIFI_ERROR_INVALID_ARGS;
|
|
break;
|
|
}
|
|
|
|
/* Get the first Scan-Id in this chuck of cached results. */
|
|
firstScanIdInPatch = nla_get_u32(tbVendor[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID]);
|
|
|
|
ALOGV("More data: %d, firstScanIdInPatch: %d, lastProcessedScanId: %d",
|
|
mGetCachedResultsRspParams->more_data, firstScanIdInPatch,
|
|
mGetCachedResultsRspParams->lastProcessedScanId);
|
|
|
|
if (numResults) {
|
|
if (firstScanIdInPatch !=
|
|
mGetCachedResultsRspParams->lastProcessedScanId) {
|
|
/* New result scan Id block, update the starting index. */
|
|
mGetCachedResultsRspParams->cachedResultsStartingIndex++;
|
|
}
|
|
|
|
ret = gscan_get_cached_results(
|
|
mGetCachedResultsRspParams->cached_results,
|
|
tbVendor);
|
|
/* If a parsing error occurred, exit and proceed for cleanup. */
|
|
if (ret)
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
/* Error case should not happen print log */
|
|
ALOGE("%s: Wrong GScan subcmd response 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_GET_CACHED_RESULTS:
|
|
{
|
|
ALOGE("%s: Parsing error, free CachedResultsRspParams",
|
|
__FUNCTION__);
|
|
freeRspParams(eGScanGetCachedResultsRspParams);
|
|
}
|
|
break;
|
|
default:
|
|
ALOGE("%s: Wrong GScan subcmd received %d", __FUNCTION__, mSubcmd);
|
|
}
|
|
}
|
|
return NL_SKIP;
|
|
}
|
|
|
|
/* Called to parse and extract cached results. */
|
|
wifi_error GScanCommand:: gscan_get_cached_results(
|
|
wifi_cached_scan_results *cached_results,
|
|
struct nlattr **tb_vendor)
|
|
{
|
|
u32 j = 0;
|
|
struct nlattr *scanResultsInfo, *wifiScanResultsInfo;
|
|
int rem = 0, remResults = 0;
|
|
u32 len = 0, numScanResults = 0;
|
|
u32 i = mGetCachedResultsRspParams->cachedResultsStartingIndex;
|
|
ALOGV("%s: starting counter: %d", __FUNCTION__, i);
|
|
|
|
for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST]),
|
|
rem = nla_len(tb_vendor[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST]);
|
|
nla_ok(scanResultsInfo, rem) && i < mGetCachedResultsRspParams->max;
|
|
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_CACHED_RESULTS_SCAN_ID
|
|
])
|
|
{
|
|
ALOGE("%s: GSCAN_CACHED_RESULTS_SCAN_ID"
|
|
" not found", __FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
cached_results[i].scan_id =
|
|
nla_get_u32(
|
|
tb2[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID
|
|
]);
|
|
|
|
if (!
|
|
tb2[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_FLAGS
|
|
])
|
|
{
|
|
ALOGE("%s: GSCAN_CACHED_RESULTS_FLAGS "
|
|
"not found", __FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
cached_results[i].flags =
|
|
nla_get_u32(
|
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_FLAGS]);
|
|
|
|
if (!tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED])
|
|
{
|
|
ALOGI("%s: GSCAN_RESULTS_BUCKETS_SCANNED"
|
|
"not found", __FUNCTION__);
|
|
} else {
|
|
cached_results[i].buckets_scanned = nla_get_u32(
|
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED]);
|
|
}
|
|
|
|
if (!
|
|
tb2[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
|
|
])
|
|
{
|
|
ALOGE("%s: RESULTS_NUM_RESULTS_AVAILABLE "
|
|
"not found", __FUNCTION__);
|
|
return WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
numScanResults =
|
|
nla_get_u32(
|
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]);
|
|
|
|
if (mGetCachedResultsRspParams->lastProcessedScanId !=
|
|
cached_results[i].scan_id) {
|
|
j = 0; /* reset wifi_scan_result counter */
|
|
cached_results[i].num_results = 0;
|
|
ALOGV("parsing: *lastProcessedScanId [%d] !="
|
|
" cached_results[%d].scan_id:%d, j:%d "
|
|
"numScanResults: %d",
|
|
mGetCachedResultsRspParams->lastProcessedScanId, i,
|
|
cached_results[i].scan_id, j, numScanResults);
|
|
mGetCachedResultsRspParams->lastProcessedScanId =
|
|
cached_results[i].scan_id;
|
|
mGetCachedResultsRspParams->wifiScanResultsStartingIndex = 0;
|
|
/* Increment the number of cached scan results received */
|
|
mGetCachedResultsRspParams->num_cached_results++;
|
|
} else {
|
|
j = mGetCachedResultsRspParams->wifiScanResultsStartingIndex;
|
|
ALOGV("parsing: *lastProcessedScanId [%d] == "
|
|
"cached_results[%d].scan_id:%d, j:%d "
|
|
"numScanResults:%d",
|
|
mGetCachedResultsRspParams->lastProcessedScanId, i,
|
|
cached_results[i].scan_id, j, numScanResults);
|
|
}
|
|
|
|
ALOGV("%s: scan_id %d ", __FUNCTION__,
|
|
cached_results[i].scan_id);
|
|
ALOGV("%s: flags %u ", __FUNCTION__,
|
|
cached_results[i].flags);
|
|
|
|
for (wifiScanResultsInfo = (struct nlattr *) nla_data(tb2[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]),
|
|
remResults = nla_len(tb2[
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]);
|
|
nla_ok(wifiScanResultsInfo, remResults);
|
|
wifiScanResultsInfo = nla_next(wifiScanResultsInfo, &(remResults)))
|
|
{
|
|
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);
|
|
if (j < MAX_AP_CACHE_PER_SCAN) {
|
|
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;
|
|
}
|
|
cached_results[i].results[j].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(cached_results[i].results[j].ssid) <= len ?
|
|
sizeof(cached_results[i].results[j].ssid) : len;
|
|
memcpy((void *)&cached_results[i].results[j].ssid,
|
|
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(cached_results[i].results[j].bssid) <= len ?
|
|
sizeof(cached_results[i].results[j].bssid) : len;
|
|
memcpy(&cached_results[i].results[j].bssid,
|
|
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;
|
|
}
|
|
cached_results[i].results[j].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;
|
|
}
|
|
cached_results[i].results[j].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;
|
|
}
|
|
cached_results[i].results[j].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;
|
|
}
|
|
cached_results[i].results[j].rtt_sd =
|
|
nla_get_u32(
|
|
tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]);
|
|
#ifdef QC_HAL_DEBUG
|
|
/* Enable these prints for debugging if needed. */
|
|
ALOGD("%s: ts %" PRId64, __FUNCTION__,
|
|
cached_results[i].results[j].ts);
|
|
ALOGD("%s: SSID %s ", __FUNCTION__,
|
|
cached_results[i].results[j].ssid);
|
|
ALOGD("%s: BSSID: %02x:%02x:%02x:%02x:%02x:%02x \n",
|
|
__FUNCTION__, cached_results[i].results[j].bssid[0],
|
|
cached_results[i].results[j].bssid[1],
|
|
cached_results[i].results[j].bssid[2],
|
|
cached_results[i].results[j].bssid[3],
|
|
cached_results[i].results[j].bssid[4],
|
|
cached_results[i].results[j].bssid[5]);
|
|
ALOGD("%s: channel %d ", __FUNCTION__,
|
|
cached_results[i].results[j].channel);
|
|
ALOGD("%s: rssi %d ", __FUNCTION__,
|
|
cached_results[i].results[j].rssi);
|
|
ALOGD("%s: rtt %" PRId64, __FUNCTION__,
|
|
cached_results[i].results[j].rtt);
|
|
ALOGD("%s: rtt_sd %" PRId64, __FUNCTION__,
|
|
cached_results[i].results[j].rtt_sd);
|
|
#endif
|
|
/* Increment loop index for next record */
|
|
j++;
|
|
/* For this scan id, update the wifiScanResultsStartingIndex
|
|
* and number of cached results parsed so far.
|
|
*/
|
|
mGetCachedResultsRspParams->wifiScanResultsStartingIndex = j;
|
|
cached_results[i].num_results++;
|
|
} else {
|
|
/* We already parsed and stored up to max wifi_scan_results
|
|
* specified by the caller. Now, continue to loop over NL
|
|
* entries in order to properly update NL parsing pointer
|
|
* so it points to the next scan_id results.
|
|
*/
|
|
ALOGD("%s: loop index:%d > max num"
|
|
" of wifi_scan_results:%d for gscan cached results"
|
|
" bucket:%d. Dummy loop", __FUNCTION__,
|
|
j, MAX_AP_CACHE_PER_SCAN, i);
|
|
}
|
|
}
|
|
ALOGV("%s: cached_results[%d].num_results: %d ", __FUNCTION__,
|
|
i, cached_results[i].num_results);
|
|
/* Increment loop index for next cached scan result record */
|
|
i++;
|
|
}
|
|
/* Increment starting index of filling cached results received */
|
|
if (mGetCachedResultsRspParams->num_cached_results)
|
|
mGetCachedResultsRspParams->cachedResultsStartingIndex =
|
|
mGetCachedResultsRspParams->num_cached_results - 1;
|
|
return WIFI_SUCCESS;
|
|
}
|
|
|
|
/* Set the GSCAN BSSID Hotlist. */
|
|
wifi_error wifi_set_epno_list(wifi_request_id id,
|
|
wifi_interface_handle iface,
|
|
const wifi_epno_params *epno_params,
|
|
wifi_epno_handler handler)
|
|
{
|
|
int i, num_networks;
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData, *nlPnoParamList;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
gscan_event_handlers* event_handlers;
|
|
GScanCommandEventHandler *gScanSetPnoListCmdEventHandler;
|
|
|
|
event_handlers = (gscan_event_handlers*)info->gscan_handlers;
|
|
gScanSetPnoListCmdEventHandler =
|
|
event_handlers->gScanSetPnoListCmdEventHandler;
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_HAL_EPNO)) {
|
|
ALOGE("%s: Enhanced PNO is not supported by the driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
/* Wi-Fi HAL doesn't need to check if a similar request to set ePNO
|
|
* list was made earlier. If wifi_set_epno_list() is called while
|
|
* another one is running, the request will be sent down to driver and
|
|
* firmware. If the new request is successfully honored, then Wi-Fi HAL
|
|
* will use the new request id for the gScanSetPnoListCmdEventHandler
|
|
* object.
|
|
*/
|
|
|
|
gScanCommand =
|
|
new GScanCommand(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST);
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to create the NL msg. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to set iface id. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData) {
|
|
ALOGE("%s: Failed to add attribute NL80211_ATTR_VENDOR_DATA. Error:%d",
|
|
__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
num_networks = (unsigned int)epno_params->num_networks > MAX_EPNO_NETWORKS ?
|
|
MAX_EPNO_NETWORKS : epno_params->num_networks;
|
|
if (gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
|
|
id) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI,
|
|
epno_params->min5GHz_rssi) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI,
|
|
epno_params->min24GHz_rssi) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX,
|
|
epno_params->initial_score_max) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS,
|
|
epno_params->current_connection_bonus) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS,
|
|
epno_params->same_network_bonus) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS,
|
|
epno_params->secure_bonus) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS,
|
|
epno_params->band5GHz_bonus) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS,
|
|
num_networks))
|
|
{
|
|
ALOGE("%s: Failed to add vendor atributes. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlPnoParamList =
|
|
gScanCommand->attr_start(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST);
|
|
if (!nlPnoParamList) {
|
|
ALOGE("%s: Failed to add attr. PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST. "
|
|
"Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Add nested NL attributes for ePno List. */
|
|
for (i = 0; i < num_networks; i++) {
|
|
wifi_epno_network pnoNetwork = epno_params->networks[i];
|
|
struct nlattr *nlPnoNetwork = gScanCommand->attr_start(i);
|
|
if (!nlPnoNetwork) {
|
|
ALOGE("%s: Failed attr_start for nlPnoNetwork. Error:%d",
|
|
__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
if (gScanCommand->put_string(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID,
|
|
pnoNetwork.ssid) ||
|
|
gScanCommand->put_u8(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS,
|
|
pnoNetwork.flags) ||
|
|
gScanCommand->put_u8(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT,
|
|
pnoNetwork.auth_bit_field))
|
|
{
|
|
ALOGE("%s: Failed to add PNO_SET_LIST_PARAM_EPNO_NETWORK_*. "
|
|
"Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
gScanCommand->attr_end(nlPnoNetwork);
|
|
}
|
|
|
|
gScanCommand->attr_end(nlPnoParamList);
|
|
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
GScanCallbackHandler callbackHandler;
|
|
memset(&callbackHandler, 0, sizeof(callbackHandler));
|
|
callbackHandler.on_pno_network_found = handler.on_network_found;
|
|
|
|
/* Create an object of the event handler class to take care of the
|
|
* asychronous events on the north-bound.
|
|
*/
|
|
if (gScanSetPnoListCmdEventHandler == NULL) {
|
|
gScanSetPnoListCmdEventHandler = new GScanCommandEventHandler(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST,
|
|
callbackHandler);
|
|
if (gScanSetPnoListCmdEventHandler == NULL) {
|
|
ALOGE("%s: Error instantiating "
|
|
"gScanSetPnoListCmdEventHandler.", __FUNCTION__);
|
|
ret = WIFI_ERROR_UNKNOWN;
|
|
goto cleanup;
|
|
}
|
|
event_handlers->gScanSetPnoListCmdEventHandler =
|
|
gScanSetPnoListCmdEventHandler;
|
|
} else {
|
|
gScanSetPnoListCmdEventHandler->setCallbackHandler(callbackHandler);
|
|
}
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (gScanSetPnoListCmdEventHandler != NULL) {
|
|
gScanSetPnoListCmdEventHandler->set_request_id(id);
|
|
gScanSetPnoListCmdEventHandler->enableEventHandling();
|
|
}
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
/* Disable Event Handling if ret != 0 */
|
|
if ((ret != WIFI_SUCCESS) && gScanSetPnoListCmdEventHandler) {
|
|
ALOGI("%s: Error ret:%d, disable event handling",
|
|
__FUNCTION__, ret);
|
|
gScanSetPnoListCmdEventHandler->disableEventHandling();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* Reset the ePNO list - no ePNO networks should be matched after this */
|
|
wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface)
|
|
{
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_HAL_EPNO)) {
|
|
ALOGE("%s: Enhanced PNO is not supported by the driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
gScanCommand = new GScanCommand(wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST);
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to create the NL msg. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to set iface id. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData) {
|
|
ALOGE("%s: Failed to add attribute NL80211_ATTR_VENDOR_DATA. Error:%d",
|
|
__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
|
|
id) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS,
|
|
EPNO_NO_NETWORKS))
|
|
{
|
|
ALOGE("%s: Failed to add vendor atributes Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
return ret;
|
|
}
|
|
|
|
/* Set the ePNO Passpoint List. */
|
|
wifi_error wifi_set_passpoint_list(wifi_request_id id,
|
|
wifi_interface_handle iface, int num,
|
|
wifi_passpoint_network *networks,
|
|
wifi_passpoint_event_handler handler)
|
|
{
|
|
int i;
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData, *nlPasspointNetworksParamList;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
gscan_event_handlers* event_handlers;
|
|
GScanCommandEventHandler *gScanPnoSetPasspointListCmdEventHandler;
|
|
|
|
event_handlers = (gscan_event_handlers*)info->gscan_handlers;
|
|
gScanPnoSetPasspointListCmdEventHandler =
|
|
event_handlers->gScanPnoSetPasspointListCmdEventHandler;
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_HAL_EPNO)) {
|
|
ALOGE("%s: Enhanced PNO is not supported by the driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
/* Wi-Fi HAL doesn't need to check if a similar request to set ePNO
|
|
* passpoint list was made earlier. If wifi_set_passpoint_list() is called
|
|
* while another one is running, the request will be sent down to driver and
|
|
* firmware. If the new request is successfully honored, then Wi-Fi HAL
|
|
* will use the new request id for the
|
|
* gScanPnoSetPasspointListCmdEventHandler object.
|
|
*/
|
|
gScanCommand =
|
|
new GScanCommand(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST);
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to create the NL msg. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to set iface id. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData) {
|
|
ALOGE("%s: Failed to add attribute NL80211_ATTR_VENDOR_DATA. Error:%d",
|
|
__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID,
|
|
id) ||
|
|
gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM,
|
|
num))
|
|
{
|
|
ALOGE("%s: Failed to add vendor atributes. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlPasspointNetworksParamList =
|
|
gScanCommand->attr_start(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY);
|
|
if (!nlPasspointNetworksParamList) {
|
|
ALOGE("%s: Failed attr_start for PASSPOINT_LIST_PARAM_NETWORK_ARRAY. "
|
|
"Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Add nested NL attributes for Passpoint List param. */
|
|
for (i = 0; i < num; i++) {
|
|
wifi_passpoint_network passpointNetwork = networks[i];
|
|
struct nlattr *nlPasspointNetworkParam = gScanCommand->attr_start(i);
|
|
if (!nlPasspointNetworkParam) {
|
|
ALOGE("%s: Failed attr_start for nlPasspointNetworkParam. "
|
|
"Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
if (gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID,
|
|
passpointNetwork.id) ||
|
|
gScanCommand->put_string(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM,
|
|
passpointNetwork.realm) ||
|
|
gScanCommand->put_bytes(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID,
|
|
(char*)passpointNetwork.roamingConsortiumIds,
|
|
16 * sizeof(int64_t)) ||
|
|
gScanCommand->put_bytes(
|
|
QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN,
|
|
(char*)passpointNetwork.plmn, 3 * sizeof(u8)))
|
|
{
|
|
ALOGE("%s: Failed to add PNO_PASSPOINT_NETWORK_PARAM_ROAM_* attr. "
|
|
"Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
gScanCommand->attr_end(nlPasspointNetworkParam);
|
|
}
|
|
|
|
gScanCommand->attr_end(nlPasspointNetworksParamList);
|
|
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
GScanCallbackHandler callbackHandler;
|
|
memset(&callbackHandler, 0, sizeof(callbackHandler));
|
|
callbackHandler.on_passpoint_network_found =
|
|
handler.on_passpoint_network_found;
|
|
|
|
/* Create an object of the event handler class to take care of the
|
|
* asychronous events on the north-bound.
|
|
*/
|
|
if (gScanPnoSetPasspointListCmdEventHandler == NULL) {
|
|
gScanPnoSetPasspointListCmdEventHandler = new GScanCommandEventHandler(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST,
|
|
callbackHandler);
|
|
if (gScanPnoSetPasspointListCmdEventHandler == NULL) {
|
|
ALOGE("%s: Error instantiating "
|
|
"gScanPnoSetPasspointListCmdEventHandler.", __FUNCTION__);
|
|
ret = WIFI_ERROR_UNKNOWN;
|
|
goto cleanup;
|
|
}
|
|
event_handlers->gScanPnoSetPasspointListCmdEventHandler =
|
|
gScanPnoSetPasspointListCmdEventHandler;
|
|
} else {
|
|
gScanPnoSetPasspointListCmdEventHandler->setCallbackHandler(callbackHandler);
|
|
}
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (gScanPnoSetPasspointListCmdEventHandler != NULL) {
|
|
gScanPnoSetPasspointListCmdEventHandler->set_request_id(id);
|
|
gScanPnoSetPasspointListCmdEventHandler->enableEventHandling();
|
|
}
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
/* Disable Event Handling if ret != 0 */
|
|
if ((ret != WIFI_SUCCESS) && gScanPnoSetPasspointListCmdEventHandler) {
|
|
ALOGI("%s: Error ret:%d, disable event handling",
|
|
__FUNCTION__, ret);
|
|
gScanPnoSetPasspointListCmdEventHandler->disableEventHandling();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
wifi_error wifi_reset_passpoint_list(wifi_request_id id,
|
|
wifi_interface_handle iface)
|
|
{
|
|
wifi_error ret;
|
|
GScanCommand *gScanCommand;
|
|
struct nlattr *nlData;
|
|
interface_info *ifaceInfo = getIfaceInfo(iface);
|
|
wifi_handle wifiHandle = getWifiHandle(iface);
|
|
hal_info *info = getHalInfo(wifiHandle);
|
|
gscan_event_handlers* event_handlers;
|
|
GScanCommandEventHandler *gScanPnoSetPasspointListCmdEventHandler;
|
|
|
|
event_handlers = (gscan_event_handlers*)info->gscan_handlers;
|
|
gScanPnoSetPasspointListCmdEventHandler =
|
|
event_handlers->gScanPnoSetPasspointListCmdEventHandler;
|
|
|
|
if (!(info->supported_feature_set & WIFI_FEATURE_HAL_EPNO)) {
|
|
ALOGE("%s: Enhanced PNO is not supported by the driver",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (gScanPnoSetPasspointListCmdEventHandler == NULL ||
|
|
(gScanPnoSetPasspointListCmdEventHandler->isEventHandlingEnabled() ==
|
|
false)) {
|
|
ALOGE("wifi_reset_passpoint_list: ePNO passpoint_list isn't set. "
|
|
"Nothing to do. Exit.");
|
|
return WIFI_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
gScanCommand = new GScanCommand(
|
|
wifiHandle,
|
|
id,
|
|
OUI_QCA,
|
|
QCA_NL80211_VENDOR_SUBCMD_PNO_RESET_PASSPOINT_LIST);
|
|
|
|
if (gScanCommand == NULL) {
|
|
ALOGE("%s: Error GScanCommand NULL", __FUNCTION__);
|
|
return WIFI_ERROR_UNKNOWN;
|
|
}
|
|
|
|
/* Create the NL message. */
|
|
ret = gScanCommand->create();
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to create the NL msg. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Set the interface Id of the message. */
|
|
ret = gScanCommand->set_iface_id(ifaceInfo->name);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to set iface id. Error:%d", __FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Add the vendor specific attributes for the NL command. */
|
|
nlData = gScanCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
|
|
if (!nlData) {
|
|
ALOGE("%s: Failed to add attribute NL80211_ATTR_VENDOR_DATA. Error:%d",
|
|
__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = gScanCommand->put_u32(
|
|
QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID, id);
|
|
if (ret != WIFI_SUCCESS) {
|
|
ALOGE("%s: Failed to add vendor data attributes. Error:%d",
|
|
__FUNCTION__, ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
gScanCommand->attr_end(nlData);
|
|
|
|
ret = gScanCommand->requestResponse();
|
|
if (ret != WIFI_SUCCESS)
|
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
|
|
|
|
/* Disable Event Handling. */
|
|
if (gScanPnoSetPasspointListCmdEventHandler) {
|
|
gScanPnoSetPasspointListCmdEventHandler->disableEventHandling();
|
|
}
|
|
|
|
cleanup:
|
|
delete gScanCommand;
|
|
return ret;
|
|
}
|
|
|
|
wifi_error GScanCommand::allocCachedResultsTemp(int max,
|
|
wifi_cached_scan_results *cached_results)
|
|
{
|
|
/* Alloc memory for "max" number of cached results. */
|
|
mGetCachedResultsRspParams->cached_results =
|
|
(wifi_cached_scan_results*)
|
|
malloc(max * sizeof(wifi_cached_scan_results));
|
|
if (!mGetCachedResultsRspParams->cached_results) {
|
|
ALOGE("%s: Failed to allocate memory for "
|
|
"mGetCachedResultsRspParams->cached_results.",
|
|
__FUNCTION__);
|
|
return WIFI_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
memset(mGetCachedResultsRspParams->cached_results, 0,
|
|
max * sizeof(wifi_cached_scan_results));
|
|
|
|
mGetCachedResultsRspParams->max = max;
|
|
|
|
return WIFI_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Allocates memory for the subCmd response struct and initializes status = -1
|
|
*/
|
|
wifi_error GScanCommand::allocRspParams(eGScanRspRarams cmd)
|
|
{
|
|
switch(cmd)
|
|
{
|
|
case eGScanGetCachedResultsRspParams:
|
|
mGetCachedResultsRspParams = (GScanGetCachedResultsRspParams *)
|
|
malloc(sizeof(GScanGetCachedResultsRspParams));
|
|
if (!mGetCachedResultsRspParams)
|
|
return WIFI_ERROR_OUT_OF_MEMORY;
|
|
|
|
mGetCachedResultsRspParams->num_cached_results = 0;
|
|
mGetCachedResultsRspParams->more_data = false;
|
|
mGetCachedResultsRspParams->cachedResultsStartingIndex = -1;
|
|
mGetCachedResultsRspParams->lastProcessedScanId = -1;
|
|
mGetCachedResultsRspParams->wifiScanResultsStartingIndex = -1;
|
|
mGetCachedResultsRspParams->max = 0;
|
|
mGetCachedResultsRspParams->cached_results = NULL;
|
|
break;
|
|
default:
|
|
ALOGD("%s: Wrong request for alloc.", __FUNCTION__);
|
|
return WIFI_ERROR_NOT_SUPPORTED;
|
|
}
|
|
return WIFI_SUCCESS;
|
|
}
|
|
|
|
void GScanCommand::freeRspParams(eGScanRspRarams cmd)
|
|
{
|
|
switch(cmd)
|
|
{
|
|
case eGScanGetCachedResultsRspParams:
|
|
if (mGetCachedResultsRspParams) {
|
|
if (mGetCachedResultsRspParams->cached_results) {
|
|
free(mGetCachedResultsRspParams->cached_results);
|
|
mGetCachedResultsRspParams->cached_results = NULL;
|
|
}
|
|
free(mGetCachedResultsRspParams);
|
|
mGetCachedResultsRspParams = NULL;
|
|
}
|
|
break;
|
|
default:
|
|
ALOGD("%s: Wrong request for free.", __FUNCTION__);
|
|
}
|
|
}
|
|
|
|
wifi_error GScanCommand::copyCachedScanResults(
|
|
int *numResults,
|
|
wifi_cached_scan_results *cached_results)
|
|
{
|
|
wifi_error ret = WIFI_SUCCESS;
|
|
int i;
|
|
wifi_cached_scan_results *cachedResultRsp;
|
|
|
|
if (mGetCachedResultsRspParams && cached_results)
|
|
{
|
|
/* Populate the number of parsed cached results. */
|
|
*numResults = mGetCachedResultsRspParams->num_cached_results;
|
|
|
|
for (i = 0; i < *numResults; i++) {
|
|
cachedResultRsp = &mGetCachedResultsRspParams->cached_results[i];
|
|
cached_results[i].scan_id = cachedResultRsp->scan_id;
|
|
cached_results[i].flags = cachedResultRsp->flags;
|
|
cached_results[i].num_results = cachedResultRsp->num_results;
|
|
cached_results[i].buckets_scanned = cachedResultRsp->buckets_scanned;
|
|
|
|
if (!cached_results[i].num_results) {
|
|
ALOGI("Error: cached_results[%d].num_results=0", i);
|
|
continue;
|
|
}
|
|
|
|
ALOGV("copyCachedScanResults: "
|
|
"cached_results[%d].num_results : %d",
|
|
i, cached_results[i].num_results);
|
|
|
|
memcpy(cached_results[i].results,
|
|
cachedResultRsp->results,
|
|
cached_results[i].num_results * sizeof(wifi_scan_result));
|
|
}
|
|
} else {
|
|
ALOGE("%s: mGetCachedResultsRspParams is NULL", __FUNCTION__);
|
|
*numResults = 0;
|
|
ret = WIFI_ERROR_INVALID_ARGS;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
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;
|
|
}
|