1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "sync.h"
18 
19 #define LOG_TAG  "WifiHAL"
20 
21 #include <utils/Log.h>
22 
23 #include "wifi_hal.h"
24 #include "common.h"
25 #include "cpp_bindings.h"
26 #include "llstatscommand.h"
27 
28 //Singleton Static Instance
29 LLStatsCommand* LLStatsCommand::mLLStatsCommandInstance  = NULL;
30 
31 // This function implements creation of Vendor command
32 // For LLStats just call base Vendor command create
create()33 int LLStatsCommand::create() {
34     int ifindex;
35     int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
36     if (ret < 0) {
37         return ret;
38     }
39     // insert the oui in the msg
40     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
41     if (ret < 0)
42         goto out;
43 
44     // insert the subcmd in the msg
45     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
46     if (ret < 0)
47         goto out;
48 
49     ALOGI("mVendor_id = %d, Subcmd = %d in  %s:%d\n", mVendor_id, mSubcmd, __func__, __LINE__);
50 out:
51     return ret;
52 }
53 
LLStatsCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)54 LLStatsCommand::LLStatsCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
55         : WifiVendorCommand(handle, id, vendor_id, subcmd)
56 {
57     ALOGV("LLStatsCommand %p constructed", this);
58     memset(&mClearRspParams, 0,sizeof(LLStatsClearRspParams));
59     memset(&mResultsParams, 0,sizeof(LLStatsResultsParams));
60     memset(&mHandler, 0,sizeof(mHandler));
61 }
62 
~LLStatsCommand()63 LLStatsCommand::~LLStatsCommand()
64 {
65     ALOGW("LLStatsCommand %p distructor", this);
66     mLLStatsCommandInstance = NULL;
67     unregisterVendorHandler(mVendor_id, mSubcmd);
68 }
69 
instance(wifi_handle handle)70 LLStatsCommand* LLStatsCommand::instance(wifi_handle handle)
71 {
72     if (handle == NULL) {
73         ALOGE("Interface Handle is invalid");
74         return NULL;
75     }
76     if (mLLStatsCommandInstance == NULL) {
77         mLLStatsCommandInstance = new LLStatsCommand(handle, 0,
78                 OUI_QCA,
79                 QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET);
80         ALOGV("LLStatsCommand %p created", mLLStatsCommandInstance);
81         return mLLStatsCommandInstance;
82     }
83     else
84     {
85         if (handle != getWifiHandle(mLLStatsCommandInstance->mInfo))
86         {
87             ALOGE("Handle different");
88             return NULL;
89         }
90     }
91     ALOGV("LLStatsCommand %p created already", mLLStatsCommandInstance);
92     return mLLStatsCommandInstance;
93 }
94 
initGetContext(u32 reqId)95 void LLStatsCommand::initGetContext(u32 reqId)
96 {
97     mRequestId = reqId;
98     memset(&mResultsParams, 0,sizeof(LLStatsResultsParams));
99     memset(&mHandler, 0,sizeof(mHandler));
100 }
101 
setSubCmd(u32 subcmd)102 void LLStatsCommand::setSubCmd(u32 subcmd)
103 {
104     mSubcmd = subcmd;
105 }
106 //callback handlers registered for nl message send
error_handler_LLStats(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)107 static int error_handler_LLStats(struct sockaddr_nl *nla, struct nlmsgerr *err,
108                          void *arg)
109 {
110     struct sockaddr_nl * tmp;
111     int *ret = (int *)arg;
112     tmp = nla;
113     *ret = err->error;
114     ALOGE("%s: Error code:%d (%s)", __func__, *ret, strerror(-(*ret)));
115     return NL_STOP;
116 }
117 
118 //callback handlers registered for nl message send
ack_handler_LLStats(struct nl_msg * msg,void * arg)119 static int ack_handler_LLStats(struct nl_msg *msg, void *arg)
120 {
121     int *ret = (int *)arg;
122     struct nl_msg * a;
123 
124     ALOGE("%s: called", __func__);
125     a = msg;
126     *ret = 0;
127     return NL_STOP;
128 }
129 
130 //callback handlers registered for nl message send
finish_handler_LLStats(struct nl_msg * msg,void * arg)131 static int finish_handler_LLStats(struct nl_msg *msg, void *arg)
132 {
133   int *ret = (int *)arg;
134   struct nl_msg * a;
135 
136   ALOGE("%s: called", __func__);
137   a = msg;
138   *ret = 0;
139   return NL_SKIP;
140 }
141 
get_wifi_interface_info(wifi_interface_link_layer_info * stats,struct nlattr ** tb_vendor)142 static void get_wifi_interface_info(wifi_interface_link_layer_info *stats, struct nlattr **tb_vendor)
143 {
144     u32 len = 0;
145     u8 *data;
146 
147     stats->mode = (wifi_interface_mode)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE]);
148     len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR]);
149     len = ((sizeof(stats->mac_addr) <= len) ? sizeof(stats->mac_addr) : len);
150     memcpy(&stats->mac_addr[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR]), len);
151     stats->state = (wifi_connection_state)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE]);
152     stats->roaming = (wifi_roam_state)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING]);
153     stats->capabilities = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES]);
154 
155     len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID]);
156     len = ((sizeof(stats->ssid) <= len) ? sizeof(stats->ssid) : len);
157     memcpy(&stats->ssid[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID]), len);
158 
159     len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID]);
160     len = ((sizeof(stats->bssid) <= len) ? sizeof(stats->bssid) : len);
161     memcpy(&stats->bssid[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID]), len);
162     len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR]);
163     len = ((sizeof(stats->ap_country_str) <= len) ? sizeof(stats->ap_country_str) : len);
164     memcpy(&stats->ap_country_str[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR]),
165            len);
166     len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR]);
167     len = ((sizeof(stats->country_str) < len) ? sizeof(stats->country_str) : len);
168     memcpy(&stats->country_str[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR]),
169            len);
170 
171     ALOGI("STATS IFACE: Mode %d", stats->mode);
172     ALOGI("STATS IFACE: MAC %pM", stats->mac_addr);
173     ALOGI("STATS IFACE: State %d ", stats->state);
174     ALOGI("STATS IFACE: Roaming %d ", stats->roaming);
175     ALOGI("STATS IFACE: capabilities %0x ", stats->capabilities);
176     ALOGI("STATS IFACE: SSID %s ", stats->ssid);
177     ALOGI("STATS IFACE: BSSID %pM ", stats->bssid);
178     ALOGI("STATS IFACE: AP country str %c%c%c ", stats->ap_country_str[0],
179             stats->ap_country_str[1], stats->ap_country_str[2]);
180     ALOGI("STATS IFACE:Country String for this Association %c%c%c", stats->country_str[0],
181             stats->country_str[1], stats->country_str[2]);
182 }
183 
get_wifi_wmm_ac_stat(wifi_wmm_ac_stat * stats,struct nlattr ** tb_vendor)184 static void get_wifi_wmm_ac_stat(wifi_wmm_ac_stat *stats, struct nlattr **tb_vendor)
185 {
186     stats->ac                     = (wifi_traffic_ac)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC]);
187     stats->tx_mpdu                = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU]);
188     stats->rx_mpdu                = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU]);
189     stats->tx_mcast               = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST]);
190     stats->rx_mcast               = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST]);
191     stats->rx_ampdu               = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU]);
192     stats->tx_ampdu               = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU]);
193     stats->mpdu_lost              = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST]);
194     stats->retries                = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES]);
195     stats->retries_short          = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT]);
196     stats->retries_long           = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG]);
197     stats->contention_time_min    = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN]);
198     stats->contention_time_max    = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX]);
199     stats->contention_time_avg    = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG]);
200     stats->contention_num_samples = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES]);
201 
202     ALOGI("STATS IFACE: ac  %u ", stats->ac);
203     ALOGI("STATS IFACE: txMpdu  %u ", stats->tx_mpdu) ;
204     ALOGI("STATS IFACE: rxMpdu  %u ", stats->rx_mpdu);
205     ALOGI("STATS IFACE: txMcast  %u ", stats->tx_mcast);
206     ALOGI("STATS IFACE: rxMcast  %u ", stats->rx_mcast);
207     ALOGI("STATS IFACE: rxAmpdu  %u ", stats->rx_ampdu);
208     ALOGI("STATS IFACE: txAmpdu  %u ", stats->tx_ampdu);
209     ALOGI("STATS IFACE: mpduLost  %u ", stats->mpdu_lost);
210     ALOGI("STATS IFACE: retries %u  ", stats->retries);
211     ALOGI("STATS IFACE: retriesShort  %u ",
212             stats->retries_short);
213     ALOGI("STATS IFACE: retriesLong  %u  ",
214             stats->retries_long);
215     ALOGI("STATS IFACE: contentionTimeMin  %u ",
216             stats->contention_time_min);
217     ALOGI("STATS IFACE: contentionTimeMax  %u ",
218             stats->contention_time_max);
219     ALOGI("STATS IFACE: contentionTimeAvg  %u ",
220             stats->contention_time_avg);
221     ALOGI("STATS IFACE: contentionNumSamples  %u ",
222             stats->contention_num_samples);
223 }
224 
get_wifi_rate_stat(wifi_rate_stat * stats,struct nlattr ** tb_vendor)225 static void get_wifi_rate_stat(wifi_rate_stat *stats, struct nlattr **tb_vendor)
226 {
227     stats->rate.preamble        = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE]);
228     stats->rate.nss             = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS]);
229     stats->rate.bw              = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW]);
230     stats->rate.rateMcsIdx      = nla_get_u8(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX]);
231     stats->rate.bitrate         = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE]);
232 
233     stats->tx_mpdu              = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU]);
234     stats->rx_mpdu              = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU]);
235     stats->mpdu_lost            = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST]);
236     stats->retries              = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES]);
237     stats->retries_short        = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT]);
238     stats->retries_long         = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG]);
239 
240 
241     ALOGI("STATS PEER_ALL : preamble  %u", stats->rate.preamble);
242     ALOGI("STATS PEER_ALL : nss %u", stats->rate.nss);
243     ALOGI("STATS PEER_ALL : bw %u", stats->rate.bw);
244     ALOGI("STATS PEER_ALL : rateMcsIdx  %u", stats->rate.rateMcsIdx);
245     ALOGI("STATS PEER_ALL : bitrate %u", stats->rate.bitrate);
246 
247     ALOGI("STATS PEER_ALL : txMpdu %u", stats->tx_mpdu);
248     ALOGI("STATS PEER_ALL : rxMpdu %u", stats->rx_mpdu);
249     ALOGI("STATS PEER_ALL : mpduLost %u", stats->mpdu_lost);
250     ALOGI("STATS PEER_ALL : retries %u", stats->retries);
251     ALOGI("STATS PEER_ALL : retriesShort %u", stats->retries_short);
252     ALOGI("STATS PEER_ALL : retriesLong %u", stats->retries_long);
253 }
254 
get_wifi_peer_info(wifi_peer_info * stats,struct nlattr ** tb_vendor)255 static void get_wifi_peer_info(wifi_peer_info *stats, struct nlattr **tb_vendor)
256 {
257     u32 i = 0, len = 0;
258     int rem;
259     wifi_rate_stat * pRateStats;
260     struct nlattr *rateInfo;
261     stats->type                   = (wifi_peer_type)nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE]);
262     len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS]);
263     len = ((sizeof(stats->peer_mac_address) <= len) ? sizeof(stats->peer_mac_address) : len);
264     memcpy((void *)&stats->peer_mac_address[0], nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS]),
265             len);
266     stats->capabilities           = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES]);
267 
268     stats->num_rate               = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES]);
269 
270     ALOGI("STATS PEER_ALL : numPeers %u", stats->type);
271     ALOGI("STATS PEER_ALL : peerMacAddress  %0x:%0x:%0x:%0x:%0x:%0x ",
272             stats->peer_mac_address[0], stats->peer_mac_address[1],
273             stats->peer_mac_address[2],stats->peer_mac_address[3],
274             stats->peer_mac_address[4],stats->peer_mac_address[5]);
275     ALOGI("STATS PEER_ALL : capabilities %0x", stats->capabilities);
276     ALOGI("STATS PEER_ALL :  numRate %u", stats->num_rate);
277     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]);
278             nla_ok(rateInfo, rem);
279             rateInfo = nla_next(rateInfo, &(rem)))
280     {
281         struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1];
282         pRateStats = (wifi_rate_stat *) ((u8 *)stats->rate_stats + (i++ * sizeof(wifi_rate_stat)));
283 
284         nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(rateInfo), nla_len(rateInfo), NULL);
285         get_wifi_rate_stat(pRateStats, tb2);
286     }
287 }
288 
get_wifi_iface_stats(wifi_iface_stat * stats,struct nlattr ** tb_vendor)289 static void get_wifi_iface_stats(wifi_iface_stat *stats, struct nlattr **tb_vendor)
290 {
291     struct nlattr *wmmInfo;
292     wifi_wmm_ac_stat *pWmmStats;
293     int i=0, rem;
294 
295     stats->beacon_rx       = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX]);
296     stats->mgmt_rx         = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX]);
297     stats->mgmt_action_rx  = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX]);
298     stats->mgmt_action_tx  = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX]);
299     stats->rssi_mgmt       = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT]);
300     stats->rssi_data       = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA]);
301     stats->rssi_ack        = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK]);
302 
303     ALOGI("STATS IFACE: beaconRx : %u ", stats->beacon_rx);
304     ALOGI("STATS IFACE: mgmtRx %u ", stats->mgmt_rx);
305     ALOGI("STATS IFACE: mgmtActionRx  %u ", stats->mgmt_action_rx);
306     ALOGI("STATS IFACE: mgmtActionTx %u ", stats->mgmt_action_tx);
307     ALOGI("STATS IFACE: rssiMgmt %u ", stats->rssi_mgmt);
308     ALOGI("STATS IFACE: rssiData %u ", stats->rssi_data);
309     ALOGI("STATS IFACE: rssiAck  %u ", stats->rssi_ack);
310     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]);
311             nla_ok(wmmInfo, rem);
312             wmmInfo = nla_next(wmmInfo, &(rem)))
313     {
314         struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1];
315         pWmmStats = (wifi_wmm_ac_stat *) ((u8 *)stats->ac + (i * sizeof(wifi_wmm_ac_stat)));
316         nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(wmmInfo), nla_len(wmmInfo), NULL);
317         get_wifi_wmm_ac_stat(pWmmStats, tb2);
318     }
319 }
320 
get_wifi_radio_stats(wifi_radio_stat * stats,struct nlattr ** tb_vendor)321 static void get_wifi_radio_stats(wifi_radio_stat *stats, struct nlattr **tb_vendor)
322 {
323     u32 i = 0;
324     struct nlattr *chInfo;
325     wifi_channel_stat *pChStats;
326     int rem;
327                     printf("sunil %d : %s \n",__LINE__,__func__);
328 
329     stats->radio             = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID]);
330                     printf("sunil %d : %s \n",__LINE__,__func__);
331     stats->on_time           = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME]);
332                     printf("sunil %d : %s \n",__LINE__,__func__);
333     stats->tx_time           = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME]);
334                     printf("sunil %d : %s \n",__LINE__,__func__);
335     stats->rx_time           = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME]);
336     ALOGI("<<<< rxTime is %u ", stats->rx_time);
337     stats->on_time_scan      = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN]);
338     stats->on_time_nbd       = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD]);
339     stats->on_time_gscan     = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN]);
340     stats->on_time_roam_scan = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN]);
341     stats->on_time_pno_scan  = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN]);
342     stats->on_time_hs20      = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20]);
343 
344     stats->num_channels                           = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS]);
345 
346     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]);
347             nla_ok(chInfo, rem);
348             chInfo = nla_next(chInfo, &(rem)))
349     {
350         struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1];
351         pChStats = (wifi_channel_stat *) ((u8 *)stats->channels + (i++ * (sizeof(wifi_channel_stat))));
352         nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(chInfo), nla_len(chInfo), NULL);
353         pChStats->channel.width                  = (wifi_channel_width)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH]);
354         pChStats->channel.center_freq            = (wifi_channel)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ]);
355         pChStats->channel.center_freq0           = (wifi_channel)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0]);
356         pChStats->channel.center_freq1           = (wifi_channel)nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1]);
357         pChStats->on_time                = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME]);
358         pChStats->cca_busy_time          = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME]);
359     }
360 }
361 
362 // This function will be the main handler for incoming event LLStats_SUBCMD
363 //Call the appropriate callback handler after parsing the vendor data.
handleEvent(WifiEvent & event)364 int LLStatsCommand::handleEvent(WifiEvent &event)
365 {
366     ALOGI("Got a LLStats message from Driver");
367     unsigned i=0;
368     u32 status;
369     WifiVendorCommand::handleEvent(event);
370 
371     // Parse the vendordata and get the attribute
372 
373     switch(mSubcmd)
374     {
375         case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS:
376             {
377                 wifi_request_id id;
378                 u32 resultsBufSize = 0;
379                 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX + 1];
380                 int rem;
381                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX,
382                         (struct nlattr *)mVendorData,
383                         mDataLen, NULL);
384                 resultsBufSize += (nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS]) * sizeof(wifi_channel_stat)
385                         + sizeof(wifi_radio_stat));
386                 mResultsParams.radio_stat = (wifi_radio_stat *)malloc(resultsBufSize);
387                 memset(mResultsParams.radio_stat, 0, resultsBufSize);
388                 ALOGI(" rxTime is %u\n ", mResultsParams.radio_stat->rx_time);
389                 ALOGI(" NumChan is %d\n ",
390                         nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS]));
391 
392                 if(mResultsParams.radio_stat){
393                     wifi_channel_stat *pWifiChannelStats;
394                     u32 i =0;
395                     printf("sunil %d : %s \n",__LINE__,__func__);
396                     get_wifi_radio_stats(mResultsParams.radio_stat, tb_vendor);
397 
398                     ALOGI(" radio is %u ", mResultsParams.radio_stat->radio);
399                     ALOGI(" onTime is %u ", mResultsParams.radio_stat->on_time);
400                     ALOGI(" txTime is %u ", mResultsParams.radio_stat->tx_time);
401                     ALOGI(" rxTime is %u ", mResultsParams.radio_stat->rx_time);
402                     ALOGI(" onTimeScan is %u ", mResultsParams.radio_stat->on_time_scan);
403                     ALOGI(" onTimeNbd is %u ", mResultsParams.radio_stat->on_time_nbd);
404                     ALOGI(" onTimeGscan is %u ", mResultsParams.radio_stat->on_time_gscan);
405                     ALOGI(" onTimeRoamScan is %u", mResultsParams.radio_stat->on_time_roam_scan);
406                     ALOGI(" onTimePnoScan is %u ", mResultsParams.radio_stat->on_time_pno_scan);
407                     ALOGI(" onTimeHs20 is %u ", mResultsParams.radio_stat->on_time_hs20);
408                     ALOGI(" numChannels is %u ", mResultsParams.radio_stat->num_channels);
409                     for ( i=0; i < mResultsParams.radio_stat->num_channels; i++)
410                     {
411                         pWifiChannelStats = (wifi_channel_stat *) ((u8 *)mResultsParams.radio_stat->channels + (i * sizeof(wifi_channel_stat)));
412 
413                         ALOGI("  width is %u ", pWifiChannelStats->channel.width);
414                         ALOGI("  CenterFreq %u ", pWifiChannelStats->channel.center_freq);
415                         ALOGI("  CenterFreq0 %u ", pWifiChannelStats->channel.center_freq0);
416                         ALOGI("  CenterFreq1 %u ", pWifiChannelStats->channel.center_freq1);
417                         ALOGI("  onTime %u ", pWifiChannelStats->on_time);
418                         ALOGI("  ccaBusyTime %u ", pWifiChannelStats->cca_busy_time);
419                     }
420                     ALOGI(" rxTime is %u in %s:%d\n", mResultsParams.radio_stat->rx_time, __func__, __LINE__);
421                 }
422             }
423             break;
424 
425         case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS:
426             {
427                 wifi_request_id id;
428                 u32 resultsBufSize = 0;
429                 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX + 1];
430                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX,
431                         (struct nlattr *)mVendorData,
432                         mDataLen, NULL);
433 
434                 resultsBufSize = sizeof(wifi_iface_stat);   // Do we need no.of peers here??
435                 mResultsParams.iface_stat = (wifi_iface_stat *) malloc (sizeof (wifi_iface_stat));
436                 get_wifi_interface_info(&mResultsParams.iface_stat->info, tb_vendor);
437                 get_wifi_iface_stats(mResultsParams.iface_stat, tb_vendor);
438             }
439             break;
440 
441         case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS:
442             {
443                 wifi_request_id id;
444                 u32 resultsBufSize = 0, i=0, num_rates = 0;
445                 u32 numPeers;
446                 int rem;
447                 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX + 1];
448                 struct nlattr *peerInfo;
449                 wifi_iface_stat *pIfaceStat;
450                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX,
451                         (struct nlattr *)mVendorData,
452                         mDataLen, NULL);
453 
454                 ALOGI(" rxTime is %u in %s:%d\n", mResultsParams.radio_stat->rx_time, __func__, __LINE__);
455                 ALOGI(" numPeers is %u in %s:%d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS]), __func__, __LINE__);
456                 ALOGI(" rxTe is %u in %s:%d\n", mResultsParams.radio_stat->rx_time, __func__, __LINE__);
457                 if((numPeers = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS])) > 0)
458                 {
459 
460                     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]);
461                             nla_ok(peerInfo, rem);
462                             peerInfo = nla_next(peerInfo, &(rem)))
463                     {
464                         struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1];
465                         nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(peerInfo), nla_len(peerInfo), NULL);
466                         num_rates += nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES]);
467                     }
468                     resultsBufSize += (numPeers * sizeof(wifi_peer_info)
469                             + num_rates * sizeof(wifi_rate_stat) + sizeof (wifi_iface_stat));
470                     pIfaceStat = (wifi_iface_stat *) malloc (resultsBufSize);
471 
472                     if(pIfaceStat){
473                         memcpy ( pIfaceStat, mResultsParams.iface_stat , sizeof(wifi_iface_stat));
474                         wifi_peer_info *pPeerStats;
475                         pIfaceStat->num_peers = numPeers;
476                         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]);
477                                 nla_ok(peerInfo, rem);
478                                 peerInfo = nla_next(peerInfo, &(rem)))
479                         {
480                             struct nlattr *tb2[ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX+ 1];
481                             pPeerStats = (wifi_peer_info *) ((u8 *)pIfaceStat->peer_info + (i++ * sizeof(wifi_peer_info)));
482                             nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX, (struct nlattr *) nla_data(peerInfo), nla_len(peerInfo), NULL);
483                             get_wifi_peer_info(pPeerStats, tb2);
484                         }
485                     }
486                     if(mResultsParams.iface_stat)
487                         free (mResultsParams.iface_stat);
488                     mResultsParams.iface_stat = pIfaceStat;
489                 }
490                 // Number of Radios are 1 for now : TODO get this info from the driver
491                 mHandler.on_link_stats_results(mRequestId,
492                                                mResultsParams.iface_stat, 1, mResultsParams.radio_stat);
493                 if(mResultsParams.radio_stat)
494                 {
495                     free(mResultsParams.radio_stat);
496                     mResultsParams.radio_stat = NULL;
497                 }
498                 if(mResultsParams.iface_stat)
499                 {
500                     free(mResultsParams.iface_stat);
501                     mResultsParams.iface_stat = NULL;
502                 }
503             }
504             break;
505 
506         default:
507             //error case should not happen print log
508             ALOGE("%s: Wrong LLStats subcmd received %d", __func__, mSubcmd);
509     }
510 
511     return NL_SKIP;
512 }
513 
setCallbackHandler(LLStatsCallbackHandler nHandler,u32 event)514 int LLStatsCommand::setCallbackHandler(LLStatsCallbackHandler nHandler, u32 event)
515 {
516     int res = 0;
517     mHandler = nHandler;
518     res = registerVendorHandler(mVendor_id, event);
519     if (res != 0) {
520         //error case should not happen print log
521         ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
522               __func__, mVendor_id, mSubcmd);
523     }
524     return res;
525 }
526 
unregisterHandler(u32 subCmd)527 void LLStatsCommand::unregisterHandler(u32 subCmd)
528 {
529     unregisterVendorHandler(mVendor_id, subCmd);
530 }
531 
getClearRspParams(u32 * stats_clear_rsp_mask,u8 * stop_rsp)532 void LLStatsCommand::getClearRspParams(u32 *stats_clear_rsp_mask, u8 *stop_rsp)
533 {
534     *stats_clear_rsp_mask =  mClearRspParams.stats_clear_rsp_mask;
535     *stop_rsp = mClearRspParams.stop_rsp;
536 }
537 
requestResponse()538 int LLStatsCommand::requestResponse()
539 {
540     return WifiCommand::requestResponse(mMsg);
541 }
542 
handleResponse(WifiEvent & reply)543 int LLStatsCommand::handleResponse(WifiEvent &reply)
544 {
545     ALOGI("Got a LLStats message from Driver");
546     unsigned i=0;
547     u32 status;
548     WifiVendorCommand::handleResponse(reply);
549 
550     // Parse the vendordata and get the attribute
551 
552     switch(mSubcmd)
553     {
554         case QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR:
555             {
556                 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
557                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
558                         (struct nlattr *)mVendorData,
559                         mDataLen, NULL);
560                 ALOGI("Resp mask : %d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK]));
561                 ALOGI("STOP resp : %d\n", nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP]));
562                 mClearRspParams.stats_clear_rsp_mask = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK]);
563                 mClearRspParams.stop_rsp = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP]);
564                 break;
565             }
566         default :
567             ALOGE("%s: Wrong LLStats subcmd received %d", __func__, mSubcmd);
568     }
569     return NL_SKIP;
570 }
571 
572 //Implementation of the functions exposed in linklayer.h
wifi_set_link_stats(wifi_interface_handle iface,wifi_link_layer_params params)573 wifi_error wifi_set_link_stats(wifi_interface_handle iface,
574                                wifi_link_layer_params params)
575 {
576     int ret = 0;
577     LLStatsCommand *LLCommand;
578     struct nlattr *nl_data;
579     interface_info *iinfo = getIfaceInfo(iface);
580     wifi_handle handle = getWifiHandle(iface);
581     LLCommand = LLStatsCommand::instance(handle);
582     if (LLCommand == NULL) {
583         ALOGE("%s: Error LLStatsCommand NULL", __func__);
584         return WIFI_ERROR_UNKNOWN;
585     }
586     LLCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET);
587 
588     /* create the message */
589     ret = LLCommand->create();
590     if (ret < 0)
591         goto cleanup;
592 
593     ret = LLCommand->set_iface_id(iinfo->name);
594     if (ret < 0)
595         goto cleanup;
596 
597     /*add the attributes*/
598     nl_data = LLCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
599     if (!nl_data)
600         goto cleanup;
601     /**/
602     ret = LLCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD,
603                                   params.mpdu_size_threshold);
604     if (ret < 0)
605         goto cleanup;
606     /**/
607     ret = LLCommand->put_u32(
608                 QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING,
609                 params.aggressive_statistics_gathering);
610     if (ret < 0)
611         goto cleanup;
612     LLCommand->attr_end(nl_data);
613 
614     ret = LLCommand->requestResponse();
615     if (ret != 0) {
616         ALOGE("%s: requestResponse Error:%d",__func__, ret);
617     }
618 
619 cleanup:
620     return (wifi_error)ret;
621 }
622 
623 //Implementation of the functions exposed in LLStats.h
wifi_get_link_stats(wifi_request_id id,wifi_interface_handle iface,wifi_stats_result_handler handler)624 wifi_error wifi_get_link_stats(wifi_request_id id,
625                                wifi_interface_handle iface,
626                                wifi_stats_result_handler handler)
627 {
628     int ret = 0;
629     LLStatsCommand *LLCommand;
630     struct nlattr *nl_data;
631     interface_info *iinfo = getIfaceInfo(iface);
632     wifi_handle handle = getWifiHandle(iface);
633     pthread_t tid;
634 
635     LLCommand = LLStatsCommand::instance(handle);
636     if (LLCommand == NULL) {
637         ALOGE("%s: Error LLStatsCommand NULL", __func__);
638         return WIFI_ERROR_UNKNOWN;
639     }
640     LLCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET);
641 
642     LLCommand->initGetContext(id);
643 
644     LLStatsCallbackHandler callbackHandler =
645     {
646         .on_link_stats_results = handler.on_link_stats_results
647     };
648 
649     /* create the message */
650     ret = LLCommand->create();
651     if (ret < 0)
652         goto cleanup;
653 
654     ret = LLCommand->set_iface_id(iinfo->name);
655     if (ret < 0)
656         goto cleanup;
657     /*add the attributes*/
658     nl_data = LLCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
659     if (!nl_data)
660         goto cleanup;
661     ret = LLCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID,
662                                   id);
663     if (ret < 0)
664         goto cleanup;
665     ret = LLCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK,
666                                   7);
667     if (ret < 0)
668         goto cleanup;
669 
670     /**/
671     LLCommand->attr_end(nl_data);
672 
673     ret = LLCommand->requestResponse();
674     if (ret != 0) {
675         ALOGE("%s: requestResponse Error:%d",__func__, ret);
676     }
677     if (ret < 0)
678         goto cleanup;
679 
680     ret = LLCommand->setCallbackHandler(callbackHandler, QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS);
681     if (ret < 0)
682         goto cleanup;
683     ret = LLCommand->setCallbackHandler(callbackHandler, QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS);
684     if (ret < 0)
685         goto cleanup;
686     ret = LLCommand->setCallbackHandler(callbackHandler, QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS);
687     if (ret < 0)
688         goto cleanup;
689 cleanup:
690     return (wifi_error)ret;
691 }
692 
693 
694 //Implementation of the functions exposed in LLStats.h
wifi_clear_link_stats(wifi_interface_handle iface,u32 stats_clear_req_mask,u32 * stats_clear_rsp_mask,u8 stop_req,u8 * stop_rsp)695 wifi_error wifi_clear_link_stats(wifi_interface_handle iface,
696                                  u32 stats_clear_req_mask,
697                                  u32 *stats_clear_rsp_mask,
698                                  u8 stop_req, u8 *stop_rsp)
699 {
700     int ret = 0;
701     LLStatsCommand *LLCommand;
702     struct nlattr *nl_data;
703     interface_info *iinfo = getIfaceInfo(iface);
704     wifi_handle handle = getWifiHandle(iface);
705 
706     LLCommand = LLStatsCommand::instance(handle);
707     if (LLCommand == NULL) {
708         ALOGE("%s: Error LLStatsCommand NULL", __func__);
709         return WIFI_ERROR_UNKNOWN;
710     }
711     LLCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR);
712 
713     /* create the message */
714     ret = LLCommand->create();
715     if (ret < 0)
716         goto cleanup;
717 
718     ret = LLCommand->set_iface_id(iinfo->name);
719     if (ret < 0)
720         goto cleanup;
721     /*add the attributes*/
722     nl_data = LLCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
723     if (!nl_data)
724         goto cleanup;
725     /**/
726     ret = LLCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK,
727                                   stats_clear_req_mask);
728     if (ret < 0)
729         goto cleanup;
730     /**/
731     ret = LLCommand->put_u8(QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ,
732                                    stop_req);
733     if (ret < 0)
734         goto cleanup;
735     LLCommand->attr_end(nl_data);
736 
737     ret = LLCommand->requestResponse();
738     if (ret != 0) {
739         ALOGE("%s: requestResponse Error:%d",__func__, ret);
740     }
741 
742     LLCommand->getClearRspParams(stats_clear_rsp_mask, stop_rsp);
743 
744 cleanup:
745     LLCommand->unregisterHandler(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS);
746     LLCommand->unregisterHandler(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS);
747     LLCommand->unregisterHandler(QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS);
748     delete LLCommand;
749     return (wifi_error)ret;
750 }
751 
752