/* * 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 #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 int LLStatsCommand::create() { int ifindex; 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; ALOGI("mVendor_id = %d, Subcmd = %d in %s:%d\n", mVendor_id, mSubcmd, __func__, __LINE__); out: return ret; } LLStatsCommand::LLStatsCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd) : WifiVendorCommand(handle, id, vendor_id, subcmd) { ALOGV("LLStatsCommand %p constructed", this); memset(&mClearRspParams, 0,sizeof(LLStatsClearRspParams)); memset(&mResultsParams, 0,sizeof(LLStatsResultsParams)); memset(&mHandler, 0,sizeof(mHandler)); } LLStatsCommand::~LLStatsCommand() { ALOGW("LLStatsCommand %p distructor", this); mLLStatsCommandInstance = NULL; unregisterVendorHandler(mVendor_id, mSubcmd); } 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); ALOGV("LLStatsCommand %p created", mLLStatsCommandInstance); return mLLStatsCommandInstance; } else { if (handle != getWifiHandle(mLLStatsCommandInstance->mInfo)) { ALOGE("Handle different"); return NULL; } } ALOGV("LLStatsCommand %p created already", mLLStatsCommandInstance); return mLLStatsCommandInstance; } void LLStatsCommand::initGetContext(u32 reqId) { mRequestId = reqId; memset(&mResultsParams, 0,sizeof(LLStatsResultsParams)); memset(&mHandler, 0,sizeof(mHandler)); } void LLStatsCommand::setSubCmd(u32 subcmd) { mSubcmd = subcmd; } //callback handlers registered for nl message send static int error_handler_LLStats(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { struct sockaddr_nl * tmp; int *ret = (int *)arg; tmp = nla; *ret = err->error; ALOGE("%s: Error code:%d (%s)", __func__, *ret, strerror(-(*ret))); return NL_STOP; } //callback handlers registered for nl message send static int ack_handler_LLStats(struct nl_msg *msg, void *arg) { int *ret = (int *)arg; struct nl_msg * a; ALOGE("%s: called", __func__); a = msg; *ret = 0; return NL_STOP; } //callback handlers registered for nl message send static int finish_handler_LLStats(struct nl_msg *msg, void *arg) { int *ret = (int *)arg; struct nl_msg * a; ALOGE("%s: called", __func__); a = msg; *ret = 0; return NL_SKIP; } static void get_wifi_interface_info(wifi_interface_link_layer_info *stats, struct nlattr **tb_vendor) { u32 len = 0; u8 *data; stats->mode = (wifi_interface_mode)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE]); 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); stats->state = (wifi_connection_state)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE]); stats->roaming = (wifi_roam_state)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING]); stats->capabilities = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES]); 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); 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); 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); 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); ALOGI("STATS IFACE: Mode %d", stats->mode); ALOGI("STATS IFACE: MAC %pM", stats->mac_addr); ALOGI("STATS IFACE: State %d ", stats->state); ALOGI("STATS IFACE: Roaming %d ", stats->roaming); ALOGI("STATS IFACE: capabilities %0x ", stats->capabilities); ALOGI("STATS IFACE: SSID %s ", stats->ssid); ALOGI("STATS IFACE: BSSID %pM ", stats->bssid); ALOGI("STATS IFACE: AP country str %c%c%c ", stats->ap_country_str[0], stats->ap_country_str[1], stats->ap_country_str[2]); ALOGI("STATS IFACE:Country String for this Association %c%c%c", stats->country_str[0], stats->country_str[1], stats->country_str[2]); } static void get_wifi_wmm_ac_stat(wifi_wmm_ac_stat *stats, struct nlattr **tb_vendor) { stats->ac = (wifi_traffic_ac)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC]); stats->tx_mpdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU]); stats->rx_mpdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU]); stats->tx_mcast = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST]); stats->rx_mcast = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST]); stats->rx_ampdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU]); stats->tx_ampdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU]); stats->mpdu_lost = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST]); stats->retries = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES]); stats->retries_short = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT]); stats->retries_long = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG]); stats->contention_time_min = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN]); stats->contention_time_max = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX]); stats->contention_time_avg = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG]); stats->contention_num_samples = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES]); ALOGI("STATS IFACE: ac %u ", stats->ac); ALOGI("STATS IFACE: txMpdu %u ", stats->tx_mpdu) ; ALOGI("STATS IFACE: rxMpdu %u ", stats->rx_mpdu); ALOGI("STATS IFACE: txMcast %u ", stats->tx_mcast); ALOGI("STATS IFACE: rxMcast %u ", stats->rx_mcast); ALOGI("STATS IFACE: rxAmpdu %u ", stats->rx_ampdu); ALOGI("STATS IFACE: txAmpdu %u ", stats->tx_ampdu); ALOGI("STATS IFACE: mpduLost %u ", stats->mpdu_lost); ALOGI("STATS IFACE: retries %u ", stats->retries); ALOGI("STATS IFACE: retriesShort %u ", stats->retries_short); ALOGI("STATS IFACE: retriesLong %u ", stats->retries_long); ALOGI("STATS IFACE: contentionTimeMin %u ", stats->contention_time_min); ALOGI("STATS IFACE: contentionTimeMax %u ", stats->contention_time_max); ALOGI("STATS IFACE: contentionTimeAvg %u ", stats->contention_time_avg); ALOGI("STATS IFACE: contentionNumSamples %u ", stats->contention_num_samples); } static void get_wifi_rate_stat(wifi_rate_stat *stats, struct nlattr **tb_vendor) { stats->rate.preamble = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE]); stats->rate.nss = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS]); stats->rate.bw = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW]); stats->rate.rateMcsIdx = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX]); stats->rate.bitrate = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE]); stats->tx_mpdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU]); stats->rx_mpdu = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU]); stats->mpdu_lost = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST]); stats->retries = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES]); stats->retries_short = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT]); stats->retries_long = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG]); ALOGI("STATS PEER_ALL : preamble %u", stats->rate.preamble); ALOGI("STATS PEER_ALL : nss %u", stats->rate.nss); ALOGI("STATS PEER_ALL : bw %u", stats->rate.bw); ALOGI("STATS PEER_ALL : rateMcsIdx %u", stats->rate.rateMcsIdx); ALOGI("STATS PEER_ALL : bitrate %u", stats->rate.bitrate); ALOGI("STATS PEER_ALL : txMpdu %u", stats->tx_mpdu); ALOGI("STATS PEER_ALL : rxMpdu %u", stats->rx_mpdu); ALOGI("STATS PEER_ALL : mpduLost %u", stats->mpdu_lost); ALOGI("STATS PEER_ALL : retries %u", stats->retries); ALOGI("STATS PEER_ALL : retriesShort %u", stats->retries_short); ALOGI("STATS PEER_ALL : retriesLong %u", stats->retries_long); } static void 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; stats->type = (wifi_peer_type)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE]); 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); stats->capabilities = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES]); stats->num_rate = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES]); ALOGI("STATS PEER_ALL : numPeers %u", stats->type); ALOGI("STATS PEER_ALL : peerMacAddress %0x:%0x:%0x:%0x:%0x:%0x ", stats->peer_mac_address[0], stats->peer_mac_address[1], stats->peer_mac_address[2],stats->peer_mac_address[3], stats->peer_mac_address[4],stats->peer_mac_address[5]); ALOGI("STATS PEER_ALL : capabilities %0x", stats->capabilities); ALOGI("STATS PEER_ALL : numRate %u", stats->num_rate); 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); get_wifi_rate_stat(pRateStats, tb2); } } static void get_wifi_iface_stats(wifi_iface_stat *stats, struct nlattr **tb_vendor) { struct nlattr *wmmInfo; wifi_wmm_ac_stat *pWmmStats; int i=0, rem; stats->beacon_rx = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX]); stats->mgmt_rx = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX]); stats->mgmt_action_rx = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX]); stats->mgmt_action_tx = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX]); stats->rssi_mgmt = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT]); stats->rssi_data = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA]); stats->rssi_ack = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK]); ALOGI("STATS IFACE: beaconRx : %u ", stats->beacon_rx); ALOGI("STATS IFACE: mgmtRx %u ", stats->mgmt_rx); ALOGI("STATS IFACE: mgmtActionRx %u ", stats->mgmt_action_rx); ALOGI("STATS IFACE: mgmtActionTx %u ", stats->mgmt_action_tx); ALOGI("STATS IFACE: rssiMgmt %u ", stats->rssi_mgmt); ALOGI("STATS IFACE: rssiData %u ", stats->rssi_data); ALOGI("STATS IFACE: rssiAck %u ", stats->rssi_ack); 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); get_wifi_wmm_ac_stat(pWmmStats, tb2); } } static void get_wifi_radio_stats(wifi_radio_stat *stats, struct nlattr **tb_vendor) { u32 i = 0; struct nlattr *chInfo; wifi_channel_stat *pChStats; int rem; printf("sunil %d : %s \n",__LINE__,__func__); stats->radio = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID]); printf("sunil %d : %s \n",__LINE__,__func__); stats->on_time = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME]); printf("sunil %d : %s \n",__LINE__,__func__); stats->tx_time = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME]); printf("sunil %d : %s \n",__LINE__,__func__); stats->rx_time = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME]); ALOGI("<<<< rxTime is %u ", stats->rx_time); stats->on_time_scan = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN]); stats->on_time_nbd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD]); stats->on_time_gscan = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN]); stats->on_time_roam_scan = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN]); stats->on_time_pno_scan = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN]); stats->on_time_hs20 = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20]); stats->num_channels = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS]); 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); pChStats->channel.width = (wifi_channel_width)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH]); pChStats->channel.center_freq = (wifi_channel)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ]); pChStats->channel.center_freq0 = (wifi_channel)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0]); pChStats->channel.center_freq1 = (wifi_channel)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1]); pChStats->on_time = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME]); pChStats->cca_busy_time = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME]); } } // This function will be the main handler for incoming event LLStats_SUBCMD //Call the appropriate callback handler after parsing the vendor data. int LLStatsCommand::handleEvent(WifiEvent &event) { ALOGI("Got a LLStats message from Driver"); unsigned i=0; u32 status; WifiVendorCommand::handleEvent(event); // Parse the vendordata and get the attribute switch(mSubcmd) { case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS: { wifi_request_id id; u32 resultsBufSize = 0; struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX + 1]; int rem; nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *)mVendorData, mDataLen, NULL); resultsBufSize += (nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS]) * sizeof(wifi_channel_stat) + sizeof(wifi_radio_stat)); mResultsParams.radio_stat = (wifi_radio_stat *)malloc(resultsBufSize); memset(mResultsParams.radio_stat, 0, resultsBufSize); ALOGI(" rxTime is %u\n ", mResultsParams.radio_stat->rx_time); ALOGI(" NumChan is %d\n ", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS])); if(mResultsParams.radio_stat){ wifi_channel_stat *pWifiChannelStats; u32 i =0; printf("sunil %d : %s \n",__LINE__,__func__); get_wifi_radio_stats(mResultsParams.radio_stat, tb_vendor); ALOGI(" radio is %u ", mResultsParams.radio_stat->radio); ALOGI(" onTime is %u ", mResultsParams.radio_stat->on_time); ALOGI(" txTime is %u ", mResultsParams.radio_stat->tx_time); ALOGI(" rxTime is %u ", mResultsParams.radio_stat->rx_time); ALOGI(" onTimeScan is %u ", mResultsParams.radio_stat->on_time_scan); ALOGI(" onTimeNbd is %u ", mResultsParams.radio_stat->on_time_nbd); ALOGI(" onTimeGscan is %u ", mResultsParams.radio_stat->on_time_gscan); ALOGI(" onTimeRoamScan is %u", mResultsParams.radio_stat->on_time_roam_scan); ALOGI(" onTimePnoScan is %u ", mResultsParams.radio_stat->on_time_pno_scan); ALOGI(" onTimeHs20 is %u ", mResultsParams.radio_stat->on_time_hs20); ALOGI(" numChannels is %u ", mResultsParams.radio_stat->num_channels); for ( i=0; i < mResultsParams.radio_stat->num_channels; i++) { pWifiChannelStats = (wifi_channel_stat *) ((u8 *)mResultsParams.radio_stat->channels + (i * sizeof(wifi_channel_stat))); ALOGI(" width is %u ", pWifiChannelStats->channel.width); ALOGI(" CenterFreq %u ", pWifiChannelStats->channel.center_freq); ALOGI(" CenterFreq0 %u ", pWifiChannelStats->channel.center_freq0); ALOGI(" CenterFreq1 %u ", pWifiChannelStats->channel.center_freq1); ALOGI(" onTime %u ", pWifiChannelStats->on_time); ALOGI(" ccaBusyTime %u ", pWifiChannelStats->cca_busy_time); } ALOGI(" rxTime is %u in %s:%d\n", mResultsParams.radio_stat->rx_time, __func__, __LINE__); } } break; case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS: { wifi_request_id id; u32 resultsBufSize = 0; struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX + 1]; nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *)mVendorData, mDataLen, NULL); resultsBufSize = sizeof(wifi_iface_stat); // Do we need no.of peers here?? mResultsParams.iface_stat = (wifi_iface_stat *) malloc (sizeof (wifi_iface_stat)); get_wifi_interface_info(&mResultsParams.iface_stat->info, tb_vendor); get_wifi_iface_stats(mResultsParams.iface_stat, tb_vendor); } break; case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS: { wifi_request_id id; u32 resultsBufSize = 0, i=0, num_rates = 0; u32 numPeers; int rem; struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX + 1]; struct nlattr *peerInfo; wifi_iface_stat *pIfaceStat; nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *)mVendorData, mDataLen, NULL); ALOGI(" rxTime is %u in %s:%d\n", mResultsParams.radio_stat->rx_time, __func__, __LINE__); ALOGI(" numPeers is %u in %s:%d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS]), __func__, __LINE__); ALOGI(" rxTe is %u in %s:%d\n", mResultsParams.radio_stat->rx_time, __func__, __LINE__); if((numPeers = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS])) > 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]; nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(peerInfo), nla_len(peerInfo), NULL); 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){ memcpy ( pIfaceStat, mResultsParams.iface_stat , sizeof(wifi_iface_stat)); wifi_peer_info *pPeerStats; pIfaceStat->num_peers = numPeers; 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))); nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(peerInfo), nla_len(peerInfo), NULL); get_wifi_peer_info(pPeerStats, tb2); } } if(mResultsParams.iface_stat) free (mResultsParams.iface_stat); mResultsParams.iface_stat = pIfaceStat; } // Number of Radios are 1 for now : TODO get this info from the driver mHandler.on_link_stats_results(mRequestId, mResultsParams.iface_stat, 1, mResultsParams.radio_stat); if(mResultsParams.radio_stat) { free(mResultsParams.radio_stat); mResultsParams.radio_stat = NULL; } if(mResultsParams.iface_stat) { free(mResultsParams.iface_stat); mResultsParams.iface_stat = NULL; } } break; default: //error case should not happen print log ALOGE("%s: Wrong LLStats subcmd received %d", __func__, mSubcmd); } return NL_SKIP; } int LLStatsCommand::setCallbackHandler(LLStatsCallbackHandler nHandler, u32 event) { int res = 0; mHandler = nHandler; res = registerVendorHandler(mVendor_id, event); if (res != 0) { //error case should not happen print log ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u", __func__, mVendor_id, mSubcmd); } return res; } void LLStatsCommand::unregisterHandler(u32 subCmd) { unregisterVendorHandler(mVendor_id, subCmd); } 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; } int LLStatsCommand::requestResponse() { return WifiCommand::requestResponse(mMsg); } int LLStatsCommand::handleResponse(WifiEvent &reply) { ALOGI("Got a LLStats message from Driver"); unsigned i=0; u32 status; WifiVendorCommand::handleResponse(reply); // Parse the vendordata and get the attribute switch(mSubcmd) { 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); ALOGI("Resp mask : %d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK])); ALOGI("STOP resp : %d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP])); mClearRspParams.stats_clear_rsp_mask = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK]); 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", __func__, mSubcmd); } return NL_SKIP; } //Implementation of the functions exposed in linklayer.h wifi_error wifi_set_link_stats(wifi_interface_handle iface, wifi_link_layer_params params) { int ret = 0; 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", __func__); return WIFI_ERROR_UNKNOWN; } LLCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET); /* create the message */ ret = LLCommand->create(); if (ret < 0) goto cleanup; ret = LLCommand->set_iface_id(iinfo->name); if (ret < 0) 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 < 0) goto cleanup; /**/ ret = LLCommand->put_u32( QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING, params.aggressive_statistics_gathering); if (ret < 0) goto cleanup; LLCommand->attr_end(nl_data); ret = LLCommand->requestResponse(); if (ret != 0) { ALOGE("%s: requestResponse Error:%d",__func__, ret); } cleanup: return (wifi_error)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) { int ret = 0; LLStatsCommand *LLCommand; struct nlattr *nl_data; interface_info *iinfo = getIfaceInfo(iface); wifi_handle handle = getWifiHandle(iface); pthread_t tid; LLCommand = LLStatsCommand::instance(handle); if (LLCommand == NULL) { ALOGE("%s: Error LLStatsCommand NULL", __func__); return WIFI_ERROR_UNKNOWN; } LLCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET); LLCommand->initGetContext(id); LLStatsCallbackHandler callbackHandler = { .on_link_stats_results = handler.on_link_stats_results }; /* create the message */ ret = LLCommand->create(); if (ret < 0) goto cleanup; ret = LLCommand->set_iface_id(iinfo->name); if (ret < 0) 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 < 0) goto cleanup; ret = LLCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK, 7); if (ret < 0) goto cleanup; /**/ LLCommand->attr_end(nl_data); ret = LLCommand->requestResponse(); if (ret != 0) { ALOGE("%s: requestResponse Error:%d",__func__, ret); } if (ret < 0) goto cleanup; ret = LLCommand->setCallbackHandler(callbackHandler, QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS); if (ret < 0) goto cleanup; ret = LLCommand->setCallbackHandler(callbackHandler, QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS); if (ret < 0) goto cleanup; ret = LLCommand->setCallbackHandler(callbackHandler, QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS); if (ret < 0) goto cleanup; cleanup: return (wifi_error)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) { int ret = 0; 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", __func__); return WIFI_ERROR_UNKNOWN; } LLCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR); /* create the message */ ret = LLCommand->create(); if (ret < 0) goto cleanup; ret = LLCommand->set_iface_id(iinfo->name); if (ret < 0) 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 < 0) goto cleanup; /**/ ret = LLCommand->put_u8(QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ, stop_req); if (ret < 0) goto cleanup; LLCommand->attr_end(nl_data); ret = LLCommand->requestResponse(); if (ret != 0) { ALOGE("%s: requestResponse Error:%d",__func__, ret); } LLCommand->getClearRspParams(stats_clear_rsp_mask, stop_rsp); cleanup: LLCommand->unregisterHandler(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS); LLCommand->unregisterHandler(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS); LLCommand->unregisterHandler(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS); delete LLCommand; return (wifi_error)ret; }