/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "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; } GScanCommandEventHandler::GScanCommandEventHandler(wifi_handle handle, int id, u32 vendor_id, u32 subcmd, GScanCallbackHandler handler) : WifiVendorCommand(handle, id, vendor_id, subcmd) { int ret = 0; ALOGD("GScanCommandEventHandler %p constructed", this); mRequestId = id; mHandler = handler; mSubCommandId = subcmd; mHotlistApFoundResults = NULL; mHotlistApFoundNumResults = 0; mHotlistApFoundMoreData = false; mSignificantChangeResults = NULL; mSignificantChangeNumResults = 0; mSignificantChangeMoreData = false; switch(mSubCommandId) { case QCA_NL80211_VENDOR_SUBCMD_GSCAN_START: { /* Register handlers for northbound asychronous scan events. */ ALOGD("%s: wait for GSCAN_RESULTS_AVAILABLE, " "FULL_SCAN_RESULT, and SCAN EVENT events. \n", __func__); 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 < 0) ALOGD("%s: Error in registering handler for " "GSCAN_START. \n", __func__); } break; case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE: { ret = registerVendorHandler(mVendor_id, QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE); if (ret < 0) ALOGD("%s: Error in registering handler for " "GSCAN_SIGNIFICANT_CHANGE. \n", __func__); } break; case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST: { ret = registerVendorHandler(mVendor_id, QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND); if (ret < 0) ALOGD("%s: Error in registering handler for" " GSCAN_HOTLIST_AP_FOUND. \n", __func__); } break; } } GScanCommandEventHandler::~GScanCommandEventHandler() { ALOGD("GScanCommandEventHandler %p destructor", this); switch(mSubCommandId) { case QCA_NL80211_VENDOR_SUBCMD_GSCAN_START: { /* Unregister event handlers. */ ALOGD("%s: Unregister handlers for GSCAN_RESULTS_AVAILABLE, " "FULL_SCAN_RESULT, and SCAN EVENT events. \n", __func__); 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); } break; } } static wifi_error gscan_get_hotlist_ap_found_results(u32 num_results, wifi_scan_result *results, u32 starting_index, struct nlattr **tb_vendor) { u32 i = starting_index; struct nlattr *scanResultsInfo; int rem = 0; u32 len = 0; ALOGE("gscan_get_hotlist_ap_found_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_get_hotlist_ap_found_results: " "RESULTS_SCAN_RESULT_TIME_STAMP not found"); return WIFI_ERROR_INVALID_ARGS; } results[i].ts = nla_get_u64( tb2[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP ]); if (! tb2[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID ]) { ALOGE("gscan_get_hotlist_ap_found_results: " "RESULTS_SCAN_RESULT_SSID not found"); return WIFI_ERROR_INVALID_ARGS; } len = nla_len(tb2[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]); len = sizeof(results->ssid) <= len ? sizeof(results->ssid) : len; memcpy((void *)&results[i].ssid, nla_data( tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID]), len); if (! tb2[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID ]) { ALOGE("gscan_get_hotlist_ap_found_results: " "RESULTS_SCAN_RESULT_BSSID not found"); return WIFI_ERROR_INVALID_ARGS; } len = nla_len( tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]); len = sizeof(results->bssid) <= len ? sizeof(results->bssid) : len; memcpy(&results[i].bssid, nla_data( tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID]), len); if (! tb2[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL ]) { ALOGE("gscan_get_hotlist_ap_found_results: " "RESULTS_SCAN_RESULT_CHANNEL not found"); return WIFI_ERROR_INVALID_ARGS; } results[i].channel = nla_get_u32( tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL]); if (! tb2[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI ]) { ALOGE("gscan_get_hotlist_ap_found_results: " "RESULTS_SCAN_RESULT_RSSI not found"); return WIFI_ERROR_INVALID_ARGS; } results[i].rssi = nla_get_u32( tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI]); if (! tb2[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT ]) { ALOGE("gscan_get_hotlist_ap_found_results: " "RESULTS_SCAN_RESULT_RTT not found"); return WIFI_ERROR_INVALID_ARGS; } results[i].rtt = nla_get_u32( tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT]); if (! tb2[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD ]) { ALOGE("gscan_get_hotlist_ap_found_results: " "RESULTS_SCAN_RESULT_RTT_SD not found"); return WIFI_ERROR_INVALID_ARGS; } results[i].rtt_sd = nla_get_u32( tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]); ALOGE("gscan_get_hotlist_ap_found_results: ts %lld ", results[i].ts); ALOGE("gscan_get_hotlist_ap_found_results: SSID %s ", results[i].ssid) ; ALOGE("gscan_get_hotlist_ap_found_results: " "BSSID: %02x:%02x:%02x:%02x:%02x:%02x \n", results[i].bssid[0], results[i].bssid[1], results[i].bssid[2], results[i].bssid[3], results[i].bssid[4], results[i].bssid[5]); ALOGE("gscan_get_hotlist_ap_found_results: channel %d ", results[i].channel); ALOGE("gscan_get_hotlist_ap_found_results: rssi %d ", results[i].rssi); ALOGE("gscan_get_hotlist_ap_found_results: rtt %lld ", results[i].rtt); ALOGE("gscan_get_hotlist_ap_found_results: rtt_sd %lld ", 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; struct nlattr *scanResultsInfo; ALOGE("gscan_get_significant_change_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_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); ALOGI("\nsignificant_change_result:%d, BSSID:" "%02x:%02x:%02x:%02x:%02x:%02x \n", 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]); 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]); ALOGI("significant_change_result:%d, channel:%d.\n", i, results[i]->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]); ALOGI("gscan_get_significant_change_results: " "significant_change_result:%d, num_rssi:%d.\n", i, results[i]->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; } ALOGI("gscan_get_significant_change_results: before reading the RSSI " "list: num_rssi:%d, size_of_rssi:%d, total size:%d, ", results[i]->num_rssi, sizeof(wifi_rssi), results[i]->num_rssi * sizeof(wifi_rssi)); 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)); for (j = 0; j < results[i]->num_rssi; j++) ALOGI(" significant_change_result: %d, rssi[%d]:%d, ", i, j, results[i]->rssi[j]); /* Increment loop index to prase next record. */ i++; } return WIFI_SUCCESS; } /* This function will be the main handler for incoming (from driver) GSscan_SUBCMD. * Calls the appropriate callback handler after parsing the vendor data. */ int GScanCommandEventHandler::handleEvent(WifiEvent &event) { ALOGI("GScanCommandEventHandler::handleEvent: Got a GSCAN Event" " message from the Driver."); unsigned i=0; int ret = WIFI_SUCCESS; u32 status; wifi_scan_result *result; struct nlattr *tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1]; 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; ALOGD("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.", __func__); 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, ignore it.", __func__, reqId, mRequestId); break; } /* 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", __func__); ret = WIFI_ERROR_INVALID_ARGS; break; } lengthOfInfoElements = nla_get_u32( tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH]); ALOGI("%s: RESULTS_SCAN_RESULT_IE_LENGTH =%d", __func__, 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", __func__); 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", __func__); 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", __func__); 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", __func__); 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", __func__); 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", __func__); ret = WIFI_ERROR_INVALID_ARGS; break; } result->rssi = nla_get_u32( 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", __func__); 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", __func__); 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", __func__); 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", __func__); 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", __func__); 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); ALOGE("handleEvent:FULL_SCAN_RESULTS: ts %lld ", result->ts); ALOGE("handleEvent:FULL_SCAN_RESULTS: SSID %s ", result->ssid) ; ALOGE("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]); ALOGE("handleEvent:FULL_SCAN_RESULTS: channel %d ", result->channel); ALOGE("handleEvent:FULL_SCAN_RESULTS: rssi %d ", result->rssi); ALOGE("handleEvent:FULL_SCAN_RESULTS: rtt %lld ", result->rtt); ALOGE("handleEvent:FULL_SCAN_RESULTS: rtt_sd %lld ", result->rtt_sd); ALOGE("handleEvent:FULL_SCAN_RESULTS: beacon period %d ", result->beacon_period); ALOGE("handleEvent:FULL_SCAN_RESULTS: capability %d ", result->capability); ALOGE("handleEvent:FULL_SCAN_RESULTS: IE length %d ", result->ie_length); ALOGE("%s: Invoking the callback. \n", __func__); if (mHandler.on_full_scan_result) { (*mHandler.on_full_scan_result)(reqId, result); /* Reset flag and num counter. */ free(result); result = NULL; } } break; case QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE: { wifi_request_id id; u32 numResults = 0; ALOGD("Event " "QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE " "received."); if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) { ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID" "not found. Exit", __func__); 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", __func__, id, mRequestId); break; } if (!tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) { ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found", __func__); ret = WIFI_ERROR_INVALID_ARGS; break; } numResults = nla_get_u32(tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]); ALOGE("%s: number of results:%d", __func__, numResults); /* Invoke the callback func to report the number of results. */ ALOGE("%s: Calling on_scan_results_available handler", __func__); if (!mHandler.on_scan_results_available) { break; } (*mHandler.on_scan_results_available)(id, numResults); } break; case QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND: { wifi_request_id id; u32 resultsBufSize = 0; u32 numResults = 0; u32 startingIndex, sizeOfObtainedResults; ALOGD("Event QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND " "received."); 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", __func__, id, mRequestId); break; } if (!tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]) { ALOGE("%s: GSCAN_RESULTS_NUM_RESULTS_AVAILABLE not found", __func__); ret = WIFI_ERROR_INVALID_ARGS; break; } numResults = nla_get_u32(tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE]); ALOGE("%s: number of results:%d", __func__, 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", __func__); ret = WIFI_ERROR_OUT_OF_MEMORY; break; } /* Initialize the newly allocated memory area with 0. */ memset((u8 *)mHotlistApFoundResults + sizeOfObtainedResults, 0, resultsBufSize - sizeOfObtainedResults); ALOGE("%s: Num of AP FOUND results = %d. \n", __func__, mHotlistApFoundNumResults); /* To support fragmentation from firmware, monitor the * MORE_DTATA 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", __func__); 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", __func__, mHotlistApFoundMoreData); } ALOGE("%s: Extract hotlist_ap_found results.\n", __func__); startingIndex = mHotlistApFoundNumResults - numResults; ALOGE("%s: starting_index:%d", __func__, startingIndex); ret = gscan_get_hotlist_ap_found_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_SIGNIFICANT_CHANGE: { wifi_request_id reqId; u32 numResults = 0, sizeOfObtainedResults; u32 startingIndex, index = 0; struct nlattr *scanResultsInfo; int rem = 0; ALOGD("Event QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE " "received."); if (!tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) { ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Exit.", __func__); 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", __func__, 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.", __func__); 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", __func__); 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); ALOGD("%s: mSignificantChangeMoreData = %d", __func__, 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.", __func__); 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.\n", __func__); ret = WIFI_ERROR_OUT_OF_MEMORY; break; } /* Initialize the newly allocated memory area with 0. */ memset((u8 *)mSignificantChangeResults[index], 0, resultsBufSize); ALOGE("%s: For Significant Change results[%d], num_rssi:%d\n", __func__, index, num_rssi); index++; } ALOGE("%s: Extract significant change results.\n", __func__); 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_DTATA 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.", __func__); break; } mSignificantChangeMoreData = nla_get_u8( tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA]); ALOGE("%s: More data = %d. \n", __func__, mSignificantChangeMoreData); /* Send the results if no more result fragments are expected */ if (!mSignificantChangeMoreData) { ALOGE("%s: Invoking the callback. \n", __func__); (*mHandler.on_significant_change)(reqId, mSignificantChangeNumResults, 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; u32 scanEventStatus = 0; wifi_request_id reqId; ALOGD("Event QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT " "received."); if (!tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID]) { ALOGE("%s: ATTR_GSCAN_RESULTS_REQUEST_ID not found. Exit.", __func__); 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", __func__, 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.", __func__); break; } scanEvent = (wifi_scan_event) nla_get_u8(tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_TYPE]); if (!tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_STATUS]) { ALOGE("%s: GSCAN_RESULTS_SCAN_EVENT_STATUS not" " found. Stop parsing and exit.", __func__); break; } scanEventStatus = nla_get_u32(tbVendor[ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_STATUS]); ALOGE("%s: Scan event type: %d, status = %d. \n", __func__, scanEvent, scanEventStatus); /* Send the results if no more result fragments are expected. */ (*mHandler.on_scan_event)(scanEvent, scanEventStatus); } break; default: /* Error case should not happen print log */ ALOGE("%s: Wrong GScan subcmd received %d", __func__, mSubcmd); } /* A parsing error occurred, do the cleanup of gscan result lists. */ if (ret) { switch(mSubcmd) { case QCA_NL80211_VENDOR_SUBCMD_GSCAN_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: { 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; default: ALOGE("%s: Parsing err handler: wrong GScan subcmd " "received %d", __func__, mSubcmd); } } return NL_SKIP; }