| /* | |
| * Copyright (C) 2014 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "sync.h" | |
| #define LOG_TAG "WifiHAL" | |
| #include <utils/Log.h> | |
| #include "wifi_hal.h" | |
| #include "common.h" | |
| #include "cpp_bindings.h" | |
| #include "llstatscommand.h" | |
| //Singleton Static Instance | |
| LLStatsCommand* LLStatsCommand::mLLStatsCommandInstance = NULL; | |
| // This function implements creation of Vendor command | |
| // For LLStats just call base Vendor command create | |
| wifi_error LLStatsCommand::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; | |
| } | |
| LLStatsCommand::LLStatsCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd) | |
| : WifiVendorCommand(handle, id, vendor_id, subcmd) | |
| { | |
| memset(&mClearRspParams, 0,sizeof(LLStatsClearRspParams)); | |
| memset(&mResultsParams, 0,sizeof(LLStatsResultsParams)); | |
| memset(&mHandler, 0,sizeof(mHandler)); | |
| mRadioStatsSize = 0; | |
| mNumRadios = 0; | |
| mNumRadiosAllocated = 0; | |
| } | |
| LLStatsCommand::~LLStatsCommand() | |
| { | |
| mLLStatsCommandInstance = NULL; | |
| } | |
| LLStatsCommand* LLStatsCommand::instance(wifi_handle handle) | |
| { | |
| if (handle == NULL) { | |
| ALOGE("Interface Handle is invalid"); | |
| return NULL; | |
| } | |
| if (mLLStatsCommandInstance == NULL) { | |
| mLLStatsCommandInstance = new LLStatsCommand(handle, 0, | |
| OUI_QCA, | |
| QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET); | |
| return mLLStatsCommandInstance; | |
| } | |
| else | |
| { | |
| if (handle != getWifiHandle(mLLStatsCommandInstance->mInfo)) | |
| { | |
| /* upper layer must have cleaned up the handle and reinitialized, | |
| so we need to update the same */ | |
| ALOGE("Handle different, update the handle"); | |
| mLLStatsCommandInstance->mInfo = (hal_info *)handle; | |
| } | |
| } | |
| return mLLStatsCommandInstance; | |
| } | |
| void LLStatsCommand::initGetContext(u32 reqId) | |
| { | |
| mRequestId = reqId; | |
| memset(&mHandler, 0,sizeof(mHandler)); | |
| } | |
| void LLStatsCommand::setSubCmd(u32 subcmd) | |
| { | |
| mSubcmd = subcmd; | |
| } | |
| void LLStatsCommand::setHandler(wifi_stats_result_handler handler) | |
| { | |
| mHandler = handler; | |
| } | |
| static wifi_error get_wifi_interface_info(wifi_interface_link_layer_info *stats, | |
| struct nlattr **tb_vendor) | |
| { | |
| u32 len = 0; | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->mode = (wifi_interface_mode)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR]); | |
| len = ((sizeof(stats->mac_addr) <= len) ? sizeof(stats->mac_addr) : len); | |
| memcpy(&stats->mac_addr[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR]), len); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->state = (wifi_connection_state)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->roaming = (wifi_roam_state)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->capabilities = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID]); | |
| len = ((sizeof(stats->ssid) <= len) ? sizeof(stats->ssid) : len); | |
| memcpy(&stats->ssid[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID]), len); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID]); | |
| len = ((sizeof(stats->bssid) <= len) ? sizeof(stats->bssid) : len); | |
| memcpy(&stats->bssid[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID]), len); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR]); | |
| len = ((sizeof(stats->ap_country_str) <= len) ? sizeof(stats->ap_country_str) : len); | |
| memcpy(&stats->ap_country_str[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR]), | |
| len); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR]); | |
| len = ((sizeof(stats->country_str) < len) ? sizeof(stats->country_str) : len); | |
| memcpy(&stats->country_str[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR]), | |
| len); | |
| #if QC_HAL_DEBUG | |
| ALOGV("Mode : %d\n" | |
| "Mac addr : " | |
| MAC_ADDR_STR | |
| "\nState : %d\n" | |
| "Roaming : %d\n" | |
| "capabilities : %0x\n" | |
| "SSID :%s\n" | |
| "BSSID : " | |
| MAC_ADDR_STR | |
| "\nAP country str : %c%c%c\n" | |
| "Country String for this Association : %c%c%c", | |
| stats->mode, | |
| MAC_ADDR_ARRAY(stats->mac_addr), | |
| stats->state, | |
| stats->roaming, | |
| stats->capabilities, | |
| stats->ssid, | |
| MAC_ADDR_ARRAY(stats->bssid), | |
| stats->ap_country_str[0], | |
| stats->ap_country_str[1], | |
| stats->ap_country_str[2], | |
| stats->country_str[0], | |
| stats->country_str[1], | |
| stats->country_str[2]); | |
| #endif | |
| return WIFI_SUCCESS; | |
| } | |
| static wifi_error get_wifi_wmm_ac_stat(wifi_wmm_ac_stat *stats, | |
| struct nlattr **tb_vendor) | |
| { | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->ac = (wifi_traffic_ac)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->tx_mpdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rx_mpdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->tx_mcast = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rx_mcast = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rx_ampdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->tx_ampdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->mpdu_lost = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->retries = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->retries_short = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->retries_long = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->contention_time_min = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->contention_time_max = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->contention_time_avg = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->contention_num_samples = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES]); | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV("%4u | %6u | %6u | %7u | %7u | %7u |" | |
| " %7u | %8u | %7u | %12u |" | |
| " %11u | %17u | %17u |" | |
| " %17u | %20u", | |
| stats->ac, | |
| stats->tx_mpdu, | |
| stats->rx_mpdu, | |
| stats->tx_mcast, | |
| stats->rx_mcast, | |
| stats->rx_ampdu, | |
| stats->tx_ampdu, | |
| stats->mpdu_lost, | |
| stats->retries, | |
| stats->retries_short, | |
| stats->retries_long, | |
| stats->contention_time_min, | |
| stats->contention_time_max, | |
| stats->contention_time_avg, | |
| stats->contention_num_samples); | |
| #endif | |
| return WIFI_SUCCESS; | |
| } | |
| static wifi_error get_wifi_rate_stat(wifi_rate_stat *stats, | |
| struct nlattr **tb_vendor) | |
| { | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rate.preamble = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rate.nss = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rate.bw = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rate.rateMcsIdx = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rate.bitrate = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->tx_mpdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rx_mpdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->mpdu_lost = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->retries = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->retries_short = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->retries_long = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG]); | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV("%8u | %3u | %2u | %10u | %7u | %6u | %6u | %8u | %7u | %12u | %11u", | |
| stats->rate.preamble, | |
| stats->rate.nss, | |
| stats->rate.bw, | |
| stats->rate.rateMcsIdx, | |
| stats->rate.bitrate, | |
| stats->tx_mpdu, | |
| stats->rx_mpdu, | |
| stats->mpdu_lost, | |
| stats->retries, | |
| stats->retries_short, | |
| stats->retries_long); | |
| #endif | |
| return WIFI_SUCCESS; | |
| } | |
| static wifi_error get_wifi_peer_info(wifi_peer_info *stats, | |
| struct nlattr **tb_vendor) | |
| { | |
| u32 i = 0, len = 0; | |
| int rem; | |
| wifi_rate_stat * pRateStats; | |
| struct nlattr *rateInfo; | |
| wifi_error ret = WIFI_SUCCESS; | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->type = (wifi_peer_type)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS]); | |
| len = ((sizeof(stats->peer_mac_address) <= len) ? sizeof(stats->peer_mac_address) : len); | |
| memcpy((void *)&stats->peer_mac_address[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS]), | |
| len); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->capabilities = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->num_rate = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES]); | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV("numPeers %u Peer MAC addr :" MAC_ADDR_STR " capabilities %0x numRate %u", | |
| stats->type, MAC_ADDR_ARRAY(stats->peer_mac_address), | |
| stats->capabilities, stats->num_rate); | |
| #endif | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV("%8s | %3s | %2s | %10s | %7s | %6s | %6s | %8s | %7s | %12s | %11s", | |
| "preamble", "nss", "bw", "rateMcsIdx", "bitrate", "txMpdu", "rxMpdu", "mpduLost", "retries", "retriesShort", "retriesLong"); | |
| #endif | |
| for (rateInfo = (struct nlattr *) nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO]), rem = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO]); | |
| nla_ok(rateInfo, rem); | |
| rateInfo = nla_next(rateInfo, &(rem))) | |
| { | |
| struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1]; | |
| pRateStats = (wifi_rate_stat *) ((u8 *)stats->rate_stats + (i++ * sizeof(wifi_rate_stat))); | |
| nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(rateInfo), nla_len(rateInfo), NULL); | |
| ret = get_wifi_rate_stat(pRateStats, tb2); | |
| if(ret != WIFI_SUCCESS) | |
| { | |
| return ret; | |
| } | |
| } | |
| return WIFI_SUCCESS; | |
| } | |
| wifi_error LLStatsCommand::get_wifi_iface_stats(wifi_iface_stat *stats, | |
| struct nlattr **tb_vendor) | |
| { | |
| struct nlattr *wmmInfo; | |
| wifi_wmm_ac_stat *pWmmStats; | |
| int i=0, rem; | |
| wifi_error ret = WIFI_SUCCESS; | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX" | |
| "not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->beacon_rx = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET]) | |
| { | |
| stats->average_tsf_offset = 0; | |
| } else { | |
| stats->average_tsf_offset = nla_get_u64(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET]); | |
| } | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED]) | |
| { | |
| stats->leaky_ap_detected = 0; | |
| } else { | |
| stats->leaky_ap_detected = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED]); | |
| } | |
| if (!tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED]) | |
| { | |
| stats->leaky_ap_avg_num_frames_leaked = 0; | |
| } else { | |
| stats->leaky_ap_avg_num_frames_leaked = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED]); | |
| } | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME]) | |
| { | |
| stats->leaky_ap_guard_time = 0; | |
| } else { | |
| stats->leaky_ap_guard_time = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME]); | |
| } | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX" | |
| " not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->mgmt_rx = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX]); | |
| if (!tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX]) | |
| { | |
| ALOGE("%s: " | |
| "QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX" | |
| " not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->mgmt_action_rx = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX]); | |
| if (!tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX]) | |
| { | |
| ALOGE("%s: " | |
| "QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX" | |
| " not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->mgmt_action_tx = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT" | |
| " not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rssi_mgmt = get_s32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA" | |
| " not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rssi_data = get_s32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK" | |
| " not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rssi_ack = get_s32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK]); | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV("WMM STATS"); | |
| ALOGV("beaconRx : %u " | |
| "mgmtRx : %u " | |
| "mgmtActionRx : %u " | |
| "mgmtActionTx : %u " | |
| "rssiMgmt : %d " | |
| "rssiData : %d " | |
| "rssiAck : %d ", | |
| stats->beacon_rx, | |
| stats->mgmt_rx, | |
| stats->mgmt_action_rx, | |
| stats->mgmt_action_tx, | |
| stats->rssi_mgmt, | |
| stats->rssi_data, | |
| stats->rssi_ack); | |
| #endif | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO" | |
| " not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV("%4s | %6s | %6s | %7s | %7s | %7s |" | |
| " %7s | %8s | %7s | %12s |" | |
| " %11s | %17s | %17s |" | |
| " %17s | %20s", | |
| "ac","txMpdu", "rxMpdu", "txMcast", "rxMcast", "rxAmpdu", | |
| "txAmpdu", "mpduLost", "retries", "retriesShort", | |
| "retriesLong", "contentionTimeMin", "contentionTimeMax", | |
| "contentionTimeAvg", "contentionNumSamples"); | |
| #endif | |
| for (wmmInfo = (struct nlattr *) nla_data(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO]), | |
| rem = nla_len(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO]); | |
| nla_ok(wmmInfo, rem); | |
| wmmInfo = nla_next(wmmInfo, &(rem))) | |
| { | |
| struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1]; | |
| pWmmStats = (wifi_wmm_ac_stat *) ((u8 *)stats->ac | |
| + (i++ * sizeof(wifi_wmm_ac_stat))); | |
| nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, | |
| (struct nlattr *) nla_data(wmmInfo), | |
| nla_len(wmmInfo), NULL); | |
| ret = get_wifi_wmm_ac_stat(pWmmStats, tb2); | |
| if(ret != WIFI_SUCCESS) | |
| { | |
| return ret; | |
| } | |
| } | |
| return WIFI_SUCCESS; | |
| } | |
| static wifi_error get_wifi_radio_stats(wifi_radio_stat *stats, | |
| struct nlattr **tb_vendor) | |
| { | |
| u32 i = 0; | |
| struct nlattr *chInfo; | |
| wifi_channel_stat *pChStats; | |
| int rem; | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->radio = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->on_time = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->tx_time = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME]); | |
| if (stats->num_tx_levels) { | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL]) { | |
| ALOGE("%s: num_tx_levels is %u but QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL not found", __func__, stats->num_tx_levels); | |
| stats->num_tx_levels = 0; | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->tx_time_per_levels = | |
| (u32 *) malloc(sizeof(u32) * stats->num_tx_levels); | |
| if (!stats->tx_time_per_levels) { | |
| ALOGE("%s: radio_stat: tx_time_per_levels malloc Failed", __func__); | |
| stats->num_tx_levels = 0; | |
| return WIFI_ERROR_OUT_OF_MEMORY; | |
| } | |
| nla_memcpy(stats->tx_time_per_levels, | |
| tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL], | |
| sizeof(u32) * stats->num_tx_levels); | |
| } | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->rx_time = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->on_time_scan = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->on_time_nbd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->on_time_gscan = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->on_time_roam_scan = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->on_time_pno_scan = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20 not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->on_time_hs20 = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| stats->num_channels = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS]); | |
| if (stats->num_channels == 0) { | |
| return WIFI_SUCCESS; | |
| } | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| for (chInfo = (struct nlattr *) nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO]), rem = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO]); | |
| nla_ok(chInfo, rem); | |
| chInfo = nla_next(chInfo, &(rem))) | |
| { | |
| struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1]; | |
| pChStats = (wifi_channel_stat *) ((u8 *)stats->channels + (i++ * (sizeof(wifi_channel_stat)))); | |
| nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(chInfo), nla_len(chInfo), NULL); | |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| pChStats->channel.width = (wifi_channel_width)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH]); | |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| pChStats->channel.center_freq = (wifi_channel)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ]); | |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0 not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| pChStats->channel.center_freq0 = (wifi_channel)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0]); | |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1 not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| pChStats->channel.center_freq1 = (wifi_channel)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1]); | |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| pChStats->on_time = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME]); | |
| if (!tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| pChStats->cca_busy_time = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME]); | |
| if (tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME]) | |
| pChStats->cca_busy_time -= nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME]); | |
| } | |
| return WIFI_SUCCESS; | |
| } | |
| void LLStatsCommand::getClearRspParams(u32 *stats_clear_rsp_mask, u8 *stop_rsp) | |
| { | |
| *stats_clear_rsp_mask = mClearRspParams.stats_clear_rsp_mask; | |
| *stop_rsp = mClearRspParams.stop_rsp; | |
| } | |
| wifi_error LLStatsCommand::requestResponse() | |
| { | |
| return WifiCommand::requestResponse(mMsg); | |
| } | |
| wifi_error LLStatsCommand::notifyResponse() | |
| { | |
| wifi_error ret = WIFI_SUCCESS; | |
| /* Indicate stats to framework only if both radio and iface stats | |
| * are present */ | |
| if (mResultsParams.radio_stat && mResultsParams.iface_stat) { | |
| if (mNumRadios > mNumRadiosAllocated) { | |
| ALOGE("%s: Force reset mNumRadios=%d to allocated=%d", | |
| __FUNCTION__, mNumRadios, mNumRadiosAllocated); | |
| mNumRadios = mNumRadiosAllocated; | |
| } | |
| mHandler.on_link_stats_results(mRequestId, | |
| mResultsParams.iface_stat, mNumRadios, | |
| mResultsParams.radio_stat); | |
| } else { | |
| ret = WIFI_ERROR_INVALID_ARGS; | |
| } | |
| clearStats(); | |
| return ret; | |
| } | |
| void LLStatsCommand::clearStats() | |
| { | |
| if(mResultsParams.radio_stat) | |
| { | |
| wifi_radio_stat *radioStat = mResultsParams.radio_stat; | |
| if (mNumRadios > mNumRadiosAllocated) { | |
| ALOGE("%s: Force reset mNumRadios=%d to allocated=%d", | |
| __FUNCTION__, mNumRadios, mNumRadiosAllocated); | |
| mNumRadios = mNumRadiosAllocated; | |
| } | |
| for (u8 radio = 0; radio < mNumRadios; radio++) { | |
| if (radioStat->tx_time_per_levels) { | |
| free(radioStat->tx_time_per_levels); | |
| radioStat->tx_time_per_levels = NULL; | |
| } | |
| radioStat = (wifi_radio_stat *)((u8 *)radioStat + | |
| sizeof(wifi_radio_stat) + (sizeof(wifi_channel_stat) * | |
| radioStat->num_channels)); | |
| } | |
| free(mResultsParams.radio_stat); | |
| mResultsParams.radio_stat = NULL; | |
| mRadioStatsSize = 0; | |
| mNumRadios = 0; | |
| mNumRadiosAllocated = 0; | |
| } | |
| if(mResultsParams.iface_stat) | |
| { | |
| free(mResultsParams.iface_stat); | |
| mResultsParams.iface_stat = NULL; | |
| } | |
| } | |
| int LLStatsCommand::handleResponse(WifiEvent &reply) | |
| { | |
| unsigned i=0; | |
| int status = WIFI_ERROR_NONE; | |
| WifiVendorCommand::handleResponse(reply); | |
| // Parse the vendordata and get the attribute | |
| switch(mSubcmd) | |
| { | |
| case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET: | |
| { | |
| u32 resultsBufSize = 0; | |
| struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX + 1]; | |
| int rem; | |
| wifi_radio_stat *radioStatsBuf; | |
| nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, | |
| (struct nlattr *)mVendorData, | |
| mDataLen, NULL); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE not found", | |
| __FUNCTION__); | |
| status = WIFI_ERROR_INVALID_ARGS; | |
| goto cleanup; | |
| } | |
| switch(nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE])) | |
| { | |
| case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_RADIO: | |
| { | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS" | |
| " not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| mNumRadios = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS]); | |
| if (!tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS | |
| ]) | |
| { | |
| ALOGE("%s:" | |
| "QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS" | |
| " not found", __FUNCTION__); | |
| status = WIFI_ERROR_INVALID_ARGS; | |
| goto cleanup; | |
| } | |
| resultsBufSize += (nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS]) | |
| * sizeof(wifi_channel_stat) | |
| + sizeof(wifi_radio_stat)); | |
| radioStatsBuf = (wifi_radio_stat *)realloc( | |
| mResultsParams.radio_stat, | |
| mRadioStatsSize + resultsBufSize); | |
| if (!radioStatsBuf) | |
| { | |
| ALOGE("%s: radio_stat: malloc Failed", __FUNCTION__); | |
| status = WIFI_ERROR_OUT_OF_MEMORY; | |
| goto cleanup; | |
| } | |
| mResultsParams.radio_stat = radioStatsBuf; | |
| //Move the buffer to populate current radio stats | |
| radioStatsBuf = (wifi_radio_stat *)( | |
| (u8 *)mResultsParams.radio_stat | |
| + mRadioStatsSize); | |
| memset(radioStatsBuf, 0, resultsBufSize); | |
| mRadioStatsSize += resultsBufSize; | |
| mNumRadiosAllocated ++; | |
| if (tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS]) | |
| radioStatsBuf->num_tx_levels = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS]); | |
| wifi_channel_stat *pWifiChannelStats; | |
| status = get_wifi_radio_stats(radioStatsBuf, | |
| tb_vendor); | |
| if(status != WIFI_SUCCESS) | |
| { | |
| goto cleanup; | |
| } | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV("radio :%u onTime :%u txTime :%u rxTime :%u" | |
| " onTimeScan :%u onTimeNbd :%u onTimeGscan :%u" | |
| " onTimeRoamScan :%u onTimePnoScan :%u" | |
| " onTimeHs20 :%u numChannels :%u num_tx_levels: %u", | |
| radioStatsBuf->radio, | |
| radioStatsBuf->on_time, | |
| radioStatsBuf->tx_time, | |
| radioStatsBuf->rx_time, | |
| radioStatsBuf->on_time_scan, | |
| radioStatsBuf->on_time_nbd, | |
| radioStatsBuf->on_time_gscan, | |
| radioStatsBuf->on_time_roam_scan, | |
| radioStatsBuf->on_time_pno_scan, | |
| radioStatsBuf->on_time_hs20, | |
| radioStatsBuf->num_channels, | |
| radioStatsBuf->num_tx_levels); | |
| #ifdef QC_HAL_DEBUG | |
| for (i = 0; i < radioStatsBuf->num_tx_levels; i++) { | |
| ALOGV("Power level: %u tx_time: %u", i, | |
| radioStatsBuf->tx_time_per_levels[i]); | |
| } | |
| #endif | |
| ALOGV("%5s | %10s | %11s | %11s | %6s | %11s", "width", | |
| "CenterFreq", "CenterFreq0", "CenterFreq1", | |
| "onTime", "ccaBusyTime"); | |
| #endif | |
| for ( i=0; i < radioStatsBuf->num_channels; i++) | |
| { | |
| pWifiChannelStats = | |
| (wifi_channel_stat *) ( | |
| (u8 *)radioStatsBuf->channels | |
| + (i * sizeof(wifi_channel_stat))); | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV("%5u | %10u | %11u | %11u | %6u | %11u", | |
| pWifiChannelStats->channel.width, | |
| pWifiChannelStats->channel.center_freq, | |
| pWifiChannelStats->channel.center_freq0, | |
| pWifiChannelStats->channel.center_freq1, | |
| pWifiChannelStats->on_time, | |
| pWifiChannelStats->cca_busy_time); | |
| #endif | |
| } | |
| } | |
| break; | |
| case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_IFACE: | |
| { | |
| resultsBufSize = sizeof(wifi_iface_stat); | |
| mResultsParams.iface_stat = | |
| (wifi_iface_stat *) malloc (resultsBufSize); | |
| if (!mResultsParams.iface_stat) | |
| { | |
| ALOGE("%s: iface_stat: malloc Failed", __FUNCTION__); | |
| status = WIFI_ERROR_OUT_OF_MEMORY; | |
| goto cleanup; | |
| } | |
| memset(mResultsParams.iface_stat, 0, resultsBufSize); | |
| status = get_wifi_interface_info( | |
| &mResultsParams.iface_stat->info, tb_vendor); | |
| if(status != WIFI_SUCCESS) | |
| { | |
| goto cleanup; | |
| } | |
| status = get_wifi_iface_stats(mResultsParams.iface_stat, | |
| tb_vendor); | |
| if(status != WIFI_SUCCESS) | |
| { | |
| goto cleanup; | |
| } | |
| /* Driver/firmware might send this attribute when there | |
| * are no peers connected. | |
| * So that, the event | |
| * QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS can be | |
| * avoided. | |
| */ | |
| if (tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS]) | |
| { | |
| mResultsParams.iface_stat->num_peers = | |
| nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS]); | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV("%s: numPeers is %u\n", __FUNCTION__, | |
| mResultsParams.iface_stat->num_peers); | |
| #endif | |
| } | |
| } | |
| break; | |
| case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS: | |
| { | |
| struct nlattr *peerInfo; | |
| wifi_iface_stat *pIfaceStat = NULL; | |
| u32 numPeers, num_rates = 0; | |
| if (!tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS]) | |
| { | |
| ALOGE("%s:QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS" | |
| " not found", __FUNCTION__); | |
| status = WIFI_ERROR_INVALID_ARGS; | |
| goto cleanup; | |
| } | |
| #ifdef QC_HAL_DEBUG | |
| ALOGV(" numPeers is %u in %s\n", | |
| nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS]), | |
| __FUNCTION__); | |
| #endif | |
| if((numPeers = nla_get_u32(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS])) > 0) | |
| { | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO" | |
| " not found", __FUNCTION__); | |
| status = WIFI_ERROR_INVALID_ARGS; | |
| goto cleanup; | |
| } | |
| for (peerInfo = (struct nlattr *) nla_data(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO]), | |
| rem = nla_len(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO]); | |
| nla_ok(peerInfo, rem); | |
| peerInfo = nla_next(peerInfo, &(rem))) | |
| { | |
| struct nlattr *tb2[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1]; | |
| nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, | |
| (struct nlattr *) nla_data(peerInfo), | |
| nla_len(peerInfo), NULL); | |
| if (!tb2[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES]) | |
| { | |
| ALOGE("%s:" | |
| "QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES" | |
| " not found", __FUNCTION__); | |
| status = WIFI_ERROR_INVALID_ARGS; | |
| goto cleanup; | |
| } | |
| num_rates += nla_get_u32(tb2[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES]); | |
| } | |
| resultsBufSize += (numPeers * sizeof(wifi_peer_info) | |
| + num_rates * sizeof(wifi_rate_stat) | |
| + sizeof (wifi_iface_stat)); | |
| pIfaceStat = (wifi_iface_stat *) malloc ( | |
| resultsBufSize); | |
| if (!pIfaceStat) | |
| { | |
| ALOGE("%s: pIfaceStat: malloc Failed", __FUNCTION__); | |
| status = WIFI_ERROR_OUT_OF_MEMORY; | |
| goto cleanup; | |
| } | |
| memset(pIfaceStat, 0, resultsBufSize); | |
| if(mResultsParams.iface_stat) { | |
| if(resultsBufSize >= sizeof(wifi_iface_stat)) { | |
| memcpy ( pIfaceStat, mResultsParams.iface_stat, | |
| sizeof(wifi_iface_stat)); | |
| free (mResultsParams.iface_stat); | |
| mResultsParams.iface_stat = pIfaceStat; | |
| } else { | |
| ALOGE("%s: numPeers = %u, num_rates= %u, " | |
| "either numPeers or num_rates is invalid", | |
| __FUNCTION__,numPeers,num_rates); | |
| status = WIFI_ERROR_UNKNOWN; | |
| free(pIfaceStat); | |
| goto cleanup; | |
| } | |
| } | |
| wifi_peer_info *pPeerStats; | |
| pIfaceStat->num_peers = numPeers; | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO" | |
| " not found", __FUNCTION__); | |
| status = WIFI_ERROR_INVALID_ARGS; | |
| goto cleanup; | |
| } | |
| num_rates = 0; | |
| for (peerInfo = (struct nlattr *) nla_data(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO]), | |
| rem = nla_len(tb_vendor[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO]); | |
| nla_ok(peerInfo, rem); | |
| peerInfo = nla_next(peerInfo, &(rem))) | |
| { | |
| struct nlattr *tb2[ | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1]; | |
| pPeerStats = (wifi_peer_info *) ( | |
| (u8 *)pIfaceStat->peer_info | |
| + (i++ * sizeof(wifi_peer_info)) | |
| + (num_rates * sizeof(wifi_rate_stat))); | |
| nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, | |
| (struct nlattr *) nla_data(peerInfo), | |
| nla_len(peerInfo), NULL); | |
| status = get_wifi_peer_info(pPeerStats, tb2); | |
| if(status != WIFI_SUCCESS) | |
| { | |
| goto cleanup; | |
| } | |
| num_rates += pPeerStats->num_rate; | |
| } | |
| } | |
| } | |
| break; | |
| case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_INVALID: | |
| default: | |
| //error case should not happen print log | |
| ALOGE("%s: Wrong LLStats subcmd received %d", __FUNCTION__, | |
| mSubcmd); | |
| } | |
| } | |
| break; | |
| case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR: | |
| { | |
| struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1]; | |
| nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX, | |
| (struct nlattr *)mVendorData, | |
| mDataLen, NULL); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| ALOGI("Resp mask : %d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK])); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| ALOGI("STOP resp : %d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP])); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| mClearRspParams.stats_clear_rsp_mask = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK]); | |
| if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP]) | |
| { | |
| ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP not found", __FUNCTION__); | |
| return WIFI_ERROR_INVALID_ARGS; | |
| } | |
| mClearRspParams.stop_rsp = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP]); | |
| break; | |
| } | |
| default : | |
| ALOGE("%s: Wrong LLStats subcmd received %d", __FUNCTION__, mSubcmd); | |
| } | |
| return NL_SKIP; | |
| cleanup: | |
| clearStats(); | |
| return status; | |
| } | |
| //Implementation of the functions exposed in linklayer.h | |
| wifi_error wifi_set_link_stats(wifi_interface_handle iface, | |
| wifi_link_layer_params params) | |
| { | |
| wifi_error ret; | |
| LLStatsCommand *LLCommand; | |
| struct nlattr *nl_data; | |
| interface_info *iinfo = getIfaceInfo(iface); | |
| wifi_handle handle = getWifiHandle(iface); | |
| ALOGI("mpdu_size_threshold : %u, aggressive_statistics_gathering : %u", | |
| params.mpdu_size_threshold, params.aggressive_statistics_gathering); | |
| LLCommand = LLStatsCommand::instance(handle); | |
| if (LLCommand == NULL) { | |
| ALOGE("%s: Error LLStatsCommand NULL", __FUNCTION__); | |
| return WIFI_ERROR_UNKNOWN; | |
| } | |
| LLCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET); | |
| /* create the message */ | |
| ret = LLCommand->create(); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| ret = LLCommand->set_iface_id(iinfo->name); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| /*add the attributes*/ | |
| nl_data = LLCommand->attr_start(NL80211_ATTR_VENDOR_DATA); | |
| if (!nl_data) | |
| goto cleanup; | |
| /**/ | |
| ret = LLCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD, | |
| params.mpdu_size_threshold); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| /**/ | |
| ret = LLCommand->put_u32( | |
| QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING, | |
| params.aggressive_statistics_gathering); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| LLCommand->attr_end(nl_data); | |
| ret = LLCommand->requestResponse(); | |
| if (ret != WIFI_SUCCESS) | |
| ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret); | |
| cleanup: | |
| return ret; | |
| } | |
| //Implementation of the functions exposed in LLStats.h | |
| wifi_error wifi_get_link_stats(wifi_request_id id, | |
| wifi_interface_handle iface, | |
| wifi_stats_result_handler handler) | |
| { | |
| wifi_error ret; | |
| LLStatsCommand *LLCommand; | |
| struct nlattr *nl_data; | |
| interface_info *iinfo = getIfaceInfo(iface); | |
| wifi_handle handle = getWifiHandle(iface); | |
| LLCommand = LLStatsCommand::instance(handle); | |
| if (LLCommand == NULL) { | |
| ALOGE("%s: Error LLStatsCommand NULL", __FUNCTION__); | |
| return WIFI_ERROR_UNKNOWN; | |
| } | |
| LLCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET); | |
| LLCommand->initGetContext(id); | |
| LLCommand->setHandler(handler); | |
| /* create the message */ | |
| ret = LLCommand->create(); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| ret = LLCommand->set_iface_id(iinfo->name); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| /*add the attributes*/ | |
| nl_data = LLCommand->attr_start(NL80211_ATTR_VENDOR_DATA); | |
| if (!nl_data) | |
| goto cleanup; | |
| ret = LLCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID, | |
| id); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| ret = LLCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK, | |
| 7); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| /**/ | |
| LLCommand->attr_end(nl_data); | |
| ret = LLCommand->requestResponse(); | |
| if (ret != WIFI_SUCCESS) | |
| ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret); | |
| if (ret != WIFI_SUCCESS) { | |
| LLCommand->clearStats(); | |
| goto cleanup; | |
| } | |
| if (ret == WIFI_SUCCESS) | |
| ret = LLCommand->notifyResponse(); | |
| cleanup: | |
| return ret; | |
| } | |
| //Implementation of the functions exposed in LLStats.h | |
| wifi_error wifi_clear_link_stats(wifi_interface_handle iface, | |
| u32 stats_clear_req_mask, | |
| u32 *stats_clear_rsp_mask, | |
| u8 stop_req, u8 *stop_rsp) | |
| { | |
| wifi_error ret; | |
| LLStatsCommand *LLCommand; | |
| struct nlattr *nl_data; | |
| interface_info *iinfo = getIfaceInfo(iface); | |
| wifi_handle handle = getWifiHandle(iface); | |
| ALOGI("clear_req : %x, stop_req : %u", stats_clear_req_mask, stop_req); | |
| LLCommand = LLStatsCommand::instance(handle); | |
| if (LLCommand == NULL) { | |
| ALOGE("%s: Error LLStatsCommand NULL", __FUNCTION__); | |
| return WIFI_ERROR_UNKNOWN; | |
| } | |
| LLCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR); | |
| /* create the message */ | |
| ret = LLCommand->create(); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| ret = LLCommand->set_iface_id(iinfo->name); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| /*add the attributes*/ | |
| nl_data = LLCommand->attr_start(NL80211_ATTR_VENDOR_DATA); | |
| if (!nl_data) | |
| goto cleanup; | |
| /**/ | |
| ret = LLCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK, | |
| stats_clear_req_mask); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| /**/ | |
| ret = LLCommand->put_u8(QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ, | |
| stop_req); | |
| if (ret != WIFI_SUCCESS) | |
| goto cleanup; | |
| LLCommand->attr_end(nl_data); | |
| ret = LLCommand->requestResponse(); | |
| if (ret != WIFI_SUCCESS) | |
| ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret); | |
| LLCommand->getClearRspParams(stats_clear_rsp_mask, stop_rsp); | |
| cleanup: | |
| delete LLCommand; | |
| return ret; | |
| } |