You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2287 lines
83 KiB
2287 lines
83 KiB
/* |
|
* 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" |
|
|
|
#define GSCAN_EVENT_WAIT_TIME_SECONDS 4 |
|
|
|
/* 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)); |
|
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, ret = 0; |
|
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 < 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. ", __FUNCTION__, ret); |
|
} |
|
|
|
cleanup: |
|
delete gScanCommand; |
|
return mapErrorKernelToWifiHAL(ret); |
|
} |
|
|
|
wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle, |
|
wifi_gscan_capabilities *capabilities) |
|
{ |
|
wifi_error ret = WIFI_SUCCESS; |
|
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 mapErrorKernelToWifiHAL(ret); |
|
} |
|
|
|
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; |
|
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 < 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; |
|
|
|
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 != 0) { |
|
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 && gScanStartCmdEventHandler) { |
|
ALOGI("%s: Error ret:%d, disable event handling", |
|
__FUNCTION__, ret); |
|
gScanStartCmdEventHandler->disableEventHandling(); |
|
} |
|
return mapErrorKernelToWifiHAL(ret); |
|
|
|
} |
|
|
|
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); |
|
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 < 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->requestResponse(); |
|
if (ret != 0) { |
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret); |
|
} |
|
|
|
/* Disable Event Handling. */ |
|
if (gScanStartCmdEventHandler) { |
|
gScanStartCmdEventHandler->disableEventHandling(); |
|
} |
|
|
|
cleanup: |
|
delete gScanCommand; |
|
return mapErrorKernelToWifiHAL(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, ret = 0; |
|
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 < 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_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 != 0) { |
|
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 && gScanSetBssidHotlistCmdEventHandler) { |
|
ALOGI("%s: Error ret:%d, disable event handling", |
|
__FUNCTION__, ret); |
|
gScanSetBssidHotlistCmdEventHandler->disableEventHandling(); |
|
} |
|
return mapErrorKernelToWifiHAL(ret); |
|
} |
|
|
|
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); |
|
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 < 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->requestResponse(); |
|
if (ret != 0) { |
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret); |
|
} |
|
|
|
/* Disable Event Handling. */ |
|
if (gScanSetBssidHotlistCmdEventHandler) { |
|
gScanSetBssidHotlistCmdEventHandler->disableEventHandling(); |
|
} |
|
|
|
cleanup: |
|
delete gScanCommand; |
|
return mapErrorKernelToWifiHAL(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, ret = 0; |
|
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 < 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_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 != 0) { |
|
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 && gScanSetSignificantChangeCmdEventHandler) { |
|
ALOGI("%s: Error ret:%d, disable event handling", |
|
__FUNCTION__, ret); |
|
gScanSetSignificantChangeCmdEventHandler->disableEventHandling(); |
|
} |
|
delete gScanCommand; |
|
return mapErrorKernelToWifiHAL(ret); |
|
} |
|
|
|
/* 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); |
|
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 < 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->requestResponse(); |
|
if (ret != 0) { |
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret); |
|
} |
|
|
|
/* Disable Event Handling. */ |
|
if (gScanSetSignificantChangeCmdEventHandler) { |
|
gScanSetSignificantChangeCmdEventHandler->disableEventHandling(); |
|
} |
|
|
|
cleanup: |
|
delete gScanCommand; |
|
return mapErrorKernelToWifiHAL(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, ret = 0, retRequestRsp = 0; |
|
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 != 0) { |
|
ALOGE("%s: Failed to allocate memory for response struct. Error:%d", |
|
__FUNCTION__, ret); |
|
goto cleanup; |
|
} |
|
|
|
ret = gScanCommand->allocCachedResultsTemp(max, results); |
|
if (ret != 0) { |
|
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 < 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; |
|
} |
|
|
|
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); |
|
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 mapErrorKernelToWifiHAL(ret); |
|
} |
|
|
|
/* Random MAC OUI for PNO */ |
|
wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui) |
|
{ |
|
int ret = 0; |
|
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 < 0) |
|
goto cleanup; |
|
|
|
ret = vCommand->set_iface_id(iinfo->name); |
|
if (ret < 0) |
|
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 < 0) |
|
goto cleanup; |
|
|
|
vCommand->attr_end(nlData); |
|
|
|
ret = vCommand->requestResponse(); |
|
if (ret != 0) { |
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret); |
|
goto cleanup; |
|
} |
|
|
|
cleanup: |
|
delete vCommand; |
|
return mapErrorKernelToWifiHAL(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 */ |
|
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; |
|
|
|
ALOGV("%s: mVendor_id = %d, Subcmd = %d.", |
|
__FUNCTION__, mVendor_id, mSubcmd); |
|
out: |
|
return ret; |
|
} |
|
|
|
int GScanCommand::requestResponse() |
|
{ |
|
return WifiCommand::requestResponse(mMsg); |
|
} |
|
|
|
int GScanCommand::handleResponse(WifiEvent &reply) { |
|
int i = 0; |
|
int 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. */ |
|
int 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, ret = 0, num_networks; |
|
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 < 0) { |
|
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 < 0) { |
|
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 != 0) { |
|
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 && gScanSetPnoListCmdEventHandler) { |
|
ALOGI("%s: Error ret:%d, disable event handling", |
|
__FUNCTION__, ret); |
|
gScanSetPnoListCmdEventHandler->disableEventHandling(); |
|
} |
|
return mapErrorKernelToWifiHAL(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) |
|
{ |
|
int ret = 0; |
|
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 < 0) { |
|
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 < 0) { |
|
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 != 0) { |
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret); |
|
} |
|
|
|
cleanup: |
|
delete gScanCommand; |
|
return mapErrorKernelToWifiHAL(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, ret = 0; |
|
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 < 0) { |
|
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 < 0) { |
|
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 != 0) { |
|
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 && gScanPnoSetPasspointListCmdEventHandler) { |
|
ALOGI("%s: Error ret:%d, disable event handling", |
|
__FUNCTION__, ret); |
|
gScanPnoSetPasspointListCmdEventHandler->disableEventHandling(); |
|
} |
|
return mapErrorKernelToWifiHAL(ret); |
|
} |
|
|
|
wifi_error wifi_reset_passpoint_list(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); |
|
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 < 0) { |
|
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 < 0) { |
|
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 < 0) { |
|
ALOGE("%s: Failed to add vendor data attributes. Error:%d", |
|
__FUNCTION__, ret); |
|
goto cleanup; |
|
} |
|
|
|
gScanCommand->attr_end(nlData); |
|
|
|
ret = gScanCommand->requestResponse(); |
|
if (ret != 0) { |
|
ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret); |
|
} |
|
|
|
/* Disable Event Handling. */ |
|
if (gScanPnoSetPasspointListCmdEventHandler) { |
|
gScanPnoSetPasspointListCmdEventHandler->disableEventHandling(); |
|
} |
|
|
|
cleanup: |
|
delete gScanCommand; |
|
return mapErrorKernelToWifiHAL(ret); |
|
} |
|
|
|
int 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 |
|
*/ |
|
int GScanCommand::allocRspParams(eGScanRspRarams cmd) |
|
{ |
|
int ret = 0; |
|
switch(cmd) |
|
{ |
|
case eGScanGetCachedResultsRspParams: |
|
mGetCachedResultsRspParams = (GScanGetCachedResultsRspParams *) |
|
malloc(sizeof(GScanGetCachedResultsRspParams)); |
|
if (!mGetCachedResultsRspParams) |
|
ret = -1; |
|
else { |
|
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__); |
|
ret = -1; |
|
} |
|
return ret; |
|
} |
|
|
|
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; |
|
}
|
|
|