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.
2018 lines
76 KiB
2018 lines
76 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. |
|
*/ |
|
|
|
#define LOG_TAG "WifiHAL" |
|
|
|
#include <utils/Log.h> |
|
#include "gscan_event_handler.h" |
|
#include "vendor_definitions.h" |
|
|
|
/* This function implements creation of Vendor command event handler. */ |
|
int GScanCommandEventHandler::create() { |
|
int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0); |
|
if (ret < 0) { |
|
return ret; |
|
} |
|
|
|
/* Insert the oui in the msg */ |
|
ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id); |
|
if (ret < 0) |
|
goto out; |
|
|
|
/* Insert the subcmd in the msg */ |
|
ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd); |
|
if (ret < 0) |
|
goto out; |
|
out: |
|
return ret; |
|
} |
|
|
|
int GScanCommandEventHandler::get_request_id() |
|
{ |
|
return mRequestId; |
|
} |
|
|
|
void GScanCommandEventHandler::set_request_id(int request_id) |
|
{ |
|
mRequestId = request_id; |
|
} |
|
|
|
void GScanCommandEventHandler::enableEventHandling() |
|
{ |
|
mEventHandlingEnabled = true; |
|
} |
|
|
|
void GScanCommandEventHandler::disableEventHandling() |
|
{ |
|
mEventHandlingEnabled = false; |
|
} |
|
|
|
bool GScanCommandEventHandler::isEventHandlingEnabled() |
|
{ |
|
return mEventHandlingEnabled; |
|
} |
|
|
|
void GScanCommandEventHandler::setCallbackHandler(GScanCallbackHandler handler) |
|
{ |
|
mHandler = handler; |
|
} |
|
|
|
GScanCommandEventHandler::GScanCommandEventHandler(wifi_handle handle, int id, |
|
u32 vendor_id, |
|
u32 subcmd, |
|
GScanCallbackHandler handler) |
|
: WifiVendorCommand(handle, id, vendor_id, subcmd) |
|
{ |
|
int ret = 0; |
|
mRequestId = id; |
|
mHandler = handler; |
|
mSubCommandId = subcmd; |
|
mHotlistApFoundResults = NULL; |
|
mHotlistApFoundNumResults = 0; |
|
mHotlistApFoundMoreData = false; |
|
mHotlistApLostResults = NULL; |
|
mHotlistApLostNumResults = 0; |
|
mHotlistApLostMoreData = false; |
|
mSignificantChangeResults = NULL; |
|
mSignificantChangeNumResults = 0; |
|
mSignificantChangeMoreData = false; |
|
mHotlistSsidFoundNumResults = 0; |
|
mHotlistSsidFoundMoreData = false; |
|
mHotlistSsidLostNumResults = 0; |
|
mHotlistSsidLostMoreData = false; |
|
mHotlistSsidFoundResults = NULL; |
|
mHotlistSsidLostResults = NULL; |
|
mPnoNetworkFoundResults = NULL; |
|
mPnoNetworkFoundNumResults = 0; |
|
mPnoNetworkFoundMoreData = false; |
|
mPasspointNetworkFoundResult = NULL; |
|
mPasspointAnqp = NULL; |
|
mPasspointAnqpLen = 0; |
|
mPasspointNetId = -1; |
|
mEventHandlingEnabled = false; |
|
|
|
switch(mSubCommandId) |
|
{ |
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_START: |
|
{ |
|
/* Register handlers for northbound asychronous scan events. */ |
|
ret = registerVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE) || |
|
registerVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT) || |
|
registerVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT); |
|
if (ret) |
|
ALOGE("%s: Error in registering handler for " |
|
"GSCAN_START. \n", __FUNCTION__); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE: |
|
{ |
|
ret = registerVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE); |
|
if (ret) |
|
ALOGE("%s: Error in registering handler for " |
|
"GSCAN_SIGNIFICANT_CHANGE. \n", __FUNCTION__); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST: |
|
{ |
|
ret = registerVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND); |
|
if (ret) |
|
ALOGE("%s: Error in registering handler for" |
|
" GSCAN_HOTLIST_AP_FOUND. \n", __FUNCTION__); |
|
|
|
ret = registerVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST); |
|
if (ret) |
|
ALOGE("%s: Error in registering handler for" |
|
" GSCAN_HOTLIST_AP_LOST. \n", __FUNCTION__); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST: |
|
{ |
|
ret = registerVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND); |
|
if (ret) |
|
ALOGE("%s: Error in registering handler for" |
|
" PNO_NETWORK_FOUND. \n", __FUNCTION__); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST: |
|
{ |
|
ret = registerVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND); |
|
if (ret) |
|
ALOGE("%s: Error in registering handler for" |
|
" PNO_PASSPOINT_NETWORK_FOUND. \n", __FUNCTION__); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
GScanCommandEventHandler::~GScanCommandEventHandler() |
|
{ |
|
switch(mSubCommandId) |
|
{ |
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_START: |
|
{ |
|
/* Unregister event handlers. */ |
|
unregisterVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE); |
|
unregisterVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT); |
|
unregisterVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE: |
|
{ |
|
unregisterVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST: |
|
{ |
|
unregisterVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND); |
|
unregisterVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST: |
|
{ |
|
unregisterVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST: |
|
{ |
|
unregisterVendorHandler(mVendor_id, |
|
QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
wifi_error GScanCommandEventHandler::gscan_parse_hotlist_ap_results( |
|
u32 num_results, |
|
wifi_scan_result *results, |
|
u32 starting_index, |
|
struct nlattr **tb_vendor) |
|
{ |
|
u32 i = starting_index; |
|
struct nlattr *scanResultsInfo; |
|
int rem = 0; |
|
u32 len = 0; |
|
ALOGV("gscan_parse_hotlist_ap_results: starting counter: %d", i); |
|
|
|
for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]), |
|
rem = nla_len(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST |
|
]); |
|
nla_ok(scanResultsInfo, rem); |
|
scanResultsInfo = nla_next(scanResultsInfo, &(rem))) |
|
{ |
|
struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1]; |
|
nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX, |
|
(struct nlattr *) nla_data(scanResultsInfo), |
|
nla_len(scanResultsInfo), NULL); |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ap_results: " |
|
"RESULTS_SCAN_RESULT_TIME_STAMP not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].ts = |
|
nla_get_u64( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ap_results: " |
|
"RESULTS_SCAN_RESULT_SSID not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
len = nla_len(tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]); |
|
len = |
|
sizeof(results->ssid) <= len ? sizeof(results->ssid) : len; |
|
memcpy((void *)&results[i].ssid, |
|
nla_data( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ap_results: " |
|
"RESULTS_SCAN_RESULT_BSSID not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
len = nla_len( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]); |
|
len = |
|
sizeof(results->bssid) <= len ? sizeof(results->bssid) : len; |
|
memcpy(&results[i].bssid, |
|
nla_data( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), len); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ap_results: " |
|
"RESULTS_SCAN_RESULT_CHANNEL not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].channel = |
|
nla_get_u32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ap_results: " |
|
"RESULTS_SCAN_RESULT_RSSI not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].rssi = |
|
get_s32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ap_results: " |
|
"RESULTS_SCAN_RESULT_RTT not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].rtt = |
|
nla_get_u32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ap_results: " |
|
"RESULTS_SCAN_RESULT_RTT_SD not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].rtt_sd = |
|
nla_get_u32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]); |
|
|
|
ALOGV("gscan_parse_hotlist_ap_results: ts %" PRId64 " SSID %s " |
|
"BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel %d rssi %d " |
|
"rtt %" PRId64" rtt_sd %" PRId64, |
|
results[i].ts, results[i].ssid, |
|
results[i].bssid[0], results[i].bssid[1], results[i].bssid[2], |
|
results[i].bssid[3], results[i].bssid[4], results[i].bssid[5], |
|
results[i].channel, results[i].rssi, results[i].rtt, |
|
results[i].rtt_sd); |
|
/* Increment loop index for next record */ |
|
i++; |
|
} |
|
return WIFI_SUCCESS; |
|
} |
|
|
|
static wifi_error gscan_get_significant_change_results(u32 num_results, |
|
wifi_significant_change_result **results, |
|
u32 starting_index, |
|
struct nlattr **tb_vendor) |
|
{ |
|
u32 i = starting_index; |
|
int j; |
|
int rem = 0; |
|
u32 len = 0; |
|
char rssi_buf[1024]; //TODO: sizeof buf |
|
int rem_size; |
|
struct nlattr *scanResultsInfo; |
|
|
|
for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]), |
|
rem = nla_len(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]); |
|
nla_ok(scanResultsInfo, rem); |
|
scanResultsInfo = nla_next(scanResultsInfo, &(rem))) |
|
{ |
|
struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1]; |
|
nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX, |
|
(struct nlattr *) nla_data(scanResultsInfo), |
|
nla_len(scanResultsInfo), NULL); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID |
|
]) |
|
{ |
|
ALOGE("gscan_get_significant_change_results: " |
|
"SIGNIFICANT_CHANGE_RESULT_BSSID not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
len = nla_len( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID] |
|
); |
|
len = |
|
sizeof(results[i]->bssid) <= len ? sizeof(results[i]->bssid) : len; |
|
memcpy(&results[i]->bssid[0], |
|
nla_data( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID]), |
|
len); |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL |
|
]) |
|
{ |
|
ALOGE("gscan_get_significant_change_results: " |
|
"SIGNIFICANT_CHANGE_RESULT_CHANNEL not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i]->channel = |
|
nla_get_u32( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL]); |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI |
|
]) |
|
{ |
|
ALOGE("gscan_get_significant_change_results: " |
|
"SIGNIFICANT_CHANGE_RESULT_NUM_RSSI not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i]->num_rssi = |
|
nla_get_u32( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI]); |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST |
|
]) |
|
{ |
|
ALOGE("gscan_get_significant_change_results: " |
|
"SIGNIFICANT_CHANGE_RESULT_RSSI_LIST not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
|
|
memcpy(&(results[i]->rssi[0]), |
|
nla_data( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST] |
|
), results[i]->num_rssi * sizeof(wifi_rssi)); |
|
|
|
ALOGV("significant_change_result:%d, BSSID:" |
|
"%02x:%02x:%02x:%02x:%02x:%02x channel:%d num_rssi:%d ", |
|
i, results[i]->bssid[0], results[i]->bssid[1], results[i]->bssid[2], |
|
results[i]->bssid[3], results[i]->bssid[4], results[i]->bssid[5], |
|
results[i]->channel, results[i]->num_rssi); |
|
|
|
rem_size = sizeof(rssi_buf); |
|
char *dst = rssi_buf; |
|
for (j = 0; j < results[i]->num_rssi && rem_size > 0; j++) { |
|
len = snprintf(dst, rem_size, "rssi[%d]:%d, ", j, results[i]->rssi[j]); |
|
dst += len; |
|
rem_size -= len; |
|
} |
|
ALOGV("RSSI LIST: %s", rssi_buf); |
|
|
|
/* Increment loop index to prase next record. */ |
|
i++; |
|
} |
|
return WIFI_SUCCESS; |
|
} |
|
|
|
wifi_error GScanCommandEventHandler::gscan_parse_hotlist_ssid_results( |
|
u32 num_results, |
|
wifi_scan_result *results, |
|
u32 starting_index, |
|
struct nlattr **tb_vendor) |
|
{ |
|
u32 i = starting_index; |
|
struct nlattr *scanResultsInfo; |
|
int rem = 0; |
|
u32 len = 0; |
|
|
|
for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]), |
|
rem = nla_len(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST |
|
]); |
|
nla_ok(scanResultsInfo, rem); |
|
scanResultsInfo = nla_next(scanResultsInfo, &(rem))) |
|
{ |
|
struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1]; |
|
nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX, |
|
(struct nlattr *) nla_data(scanResultsInfo), |
|
nla_len(scanResultsInfo), NULL); |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ssid_results: " |
|
"RESULTS_SCAN_RESULT_TIME_STAMP not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].ts = |
|
nla_get_u64( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ssid_results: " |
|
"RESULTS_SCAN_RESULT_SSID not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
len = nla_len(tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]); |
|
len = |
|
sizeof(results->ssid) <= len ? sizeof(results->ssid) : len; |
|
memcpy((void *)&results[i].ssid, |
|
nla_data( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ssid_results: " |
|
"RESULTS_SCAN_RESULT_BSSID not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
len = nla_len( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]); |
|
len = |
|
sizeof(results->bssid) <= len ? sizeof(results->bssid) : len; |
|
memcpy(&results[i].bssid, |
|
nla_data( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), len); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ssid_results: " |
|
"RESULTS_SCAN_RESULT_CHANNEL not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].channel = |
|
nla_get_u32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ssid_results: " |
|
"RESULTS_SCAN_RESULT_RSSI not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].rssi = |
|
get_s32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ssid_results: " |
|
"RESULTS_SCAN_RESULT_RTT not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].rtt = |
|
nla_get_u32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD |
|
]) |
|
{ |
|
ALOGE("gscan_parse_hotlist_ssid_results: " |
|
"RESULTS_SCAN_RESULT_RTT_SD not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].rtt_sd = |
|
nla_get_u32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]); |
|
|
|
ALOGV("gscan_parse_hotlist_ssid_results: ts %" PRId64 " SSID %s " |
|
"BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel %d rssi %d " |
|
"rtt %" PRId64 " rtt_sd %" PRId64, |
|
results[i].ts, results[i].ssid, |
|
results[i].bssid[0], results[i].bssid[1], results[i].bssid[2], |
|
results[i].bssid[3], results[i].bssid[4], results[i].bssid[5], |
|
results[i].channel, results[i].rssi, results[i].rtt, |
|
results[i].rtt_sd); |
|
/* Increment loop index for next record */ |
|
i++; |
|
} |
|
return WIFI_SUCCESS; |
|
} |
|
|
|
wifi_error GScanCommandEventHandler::gscan_parse_passpoint_network_result( |
|
struct nlattr **tb_vendor) |
|
{ |
|
struct nlattr *scanResultsInfo, *wifiScanResultsInfo; |
|
u32 resultsBufSize = 0; |
|
u32 len = 0; |
|
int rem = 0; |
|
|
|
for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST]), |
|
rem = nla_len(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST |
|
]); |
|
nla_ok(scanResultsInfo, rem); |
|
scanResultsInfo = nla_next(scanResultsInfo, &(rem))) |
|
{ |
|
struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1]; |
|
nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX, |
|
(struct nlattr *) nla_data(scanResultsInfo), |
|
nla_len(scanResultsInfo), NULL); |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID |
|
]) |
|
{ |
|
ALOGE("%s: GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID not found", |
|
__FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
mPasspointNetId = |
|
nla_get_u32( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID |
|
]); |
|
|
|
for (wifiScanResultsInfo = (struct nlattr *) nla_data(tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]), |
|
rem = nla_len(tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST |
|
]); |
|
nla_ok(wifiScanResultsInfo, rem); |
|
wifiScanResultsInfo = nla_next(wifiScanResultsInfo, &(rem))) |
|
{ |
|
struct nlattr *tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1]; |
|
nla_parse(tb3, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX, |
|
(struct nlattr *) nla_data(wifiScanResultsInfo), |
|
nla_len(wifiScanResultsInfo), NULL); |
|
|
|
resultsBufSize = sizeof(wifi_scan_result); |
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_IE_LENGTH not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
resultsBufSize += |
|
nla_get_u32( |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH]); |
|
|
|
/* Allocate the appropriate memory for mPasspointNetworkFoundResult */ |
|
mPasspointNetworkFoundResult = (wifi_scan_result *) |
|
malloc (resultsBufSize); |
|
|
|
if (!mPasspointNetworkFoundResult) { |
|
ALOGE("%s: Failed to alloc memory for result struct. Exit.\n", |
|
__FUNCTION__); |
|
return WIFI_ERROR_OUT_OF_MEMORY; |
|
} |
|
memset(mPasspointNetworkFoundResult, 0, resultsBufSize); |
|
|
|
mPasspointNetworkFoundResult->ie_length = |
|
nla_get_u32( |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH]); |
|
|
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_TIME_STAMP not found", |
|
__FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
mPasspointNetworkFoundResult->ts = |
|
nla_get_u64( |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]); |
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_SSID not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
len = nla_len(tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]); |
|
len = |
|
sizeof(mPasspointNetworkFoundResult->ssid) <= len ? |
|
sizeof(mPasspointNetworkFoundResult->ssid) : len; |
|
memcpy((void *)&(mPasspointNetworkFoundResult->ssid[0]), |
|
nla_data( |
|
tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len); |
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_BSSID not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
len = nla_len( |
|
tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]); |
|
len = |
|
sizeof(mPasspointNetworkFoundResult->bssid) <= len ? |
|
sizeof(mPasspointNetworkFoundResult->bssid) : len; |
|
memcpy(&(mPasspointNetworkFoundResult->bssid[0]), |
|
nla_data( |
|
tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), |
|
len); |
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_CHANNEL not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
mPasspointNetworkFoundResult->channel = |
|
nla_get_u32( |
|
tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]); |
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_RSSI not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
mPasspointNetworkFoundResult->rssi = |
|
get_s32( |
|
tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]); |
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_RTT not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
mPasspointNetworkFoundResult->rtt = |
|
nla_get_u32( |
|
tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]); |
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_RTT_SD not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
mPasspointNetworkFoundResult->rtt_sd = |
|
nla_get_u32( |
|
tb3[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]); |
|
|
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_BEACON_PERIOD not found", |
|
__FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
mPasspointNetworkFoundResult->beacon_period = |
|
nla_get_u16( |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD]); |
|
|
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_CAPABILITY not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
mPasspointNetworkFoundResult->capability = |
|
nla_get_u16( |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY]); |
|
|
|
if (! |
|
tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_IE_DATA not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
memcpy(&(mPasspointNetworkFoundResult->ie_data[0]), |
|
nla_data(tb3[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA]), |
|
mPasspointNetworkFoundResult->ie_length); |
|
|
|
ALOGV("%s: ts: %" PRId64 " SSID: %s " |
|
"BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel: %d rssi: %d" |
|
" rtt: % " PRId64 " rtt_sd %" PRId64 " ie_length %u ", |
|
__FUNCTION__, mPasspointNetworkFoundResult->ts, |
|
mPasspointNetworkFoundResult->ssid, |
|
mPasspointNetworkFoundResult->bssid[0], |
|
mPasspointNetworkFoundResult->bssid[1], |
|
mPasspointNetworkFoundResult->bssid[2], |
|
mPasspointNetworkFoundResult->bssid[3], |
|
mPasspointNetworkFoundResult->bssid[4], |
|
mPasspointNetworkFoundResult->bssid[5], |
|
mPasspointNetworkFoundResult->channel, |
|
mPasspointNetworkFoundResult->rssi, |
|
mPasspointNetworkFoundResult->rtt, |
|
mPasspointNetworkFoundResult->rtt_sd, |
|
mPasspointNetworkFoundResult->ie_length); |
|
ALOGV("%s: ie_data: ", __FUNCTION__); |
|
hexdump(mPasspointNetworkFoundResult->ie_data, |
|
mPasspointNetworkFoundResult->ie_length); |
|
} |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN |
|
]) |
|
{ |
|
ALOGE("%s:PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN not found", |
|
__FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
mPasspointAnqpLen = |
|
nla_get_u32( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN]); |
|
|
|
if (!mPasspointAnqpLen) |
|
{ |
|
break; |
|
} |
|
mPasspointAnqp = (u8 *) malloc (mPasspointAnqpLen); |
|
if (!mPasspointAnqp) { |
|
ALOGE("%s: Failed to alloc memory for result struct. Exit.\n", |
|
__FUNCTION__); |
|
return WIFI_ERROR_OUT_OF_MEMORY; |
|
} |
|
|
|
memset(mPasspointAnqp, 0, mPasspointAnqpLen); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_PASSPOINT_MATCH_ANQP not found", __FUNCTION__); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
memcpy(&(mPasspointAnqp[0]), |
|
nla_data(tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP]), |
|
mPasspointAnqpLen); |
|
|
|
ALOGV("%s: ANQP LEN:%d, ANQP IE:", __FUNCTION__, mPasspointAnqpLen); |
|
hexdump((char*)mPasspointAnqp, mPasspointAnqpLen); |
|
|
|
/* expecting only one result break out after the first loop */ |
|
break; |
|
} |
|
return WIFI_SUCCESS; |
|
} |
|
|
|
wifi_error GScanCommandEventHandler::gscan_parse_pno_network_results( |
|
u32 num_results, |
|
wifi_scan_result *results, |
|
u32 starting_index, |
|
struct nlattr **tb_vendor) |
|
{ |
|
u32 i = starting_index; |
|
struct nlattr *scanResultsInfo; |
|
int rem = 0; |
|
u32 len = 0; |
|
|
|
for (scanResultsInfo = (struct nlattr *) nla_data(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]), |
|
rem = nla_len(tb_vendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST |
|
]); |
|
nla_ok(scanResultsInfo, rem); |
|
scanResultsInfo = nla_next(scanResultsInfo, &(rem))) |
|
{ |
|
struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1]; |
|
nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX, |
|
(struct nlattr *) nla_data(scanResultsInfo), |
|
nla_len(scanResultsInfo), NULL); |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]) |
|
{ |
|
ALOGE("gscan_parse_pno_network_results: " |
|
"RESULTS_SCAN_RESULT_TIME_STAMP not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].ts = |
|
nla_get_u64( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID |
|
]) |
|
{ |
|
ALOGE("gscan_parse_pno_network_results: " |
|
"RESULTS_SCAN_RESULT_SSID not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
len = nla_len(tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]); |
|
len = |
|
sizeof(results->ssid) <= len ? sizeof(results->ssid) : len; |
|
memcpy((void *)&results[i].ssid, |
|
nla_data( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID |
|
]) |
|
{ |
|
ALOGE("gscan_parse_pno_network_results: " |
|
"RESULTS_SCAN_RESULT_BSSID not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
len = nla_len( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]); |
|
len = |
|
sizeof(results->bssid) <= len ? sizeof(results->bssid) : len; |
|
memcpy(&results[i].bssid, |
|
nla_data( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), len); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL |
|
]) |
|
{ |
|
ALOGE("gscan_parse_pno_network_results: " |
|
"RESULTS_SCAN_RESULT_CHANNEL not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].channel = |
|
nla_get_u32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI |
|
]) |
|
{ |
|
ALOGE("gscan_parse_pno_network_results: " |
|
"RESULTS_SCAN_RESULT_RSSI not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].rssi = |
|
get_s32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT |
|
]) |
|
{ |
|
ALOGE("gscan_parse_pno_network_results: " |
|
"RESULTS_SCAN_RESULT_RTT not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].rtt = |
|
nla_get_u32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]); |
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD |
|
]) |
|
{ |
|
ALOGE("gscan_parse_pno_network_results: " |
|
"RESULTS_SCAN_RESULT_RTT_SD not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].rtt_sd = |
|
nla_get_u32( |
|
tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]); |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD]) |
|
{ |
|
ALOGE("gscan_parse_pno_network_results: " |
|
"RESULTS_SCAN_RESULT_BEACON_PERIOD not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].beacon_period = |
|
nla_get_u16( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD]); |
|
|
|
if (! |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY |
|
]) |
|
{ |
|
ALOGE("gscan_parse_pno_network_results: " |
|
"RESULTS_SCAN_RESULT_CAPABILITY not found"); |
|
return WIFI_ERROR_INVALID_ARGS; |
|
} |
|
results[i].capability = |
|
nla_get_u16( |
|
tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY]); |
|
|
|
ALOGV("gscan_parse_pno_network_results: ts %" PRId64 " SSID %s " |
|
"BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel %d rssi %d " |
|
"rtt %" PRId64 " rtt_sd %" PRId64, |
|
results[i].ts, results[i].ssid, |
|
results[i].bssid[0], results[i].bssid[1], results[i].bssid[2], |
|
results[i].bssid[3], results[i].bssid[4], results[i].bssid[5], |
|
results[i].channel, results[i].rssi, results[i].rtt, |
|
results[i].rtt_sd); |
|
/* Increment loop index for next record */ |
|
i++; |
|
} |
|
return WIFI_SUCCESS; |
|
} |
|
|
|
/* This function will be the main handler for incoming (from driver) |
|
* GScan_SUBCMD. Calls the appropriate callback handler after parsing |
|
* the vendor data. |
|
*/ |
|
int GScanCommandEventHandler::handleEvent(WifiEvent &event) |
|
{ |
|
unsigned i=0; |
|
int ret = WIFI_SUCCESS; |
|
wifi_scan_result *result = NULL; |
|
struct nlattr *tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1]; |
|
|
|
if (mEventHandlingEnabled == false) |
|
{ |
|
ALOGV("%s:Discarding event: %d", |
|
__FUNCTION__, mSubcmd); |
|
return NL_SKIP; |
|
} |
|
|
|
WifiVendorCommand::handleEvent(event); |
|
|
|
nla_parse(tbVendor, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX, |
|
(struct nlattr *)mVendorData, |
|
mDataLen, NULL); |
|
|
|
switch(mSubcmd) |
|
{ |
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT: |
|
{ |
|
wifi_request_id reqId; |
|
u32 len = 0; |
|
u32 resultsBufSize = 0; |
|
u32 lengthOfInfoElements = 0; |
|
u32 buckets_scanned = 0; |
|
|
|
ALOGV("Event QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT " |
|
"received."); |
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) |
|
{ |
|
ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Exit.", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
reqId = nla_get_u32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID] |
|
); |
|
/* If event has a different request_id, ignore that and use the |
|
* request_id value which we're maintaining. |
|
*/ |
|
if (reqId != mRequestId) { |
|
#ifdef QC_HAL_DEBUG |
|
ALOGE("%s: Event has Req. ID:%d <> Ours:%d, continue...", |
|
__FUNCTION__, reqId, mRequestId); |
|
#endif |
|
reqId = mRequestId; |
|
} |
|
|
|
/* Parse and extract the results. */ |
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH |
|
]) |
|
{ |
|
ALOGE("%s:RESULTS_SCAN_RESULT_IE_LENGTH not found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
lengthOfInfoElements = |
|
nla_get_u32( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH]); |
|
|
|
ALOGV("%s: RESULTS_SCAN_RESULT_IE_LENGTH =%d", |
|
__FUNCTION__, lengthOfInfoElements); |
|
|
|
resultsBufSize = |
|
lengthOfInfoElements + sizeof(wifi_scan_result); |
|
result = (wifi_scan_result *) malloc (resultsBufSize); |
|
if (!result) { |
|
ALOGE("%s: Failed to alloc memory for result struct. Exit.\n", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_OUT_OF_MEMORY; |
|
break; |
|
} |
|
memset(result, 0, resultsBufSize); |
|
|
|
result->ie_length = lengthOfInfoElements; |
|
|
|
/* Extract and fill out the wifi_scan_result struct. */ |
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_TIME_STAMP not found", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
result->ts = |
|
nla_get_u64( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP |
|
]); |
|
|
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_SSID not found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
len = nla_len(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]); |
|
len = |
|
sizeof(result->ssid) <= len ? sizeof(result->ssid) : len; |
|
memcpy((void *)&result->ssid, |
|
nla_data( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len); |
|
|
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_BSSID not found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
len = nla_len( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]); |
|
len = |
|
sizeof(result->bssid) <= len ? sizeof(result->bssid) : len; |
|
memcpy(&result->bssid, |
|
nla_data( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), len); |
|
|
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_CHANNEL not found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
result->channel = |
|
nla_get_u32( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]); |
|
|
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_RSSI not found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
result->rssi = |
|
get_s32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI] |
|
); |
|
|
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_RTT not found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
result->rtt = |
|
nla_get_u32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]); |
|
|
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_RTT_SD not found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
result->rtt_sd = |
|
nla_get_u32( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]); |
|
|
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_BEACON_PERIOD not found", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
result->beacon_period = |
|
nla_get_u16( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD]); |
|
|
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_CAPABILITY not found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
result->capability = |
|
nla_get_u16( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY]); |
|
|
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA |
|
]) |
|
{ |
|
ALOGE("%s: RESULTS_SCAN_RESULT_IE_DATA not found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
memcpy(&(result->ie_data[0]), |
|
nla_data(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA]), |
|
lengthOfInfoElements); |
|
if (! |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED |
|
]) |
|
{ |
|
ALOGD("%s: RESULTS_BUCKETS_SCANNED not found", __FUNCTION__); |
|
} else { |
|
buckets_scanned = get_u32(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED]); |
|
} |
|
#ifdef QC_HAL_DEBUG |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: ts %" PRId64, result->ts); |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: SSID %s ", result->ssid) ; |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: " |
|
"BSSID: %02x:%02x:%02x:%02x:%02x:%02x \n", |
|
result->bssid[0], result->bssid[1], result->bssid[2], |
|
result->bssid[3], result->bssid[4], result->bssid[5]); |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: channel %d ", |
|
result->channel); |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: rssi %d ", result->rssi); |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: rtt %" PRId64, result->rtt); |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: rtt_sd %" PRId64, |
|
result->rtt_sd); |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: beacon period %d ", |
|
result->beacon_period); |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: capability %d ", |
|
result->capability); |
|
ALOGD("handleEvent:FULL_SCAN_RESULTS: IE length %d ", |
|
result->ie_length); |
|
|
|
ALOGD("%s: Invoking the callback. \n", __FUNCTION__); |
|
#endif |
|
if (mHandler.on_full_scan_result) { |
|
(*mHandler.on_full_scan_result)(reqId, result, buckets_scanned); |
|
/* Reset flag and num counter. */ |
|
free(result); |
|
result = NULL; |
|
} |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE: |
|
{ |
|
wifi_request_id id; |
|
|
|
#ifdef QC_HAL_DEBUG |
|
ALOGV("Event " |
|
"QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE " |
|
"received."); |
|
#endif |
|
|
|
if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) { |
|
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID" |
|
"not found. Exit", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
id = nla_get_u32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID] |
|
); |
|
/* If this is not for us, then ignore it. */ |
|
if (id != mRequestId) { |
|
ALOGE("%s: Event has Req. ID:%d <> ours:%d", |
|
__FUNCTION__, id, mRequestId); |
|
break; |
|
} |
|
|
|
/* Invoke the callback func to report the number of results. */ |
|
ALOGV("%s: Calling on_scan_event handler", __FUNCTION__); |
|
(*mHandler.on_scan_event)(id, WIFI_SCAN_THRESHOLD_NUM_SCANS); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND: |
|
{ |
|
wifi_request_id id; |
|
u32 resultsBufSize = 0; |
|
u32 numResults = 0; |
|
u32 startingIndex, sizeOfObtainedResults; |
|
|
|
id = nla_get_u32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID] |
|
); |
|
/* If this is not for us, just ignore it. */ |
|
if (id != mRequestId) { |
|
ALOGE("%s: Event has Req. ID:%d <> ours:%d", |
|
__FUNCTION__, id, mRequestId); |
|
break; |
|
} |
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) { |
|
ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
numResults = nla_get_u32(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]); |
|
ALOGV("%s: number of results:%d", __FUNCTION__, numResults); |
|
|
|
/* Get the memory size of previous fragments, if any. */ |
|
sizeOfObtainedResults = mHotlistApFoundNumResults * |
|
sizeof(wifi_scan_result); |
|
|
|
mHotlistApFoundNumResults += numResults; |
|
resultsBufSize += mHotlistApFoundNumResults * |
|
sizeof(wifi_scan_result); |
|
|
|
/* Check if this chunck of scan results is a continuation of |
|
* a previous one. |
|
*/ |
|
if (mHotlistApFoundMoreData) { |
|
mHotlistApFoundResults = (wifi_scan_result *) |
|
realloc (mHotlistApFoundResults, resultsBufSize); |
|
} else { |
|
mHotlistApFoundResults = (wifi_scan_result *) |
|
malloc (resultsBufSize); |
|
} |
|
|
|
if (!mHotlistApFoundResults) { |
|
ALOGE("%s: Failed to alloc memory for results array. Exit.\n", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_OUT_OF_MEMORY; |
|
break; |
|
} |
|
/* Initialize the newly allocated memory area with 0. */ |
|
memset((u8 *)mHotlistApFoundResults + sizeOfObtainedResults, 0, |
|
resultsBufSize - sizeOfObtainedResults); |
|
|
|
ALOGV("%s: Num of AP FOUND results = %d. \n", __FUNCTION__, |
|
mHotlistApFoundNumResults); |
|
|
|
/* To support fragmentation from firmware, monitor the |
|
* MORE_DATA flag and cache results until MORE_DATA = 0. |
|
* Only then we can pass on the results to framework through |
|
* the callback function. |
|
*/ |
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) { |
|
ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA not" |
|
" found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} else { |
|
mHotlistApFoundMoreData = nla_get_u8( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]); |
|
ALOGE("%s: More data = %d. \n", |
|
__FUNCTION__, mHotlistApFoundMoreData); |
|
} |
|
|
|
ALOGV("%s: Extract hotlist_ap_found results.\n", __FUNCTION__); |
|
startingIndex = mHotlistApFoundNumResults - numResults; |
|
ALOGV("%s: starting_index:%d", |
|
__FUNCTION__, startingIndex); |
|
ret = gscan_parse_hotlist_ap_results(numResults, |
|
mHotlistApFoundResults, |
|
startingIndex, |
|
tbVendor); |
|
/* If a parsing error occurred, exit and proceed for cleanup. */ |
|
if (ret) |
|
break; |
|
/* Send the results if no more result data fragments are expected */ |
|
if (!mHotlistApFoundMoreData) { |
|
(*mHandler.on_hotlist_ap_found)(id, |
|
mHotlistApFoundNumResults, |
|
mHotlistApFoundResults); |
|
/* Reset flag and num counter. */ |
|
free(mHotlistApFoundResults); |
|
mHotlistApFoundResults = NULL; |
|
mHotlistApFoundMoreData = false; |
|
mHotlistApFoundNumResults = 0; |
|
} |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST: |
|
{ |
|
wifi_request_id id; |
|
u32 resultsBufSize = 0; |
|
u32 numResults = 0; |
|
u32 startingIndex, sizeOfObtainedResults; |
|
|
|
id = nla_get_u32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID] |
|
); |
|
/* If this is not for us, just ignore it. */ |
|
if (id != mRequestId) { |
|
ALOGE("%s: Event has Req. ID:%d <> ours:%d", |
|
__FUNCTION__, id, mRequestId); |
|
break; |
|
} |
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) { |
|
ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
numResults = nla_get_u32(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]); |
|
ALOGV("%s: number of results:%d", __FUNCTION__, numResults); |
|
|
|
/* Get the memory size of previous fragments, if any. */ |
|
sizeOfObtainedResults = mHotlistApLostNumResults * |
|
sizeof(wifi_scan_result); |
|
|
|
mHotlistApLostNumResults += numResults; |
|
resultsBufSize += mHotlistApLostNumResults * |
|
sizeof(wifi_scan_result); |
|
|
|
/* Check if this chunck of scan results is a continuation of |
|
* a previous one. |
|
*/ |
|
if (mHotlistApLostMoreData) { |
|
mHotlistApLostResults = (wifi_scan_result *) |
|
realloc (mHotlistApLostResults, resultsBufSize); |
|
} else { |
|
mHotlistApLostResults = (wifi_scan_result *) |
|
malloc (resultsBufSize); |
|
} |
|
|
|
if (!mHotlistApLostResults) { |
|
ALOGE("%s: Failed to alloc memory for results array. Exit.\n", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_OUT_OF_MEMORY; |
|
break; |
|
} |
|
/* Initialize the newly allocated memory area with 0. */ |
|
memset((u8 *)mHotlistApLostResults + sizeOfObtainedResults, 0, |
|
resultsBufSize - sizeOfObtainedResults); |
|
|
|
ALOGV("%s: Num of AP Lost results = %d. \n", __FUNCTION__, |
|
mHotlistApLostNumResults); |
|
|
|
/* To support fragmentation from firmware, monitor the |
|
* MORE_DATA flag and cache results until MORE_DATA = 0. |
|
* Only then we can pass on the results to framework through |
|
* the callback function. |
|
*/ |
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) { |
|
ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA not" |
|
" found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} else { |
|
mHotlistApLostMoreData = nla_get_u8( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]); |
|
ALOGV("%s: More data = %d. \n", |
|
__FUNCTION__, mHotlistApLostMoreData); |
|
} |
|
|
|
ALOGV("%s: Extract hotlist_ap_Lost results.\n", __FUNCTION__); |
|
startingIndex = mHotlistApLostNumResults - numResults; |
|
ALOGV("%s: starting_index:%d", |
|
__FUNCTION__, startingIndex); |
|
ret = gscan_parse_hotlist_ap_results(numResults, |
|
mHotlistApLostResults, |
|
startingIndex, |
|
tbVendor); |
|
/* If a parsing error occurred, exit and proceed for cleanup. */ |
|
if (ret) |
|
break; |
|
/* Send the results if no more result data fragments are expected */ |
|
if (!mHotlistApLostMoreData) { |
|
(*mHandler.on_hotlist_ap_lost)(id, |
|
mHotlistApLostNumResults, |
|
mHotlistApLostResults); |
|
/* Reset flag and num counter. */ |
|
free(mHotlistApLostResults); |
|
mHotlistApLostResults = NULL; |
|
mHotlistApLostMoreData = false; |
|
mHotlistApLostNumResults = 0; |
|
} |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE: |
|
{ |
|
wifi_request_id reqId; |
|
u32 numResults = 0, sizeOfObtainedResults; |
|
u32 startingIndex, index = 0; |
|
struct nlattr *scanResultsInfo; |
|
int rem = 0; |
|
|
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) |
|
{ |
|
ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Exit.", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
reqId = nla_get_u32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID] |
|
); |
|
/* If this is not for us, just ignore it. */ |
|
if (reqId != mRequestId) { |
|
ALOGE("%s: Event has Req. ID:%d <> ours:%d", |
|
__FUNCTION__, reqId, mRequestId); |
|
break; |
|
} |
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) |
|
{ |
|
ALOGE("%s: ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found." |
|
"Exit.", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
numResults = nla_get_u32(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]); |
|
/* Get the memory size of previous fragments, if any. */ |
|
sizeOfObtainedResults = sizeof(wifi_significant_change_result *) * |
|
mSignificantChangeNumResults; |
|
|
|
index = mSignificantChangeNumResults; |
|
mSignificantChangeNumResults += numResults; |
|
/* |
|
* Check if this chunck of wifi_significant_change results is a |
|
* continuation of a previous one. |
|
*/ |
|
if (mSignificantChangeMoreData) { |
|
mSignificantChangeResults = |
|
(wifi_significant_change_result **) |
|
realloc (mSignificantChangeResults, |
|
sizeof(wifi_significant_change_result *) * |
|
mSignificantChangeNumResults); |
|
} else { |
|
mSignificantChangeResults = |
|
(wifi_significant_change_result **) |
|
malloc (sizeof(wifi_significant_change_result *) * |
|
mSignificantChangeNumResults); |
|
} |
|
|
|
if (!mSignificantChangeResults) { |
|
ALOGE("%s: Failed to alloc memory for results array. Exit.\n", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_OUT_OF_MEMORY; |
|
break; |
|
} |
|
/* Initialize the newly allocated memory area with 0. */ |
|
memset((u8 *)mSignificantChangeResults + sizeOfObtainedResults, 0, |
|
sizeof(wifi_significant_change_result *) * |
|
numResults); |
|
ALOGV("%s: mSignificantChangeMoreData = %d", |
|
__FUNCTION__, mSignificantChangeMoreData); |
|
|
|
for (scanResultsInfo = (struct nlattr *) nla_data(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]), |
|
rem = nla_len(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST]); |
|
nla_ok(scanResultsInfo, rem); |
|
scanResultsInfo = nla_next(scanResultsInfo, &(rem))) |
|
{ |
|
u32 num_rssi = 0; |
|
u32 resultsBufSize = 0; |
|
struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1]; |
|
nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX, |
|
(struct nlattr *) nla_data(scanResultsInfo), |
|
nla_len(scanResultsInfo), NULL); |
|
if (!tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI |
|
]) |
|
{ |
|
ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_" |
|
"SIGNIFICANT_CHANGE_RESULT_NUM_RSSI not found. " |
|
"Exit.", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
num_rssi = nla_get_u32(tb2[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI |
|
]); |
|
resultsBufSize = sizeof(wifi_significant_change_result) + |
|
num_rssi * sizeof(wifi_rssi); |
|
mSignificantChangeResults[index] = |
|
(wifi_significant_change_result *) malloc (resultsBufSize); |
|
|
|
if (!mSignificantChangeResults[index]) { |
|
ALOGE("%s: Failed to alloc memory for results array Exit", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_OUT_OF_MEMORY; |
|
break; |
|
} |
|
/* Initialize the newly allocated memory area with 0. */ |
|
memset((u8 *)mSignificantChangeResults[index], |
|
0, resultsBufSize); |
|
|
|
ALOGV("%s: For Significant Change results[%d], num_rssi:%d\n", |
|
__FUNCTION__, index, num_rssi); |
|
index++; |
|
} |
|
|
|
ALOGV("%s: Extract significant change results.\n", __FUNCTION__); |
|
startingIndex = |
|
mSignificantChangeNumResults - numResults; |
|
ret = gscan_get_significant_change_results(numResults, |
|
mSignificantChangeResults, |
|
startingIndex, |
|
tbVendor); |
|
/* If a parsing error occurred, exit and proceed for cleanup. */ |
|
if (ret) |
|
break; |
|
/* To support fragmentation from firmware, monitor the |
|
* MORE_DATA flag and cache results until MORE_DATA = 0. |
|
* Only then we can pass on the results to framework through |
|
* the callback function. |
|
*/ |
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) { |
|
ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA not" |
|
" found. Stop parsing and exit.", __FUNCTION__); |
|
break; |
|
} |
|
mSignificantChangeMoreData = nla_get_u8( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]); |
|
ALOGV("%s: More data = %d. \n", |
|
__FUNCTION__, mSignificantChangeMoreData); |
|
|
|
/* Send the results if no more result fragments are expected */ |
|
if (!mSignificantChangeMoreData) { |
|
ALOGV("%s: Invoking the callback. \n", __FUNCTION__); |
|
(*mHandler.on_significant_change)(reqId, |
|
mSignificantChangeNumResults, |
|
mSignificantChangeResults); |
|
if (mSignificantChangeResults) { |
|
/* Reset flag and num counter. */ |
|
for (index = 0; index < mSignificantChangeNumResults; |
|
index++) |
|
{ |
|
free(mSignificantChangeResults[index]); |
|
mSignificantChangeResults[index] = NULL; |
|
} |
|
free(mSignificantChangeResults); |
|
mSignificantChangeResults = NULL; |
|
} |
|
mSignificantChangeNumResults = 0; |
|
mSignificantChangeMoreData = false; |
|
} |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT: |
|
{ |
|
wifi_scan_event scanEvent; |
|
wifi_request_id reqId; |
|
|
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) |
|
{ |
|
ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Exit.", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
reqId = nla_get_u32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID] |
|
); |
|
/* If this is not for us, just ignore it. */ |
|
if (reqId != mRequestId) { |
|
ALOGE("%s: Event has Req. ID:%d <> ours:%d", |
|
__FUNCTION__, reqId, mRequestId); |
|
break; |
|
} |
|
|
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_TYPE]) { |
|
ALOGE("%s: GSCAN_RESULTS_SCAN_EVENT_TYPE not" |
|
" found. Stop parsing and exit.", __FUNCTION__); |
|
break; |
|
} |
|
scanEvent = (wifi_scan_event) nla_get_u8(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_TYPE]); |
|
|
|
ALOGV("%s: Scan event type: %d\n", __FUNCTION__, scanEvent); |
|
/* Send the results if no more result fragments are expected. */ |
|
(*mHandler.on_scan_event)(reqId, scanEvent); |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND: |
|
{ |
|
wifi_request_id id; |
|
u32 resultsBufSize = 0; |
|
u32 numResults = 0; |
|
u32 startingIndex, sizeOfObtainedResults; |
|
|
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) |
|
{ |
|
/* RequestId is not provided by FW/Driver for this event */ |
|
ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Continue.", |
|
__FUNCTION__); |
|
id = mRequestId; /* Use the saved mRequestId instead. */ |
|
} else { |
|
id = nla_get_u32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID] |
|
); |
|
/* If this is not for us, use the saved requestId */ |
|
if (id != mRequestId) { |
|
ALOGE("%s: Event has Req. ID:%d <> ours:%d", |
|
__FUNCTION__, id, mRequestId); |
|
id = mRequestId; |
|
} |
|
} |
|
|
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) { |
|
ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} |
|
numResults = nla_get_u32(tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]); |
|
ALOGV("%s: number of results:%d", __FUNCTION__, numResults); |
|
|
|
/* Get the memory size of previous fragments, if any. */ |
|
sizeOfObtainedResults = mPnoNetworkFoundNumResults * |
|
sizeof(wifi_scan_result); |
|
|
|
mPnoNetworkFoundNumResults += numResults; |
|
resultsBufSize += mPnoNetworkFoundNumResults * |
|
sizeof(wifi_scan_result); |
|
|
|
/* Check if this chunck of scan results is a continuation of |
|
* a previous one. |
|
*/ |
|
if (mPnoNetworkFoundMoreData) { |
|
mPnoNetworkFoundResults = (wifi_scan_result *) |
|
realloc (mPnoNetworkFoundResults, resultsBufSize); |
|
} else { |
|
mPnoNetworkFoundResults = (wifi_scan_result *) |
|
malloc (resultsBufSize); |
|
} |
|
|
|
if (!mPnoNetworkFoundResults) { |
|
ALOGE("%s: Failed to alloc memory for results array. Exit.\n", |
|
__FUNCTION__); |
|
ret = WIFI_ERROR_OUT_OF_MEMORY; |
|
break; |
|
} |
|
/* Initialize the newly allocated memory area with 0. */ |
|
memset((u8 *)mPnoNetworkFoundResults + sizeOfObtainedResults, 0, |
|
resultsBufSize - sizeOfObtainedResults); |
|
|
|
ALOGV("%s: Num of AP FOUND results = %d. \n", __FUNCTION__, |
|
mPnoNetworkFoundNumResults); |
|
|
|
/* To support fragmentation from firmware, monitor the |
|
* MORE_DATA flag and cache results until MORE_DATA = 0. |
|
* Only then we can pass on the results to framework through |
|
* the callback function. |
|
*/ |
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]) { |
|
ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_MORE_DATA not" |
|
" found", __FUNCTION__); |
|
ret = WIFI_ERROR_INVALID_ARGS; |
|
break; |
|
} else { |
|
mPnoNetworkFoundMoreData = nla_get_u8( |
|
tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]); |
|
ALOGV("%s: More data = %d. \n", |
|
__FUNCTION__, mPnoNetworkFoundMoreData); |
|
} |
|
|
|
ALOGV("%s: Extract PNO_NETWORK_FOUND results.\n", __FUNCTION__); |
|
startingIndex = mPnoNetworkFoundNumResults - numResults; |
|
ALOGV("%s: starting_index:%d", |
|
__FUNCTION__, startingIndex); |
|
ret = gscan_parse_pno_network_results(numResults, |
|
mPnoNetworkFoundResults, |
|
startingIndex, |
|
tbVendor); |
|
/* If a parsing error occurred, exit and proceed for cleanup. */ |
|
if (ret) |
|
break; |
|
/* Send the results if no more result data fragments are expected */ |
|
if (!mPnoNetworkFoundMoreData) { |
|
(*mHandler.on_pno_network_found)(id, |
|
mPnoNetworkFoundNumResults, |
|
mPnoNetworkFoundResults); |
|
/* Reset flag and num counter. */ |
|
if (mPnoNetworkFoundResults) { |
|
free(mPnoNetworkFoundResults); |
|
mPnoNetworkFoundResults = NULL; |
|
} |
|
mPnoNetworkFoundMoreData = false; |
|
mPnoNetworkFoundNumResults = 0; |
|
} |
|
} |
|
break; |
|
case QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND: |
|
{ |
|
wifi_request_id id; |
|
|
|
if (!tbVendor[ |
|
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) |
|
{ |
|
/* RequestId is not provided by FW/Driver for this event */ |
|
ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Continue.", |
|
__FUNCTION__); |
|
id = mRequestId; /* Use the saved mRequestId instead. */ |
|
} else { |
|
id = nla_get_u32( |
|
tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID] |
|
); |
|
/* If this is not for us, use the saved requestId */ |
|
if (id != mRequestId) { |
|
ALOGE("%s: Event has Req. ID:%d <> ours:%d", |
|
__FUNCTION__, id, mRequestId); |
|
id = mRequestId; |
|
} |
|
} |
|
|
|
ret = gscan_parse_passpoint_network_result(tbVendor); |
|
/* If a parsing error occurred, exit and proceed for cleanup. */ |
|
if (ret) |
|
{ |
|
ALOGE("%s: gscan_parse_passpoint_network_result" |
|
"returned error: %d.\n", __FUNCTION__, ret); |
|
break; |
|
} |
|
(*mHandler.on_passpoint_network_found)(id, |
|
mPasspointNetId, |
|
mPasspointNetworkFoundResult, |
|
mPasspointAnqpLen, |
|
mPasspointAnqp); |
|
if (mPasspointNetworkFoundResult) |
|
{ |
|
free(mPasspointNetworkFoundResult); |
|
mPasspointNetworkFoundResult = NULL; |
|
} |
|
if (mPasspointAnqp) |
|
{ |
|
free(mPasspointAnqp); |
|
mPasspointAnqp = NULL; |
|
} |
|
mPasspointNetId = -1; |
|
mPasspointAnqpLen = 0; |
|
} |
|
break; |
|
default: |
|
/* Error case should not happen print log */ |
|
ALOGE("%s: Wrong GScan subcmd received %d", __FUNCTION__, mSubcmd); |
|
} |
|
|
|
/* A parsing error occurred, do the cleanup of gscan result lists. */ |
|
if (ret) { |
|
switch(mSubcmd) |
|
{ |
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT: |
|
{ |
|
free(result); |
|
result = NULL; |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND: |
|
{ |
|
/* Reset flag and num counter. */ |
|
free(mHotlistApFoundResults); |
|
mHotlistApFoundResults = NULL; |
|
mHotlistApFoundMoreData = false; |
|
mHotlistApFoundNumResults = 0; |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE: |
|
{ |
|
if (mSignificantChangeResults) { |
|
for (i = 0; i < mSignificantChangeNumResults; i++) |
|
{ |
|
if (mSignificantChangeResults[i]) { |
|
free(mSignificantChangeResults[i]); |
|
mSignificantChangeResults[i] = NULL; |
|
} |
|
} |
|
free(mSignificantChangeResults); |
|
mSignificantChangeResults = NULL; |
|
} |
|
mSignificantChangeNumResults = 0; |
|
mSignificantChangeMoreData = false; |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE: |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT: |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST: |
|
{ |
|
/* Reset flag and num counter. */ |
|
free(mHotlistApLostResults); |
|
mHotlistApLostResults = NULL; |
|
mHotlistApLostMoreData = false; |
|
mHotlistApLostNumResults = 0; |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND: |
|
{ |
|
/* Reset flag and num counter. */ |
|
if (mPnoNetworkFoundResults) { |
|
free(mPnoNetworkFoundResults); |
|
mPnoNetworkFoundResults = NULL; |
|
} |
|
mPnoNetworkFoundMoreData = false; |
|
mPnoNetworkFoundNumResults = 0; |
|
} |
|
break; |
|
|
|
case QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND: |
|
{ |
|
if (mPasspointNetworkFoundResult) |
|
{ |
|
free(mPasspointNetworkFoundResult); |
|
mPasspointNetworkFoundResult = NULL; |
|
} |
|
if (mPasspointAnqp) |
|
{ |
|
free(mPasspointAnqp); |
|
mPasspointAnqp = NULL; |
|
} |
|
mPasspointNetId = -1; |
|
mPasspointAnqpLen = 0; |
|
} |
|
break; |
|
|
|
default: |
|
ALOGE("%s: Parsing err handler: wrong GScan subcmd " |
|
"received %d", __FUNCTION__, mSubcmd); |
|
} |
|
} |
|
return NL_SKIP; |
|
}
|
|
|