| /* |
| * 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" |
| |
| /* This function implements creation of Vendor command event handler. */ |
| wifi_error GScanCommandEventHandler::create() { |
| wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0); |
| if (ret != WIFI_SUCCESS) |
| return ret; |
| |
| /* Insert the oui in the msg */ |
| ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id); |
| if (ret != WIFI_SUCCESS) |
| return ret; |
| |
| /* Insert the subcmd in the msg */ |
| ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd); |
| |
| 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: " MACSTR " channel %d rssi %d " |
| "rtt %" PRId64" rtt_sd %" PRId64, |
| results[i].ts, results[i].ssid, MAC2STR(results[i].bssid), |
| 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:" MACSTR " channel:%d num_rssi:%d ", |
| i, MAC2STR(results[i]->bssid), |
| 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: " MACSTR " channel %d rssi %d " |
| "rtt %" PRId64 " rtt_sd %" PRId64, |
| results[i].ts, results[i].ssid, |
| MAC2STR(results[i].bssid), |
| 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; |
| |
| 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]); |
| |
| if (!nla_ok(scanResultsInfo, rem)) { |
| return WIFI_SUCCESS; |
| } |
| |
| 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: " MACSTR " channel: %d rssi: %d" |
| " rtt: % " PRId64 " rtt_sd %" PRId64 " ie_length %u ", |
| __FUNCTION__, mPasspointNetworkFoundResult->ts, |
| mPasspointNetworkFoundResult->ssid, |
| MAC2STR(mPasspointNetworkFoundResult->bssid), |
| 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) { |
| return WIFI_SUCCESS; |
| } |
| 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); |
| 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: " MACSTR " channel %d rssi %d " |
| "rtt %" PRId64 " rtt_sd %" PRId64, |
| results[i].ts, results[i].ssid, |
| MAC2STR(results[i].bssid), |
| 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: " MACSTR " \n", |
| MAC2STR(result->bssid)); |
| 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; |
| } |