blob: 1b5e0b5c992067f2b8b97b9a0b53db1f4f9484eb [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Dustin Brown4ea21db2018-01-05 14:13:17 -08002 * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/**
20 * DOC : wlan_hdd_stats.c
21 *
22 * WLAN Host Device Driver statistics related implementation
23 *
24 */
25
26#include "wlan_hdd_stats.h"
27#include "sme_api.h"
28#include "cds_sched.h"
29#include "wlan_hdd_trace.h"
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070030#include "wlan_hdd_lpass.h"
Nirav Shahbf1b0332016-05-25 14:27:39 +053031#include "hif.h"
Sandeep Puligillafdd201e2017-02-02 18:43:46 -080032#include <qca_vendor.h>
Zhang Qian4ead8f02017-03-27 14:21:47 +080033#include "wma_api.h"
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +053034#include "wlan_hdd_hostapd.h"
35#include "wlan_hdd_request_manager.h"
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -080036#include "wlan_hdd_debugfs_llstat.h"
Jeff Johnson32bd9742018-03-29 13:42:31 -070037#include "wlan_reg_services_api.h"
Yu Wangc0b46f82018-03-09 16:04:15 +080038#include <wlan_cfg80211_mc_cp_stats.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039
Naveen Rawat23183d62018-04-12 11:19:01 -070040#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
41#define HDD_INFO_SIGNAL STATION_INFO_SIGNAL
42#define HDD_INFO_SIGNAL_AVG STATION_INFO_SIGNAL_AVG
43#define HDD_INFO_TX_PACKETS STATION_INFO_TX_PACKETS
44#define HDD_INFO_TX_RETRIES STATION_INFO_TX_RETRIES
45#define HDD_INFO_TX_FAILED STATION_INFO_TX_FAILED
46#define HDD_INFO_TX_BITRATE STATION_INFO_TX_BITRATE
47#define HDD_INFO_TX_BYTES STATION_INFO_TX_BYTES
48#define HDD_INFO_CHAIN_SIGNAL_AVG STATION_INFO_CHAIN_SIGNAL_AVG
49#define HDD_INFO_RX_BYTES STATION_INFO_RX_BYTES
50#define HDD_INFO_RX_PACKETS STATION_INFO_RX_PACKETS
51#define HDD_INFO_TX_BYTES64 0
52#define HDD_INFO_RX_BYTES64 0
53#define HDD_INFO_INACTIVE_TIME 0
54#define HDD_INFO_CONNECTED_TIME 0
55#else
56#define HDD_INFO_SIGNAL BIT(NL80211_STA_INFO_SIGNAL)
57#define HDD_INFO_SIGNAL_AVG BIT(NL80211_STA_INFO_SIGNAL_AVG)
58#define HDD_INFO_TX_PACKETS BIT(NL80211_STA_INFO_TX_PACKETS)
59#define HDD_INFO_TX_RETRIES BIT(NL80211_STA_INFO_TX_RETRIES)
60#define HDD_INFO_TX_FAILED BIT(NL80211_STA_INFO_TX_FAILED)
61#define HDD_INFO_TX_BITRATE BIT(NL80211_STA_INFO_TX_BITRATE)
62#define HDD_INFO_TX_BYTES BIT(NL80211_STA_INFO_TX_BYTES)
63#define HDD_INFO_CHAIN_SIGNAL_AVG BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
64#define HDD_INFO_RX_BYTES BIT(NL80211_STA_INFO_RX_BYTES)
65#define HDD_INFO_RX_PACKETS BIT(NL80211_STA_INFO_RX_PACKETS)
66#define HDD_INFO_TX_BYTES64 BIT(NL80211_STA_INFO_TX_BYTES64)
67#define HDD_INFO_RX_BYTES64 BIT(NL80211_STA_INFO_RX_BYTES64)
68#define HDD_INFO_INACTIVE_TIME BIT(NL80211_STA_INFO_INACTIVE_TIME)
69#define HDD_INFO_CONNECTED_TIME BIT(NL80211_STA_INFO_CONNECTED_TIME)
70#endif /* kernel version less than 4.0.0 && no_backport */
71
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080072/* 11B, 11G Rate table include Basic rate and Extended rate
73 * The IDX field is the rate index
74 * The HI field is the rate when RSSI is strong or being ignored
75 * (in this case we report actual rate)
76 * The MID field is the rate when RSSI is moderate
77 * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
78 * The LO field is the rate when RSSI is low
79 * (in this case we don't report rates, actual current rate used)
80 */
Will Huang496b36c2017-07-11 16:38:50 +080081static const struct index_data_rate_type supported_data_rate[] = {
82 /* IDX HI HM LM LO (RSSI-based index */
83 {2, { 10, 10, 10, 0} },
84 {4, { 20, 20, 10, 0} },
85 {11, { 55, 20, 10, 0} },
86 {12, { 60, 55, 20, 0} },
87 {18, { 90, 55, 20, 0} },
88 {22, {110, 55, 20, 0} },
89 {24, {120, 90, 60, 0} },
90 {36, {180, 120, 60, 0} },
91 {44, {220, 180, 60, 0} },
92 {48, {240, 180, 90, 0} },
93 {66, {330, 180, 90, 0} },
94 {72, {360, 240, 90, 0} },
95 {96, {480, 240, 120, 0} },
96 {108, {540, 240, 120, 0} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080097};
98/* MCS Based rate table HT MCS parameters with Nss = 1 */
99static struct index_data_rate_type supported_mcs_rate_nss1[] = {
100/* MCS L20 L40 S20 S40 */
101 {0, {65, 135, 72, 150} },
102 {1, {130, 270, 144, 300} },
103 {2, {195, 405, 217, 450} },
104 {3, {260, 540, 289, 600} },
105 {4, {390, 810, 433, 900} },
106 {5, {520, 1080, 578, 1200} },
107 {6, {585, 1215, 650, 1350} },
108 {7, {650, 1350, 722, 1500} }
109};
110
111/* HT MCS parameters with Nss = 2 */
112static struct index_data_rate_type supported_mcs_rate_nss2[] = {
113/* MCS L20 L40 S20 S40 */
114 {0, {130, 270, 144, 300} },
115 {1, {260, 540, 289, 600} },
116 {2, {390, 810, 433, 900} },
117 {3, {520, 1080, 578, 1200} },
118 {4, {780, 1620, 867, 1800} },
119 {5, {1040, 2160, 1156, 2400} },
120 {6, {1170, 2430, 1300, 2700} },
121 {7, {1300, 2700, 1444, 3000} }
122};
123
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800124/* MCS Based VHT rate table MCS parameters with Nss = 1*/
125static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
126/* MCS L80 S80 L40 S40 L20 S40*/
127 {0, {293, 325}, {135, 150}, {65, 72} },
128 {1, {585, 650}, {270, 300}, {130, 144} },
129 {2, {878, 975}, {405, 450}, {195, 217} },
130 {3, {1170, 1300}, {540, 600}, {260, 289} },
131 {4, {1755, 1950}, {810, 900}, {390, 433} },
132 {5, {2340, 2600}, {1080, 1200}, {520, 578} },
133 {6, {2633, 2925}, {1215, 1350}, {585, 650} },
134 {7, {2925, 3250}, {1350, 1500}, {650, 722} },
135 {8, {3510, 3900}, {1620, 1800}, {780, 867} },
136 {9, {3900, 4333}, {1800, 2000}, {780, 867} }
137};
138
139/*MCS parameters with Nss = 2*/
140static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
141/* MCS L80 S80 L40 S40 L20 S40*/
142 {0, {585, 650}, {270, 300}, {130, 144} },
143 {1, {1170, 1300}, {540, 600}, {260, 289} },
144 {2, {1755, 1950}, {810, 900}, {390, 433} },
145 {3, {2340, 2600}, {1080, 1200}, {520, 578} },
146 {4, {3510, 3900}, {1620, 1800}, {780, 867} },
147 {5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
148 {6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
149 {7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
150 {8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
151 {9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
152};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800153
154/*array index ponints to MCS and array value points respective rssi*/
155static int rssi_mcs_tbl[][10] = {
156/*MCS 0 1 2 3 4 5 6 7 8 9*/
157 {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */
158 {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */
159 {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */
160};
161
162
163#ifdef WLAN_FEATURE_LINK_LAYER_STATS
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800164static struct hdd_ll_stats_context ll_stats_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165
166/**
167 * put_wifi_rate_stat() - put wifi rate stats
168 * @stats: Pointer to stats context
169 * @vendor_event: Pointer to vendor event
170 *
171 * Return: bool
172 */
173static bool put_wifi_rate_stat(tpSirWifiRateStat stats,
174 struct sk_buff *vendor_event)
175{
176 if (nla_put_u8(vendor_event,
177 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
178 stats->rate.preamble) ||
179 nla_put_u8(vendor_event,
180 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
181 stats->rate.nss) ||
182 nla_put_u8(vendor_event,
183 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
184 stats->rate.bw) ||
185 nla_put_u8(vendor_event,
186 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
187 stats->rate.rateMcsIdx) ||
188 nla_put_u32(vendor_event,
189 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
190 stats->rate.bitrate) ||
191 nla_put_u32(vendor_event,
192 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
193 stats->txMpdu) ||
194 nla_put_u32(vendor_event,
195 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
196 stats->rxMpdu) ||
197 nla_put_u32(vendor_event,
198 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
199 stats->mpduLost) ||
200 nla_put_u32(vendor_event,
201 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
202 stats->retries) ||
203 nla_put_u32(vendor_event,
204 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
205 stats->retriesShort) ||
206 nla_put_u32(vendor_event,
207 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
208 stats->retriesLong)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700209 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800210 return false;
211 }
212
213 return true;
214}
215
216/**
217 * put_wifi_peer_info() - put wifi peer info
218 * @stats: Pointer to stats context
219 * @vendor_event: Pointer to vendor event
220 *
221 * Return: bool
222 */
223static bool put_wifi_peer_info(tpSirWifiPeerInfo stats,
224 struct sk_buff *vendor_event)
225{
226 u32 i = 0;
227 tpSirWifiRateStat pRateStats;
228
229 if (nla_put_u32
230 (vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
Dustin Brown877a5a92016-11-17 13:56:52 -0800231 wmi_to_sir_peer_type(stats->type)) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 nla_put(vendor_event,
233 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530234 QDF_MAC_ADDR_SIZE, &stats->peerMacAddress.bytes[0]) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800235 nla_put_u32(vendor_event,
236 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
237 stats->capabilities) ||
238 nla_put_u32(vendor_event,
239 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
240 stats->numRate)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700241 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800242 goto error;
243 }
244
245 if (stats->numRate) {
246 struct nlattr *rateInfo;
247 struct nlattr *rates;
248
249 rateInfo = nla_nest_start(vendor_event,
250 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO);
251 if (rateInfo == NULL)
252 goto error;
253
254 for (i = 0; i < stats->numRate; i++) {
255 pRateStats = (tpSirWifiRateStat) ((uint8_t *)
256 stats->rateStats +
257 (i *
258 sizeof
259 (tSirWifiRateStat)));
260 rates = nla_nest_start(vendor_event, i);
261 if (rates == NULL)
262 goto error;
263
264 if (false ==
265 put_wifi_rate_stat(pRateStats, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700266 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800267 return false;
268 }
269 nla_nest_end(vendor_event, rates);
270 }
271 nla_nest_end(vendor_event, rateInfo);
272 }
273
274 return true;
275error:
276 return false;
277}
278
279/**
280 * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
281 * @stats: Pointer to stats context
282 * @vendor_event: Pointer to vendor event
283 *
284 * Return: bool
285 */
286static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats,
287 struct sk_buff *vendor_event)
288{
289 if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
290 stats->ac) ||
291 nla_put_u32(vendor_event,
292 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
293 stats->txMpdu) ||
294 nla_put_u32(vendor_event,
295 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
296 stats->rxMpdu) ||
297 nla_put_u32(vendor_event,
298 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
299 stats->txMcast) ||
300 nla_put_u32(vendor_event,
301 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
302 stats->rxMcast) ||
303 nla_put_u32(vendor_event,
304 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
305 stats->rxAmpdu) ||
306 nla_put_u32(vendor_event,
307 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
308 stats->txAmpdu) ||
309 nla_put_u32(vendor_event,
310 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
311 stats->mpduLost) ||
312 nla_put_u32(vendor_event,
313 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
314 stats->retries) ||
315 nla_put_u32(vendor_event,
316 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
317 stats->retriesShort) ||
318 nla_put_u32(vendor_event,
319 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
320 stats->retriesLong) ||
321 nla_put_u32(vendor_event,
322 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
323 stats->contentionTimeMin) ||
324 nla_put_u32(vendor_event,
325 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
326 stats->contentionTimeMax) ||
327 nla_put_u32(vendor_event,
328 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
329 stats->contentionTimeAvg) ||
330 nla_put_u32(vendor_event,
331 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
332 stats->contentionNumSamples)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700333 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800334 return false;
335 }
336
337 return true;
338}
339
340/**
341 * put_wifi_interface_info() - put wifi interface info
342 * @stats: Pointer to stats context
343 * @vendor_event: Pointer to vendor event
344 *
345 * Return: bool
346 */
347static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats,
348 struct sk_buff *vendor_event)
349{
350 if (nla_put_u32(vendor_event,
351 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
352 stats->mode) ||
353 nla_put(vendor_event,
354 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530355 QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800356 nla_put_u32(vendor_event,
357 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
358 stats->state) ||
359 nla_put_u32(vendor_event,
360 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
361 stats->roaming) ||
362 nla_put_u32(vendor_event,
363 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
364 stats->capabilities) ||
365 nla_put(vendor_event,
366 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
367 strlen(stats->ssid), stats->ssid) ||
368 nla_put(vendor_event,
369 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530370 QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800371 nla_put(vendor_event,
372 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
373 WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) ||
374 nla_put(vendor_event,
375 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
376 WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700377 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800378 return false;
379 }
380
381 return true;
382}
383
384/**
385 * put_wifi_iface_stats() - put wifi interface stats
386 * @pWifiIfaceStat: Pointer to interface stats context
387 * @num_peer: Number of peers
388 * @vendor_event: Pointer to vendor event
389 *
390 * Return: bool
391 */
392static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
393 u32 num_peers, struct sk_buff *vendor_event)
394{
395 int i = 0;
396 struct nlattr *wmmInfo;
397 struct nlattr *wmmStats;
398 u64 average_tsf_offset;
399
400 if (false == put_wifi_interface_info(&pWifiIfaceStat->info,
401 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700402 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800403 return false;
404
405 }
406
407 average_tsf_offset = pWifiIfaceStat->avg_bcn_spread_offset_high;
408 average_tsf_offset = (average_tsf_offset << 32) |
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700409 pWifiIfaceStat->avg_bcn_spread_offset_low;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800410
411 if (nla_put_u32(vendor_event,
412 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
413 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) ||
414 nla_put_u32(vendor_event,
415 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
416 num_peers) ||
417 nla_put_u32(vendor_event,
418 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
419 pWifiIfaceStat->beaconRx) ||
420 nla_put_u32(vendor_event,
421 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
422 pWifiIfaceStat->mgmtRx) ||
423 nla_put_u32(vendor_event,
424 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
425 pWifiIfaceStat->mgmtActionRx) ||
426 nla_put_u32(vendor_event,
427 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
428 pWifiIfaceStat->mgmtActionTx) ||
429 nla_put_u32(vendor_event,
430 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
431 pWifiIfaceStat->rssiMgmt) ||
432 nla_put_u32(vendor_event,
433 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
434 pWifiIfaceStat->rssiData) ||
435 nla_put_u32(vendor_event,
436 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
437 pWifiIfaceStat->rssiAck) ||
438 nla_put_u32(vendor_event,
439 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
440 pWifiIfaceStat->is_leaky_ap) ||
441 nla_put_u32(vendor_event,
442 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
443 pWifiIfaceStat->avg_rx_frms_leaked) ||
444 nla_put_u32(vendor_event,
445 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
446 pWifiIfaceStat->rx_leak_window) ||
Dustin Brownbb7e2f52016-10-17 12:16:35 -0700447 hdd_wlan_nla_put_u64(vendor_event,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800448 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
gaolezb432ed92017-03-16 18:40:04 +0800449 average_tsf_offset) ||
450 nla_put_u32(vendor_event,
451 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT,
452 pWifiIfaceStat->rts_succ_cnt) ||
453 nla_put_u32(vendor_event,
454 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT,
455 pWifiIfaceStat->rts_fail_cnt) ||
456 nla_put_u32(vendor_event,
457 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT,
458 pWifiIfaceStat->ppdu_succ_cnt) ||
459 nla_put_u32(vendor_event,
460 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT,
461 pWifiIfaceStat->ppdu_fail_cnt)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700462 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800463 return false;
464 }
465
466 wmmInfo = nla_nest_start(vendor_event,
467 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
468 if (wmmInfo == NULL)
469 return false;
470
471 for (i = 0; i < WIFI_AC_MAX; i++) {
472 wmmStats = nla_nest_start(vendor_event, i);
473 if (wmmStats == NULL)
474 return false;
475
476 if (false ==
477 put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i],
478 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700479 hdd_err("put_wifi_wmm_ac_stat Fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800480 return false;
481 }
482
483 nla_nest_end(vendor_event, wmmStats);
484 }
485 nla_nest_end(vendor_event, wmmInfo);
486 return true;
487}
488
489/**
490 * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
491 * @deviceMode: Device mode
492 *
493 * Return: interface mode
494 */
495static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode)
496{
497 switch (deviceMode) {
Krunal Sonif07bb382016-03-10 13:02:11 -0800498 case QDF_STA_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800499 return WIFI_INTERFACE_STA;
Krunal Sonif07bb382016-03-10 13:02:11 -0800500 case QDF_SAP_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501 return WIFI_INTERFACE_SOFTAP;
Krunal Sonif07bb382016-03-10 13:02:11 -0800502 case QDF_P2P_CLIENT_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800503 return WIFI_INTERFACE_P2P_CLIENT;
Krunal Sonif07bb382016-03-10 13:02:11 -0800504 case QDF_P2P_GO_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800505 return WIFI_INTERFACE_P2P_GO;
Krunal Sonif07bb382016-03-10 13:02:11 -0800506 case QDF_IBSS_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507 return WIFI_INTERFACE_IBSS;
508 default:
509 /* Return Interface Mode as STA for all the unsupported modes */
510 return WIFI_INTERFACE_STA;
511 }
512}
513
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700514bool hdd_get_interface_info(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800515 tpSirWifiInterfaceInfo pInfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800516{
517 uint8_t *staMac = NULL;
Jeff Johnsond377dce2017-10-04 10:32:42 -0700518 struct hdd_station_ctx *sta_ctx;
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700519 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800520 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
521
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700522 pInfo->mode = hdd_map_device_to_ll_iface_mode(adapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800523
Jeff Johnson1e851a12017-10-28 14:36:12 -0700524 qdf_copy_macaddr(&pInfo->macAddr, &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700526 if (((QDF_STA_MODE == adapter->device_mode) ||
527 (QDF_P2P_CLIENT_MODE == adapter->device_mode) ||
528 (QDF_P2P_DEVICE_MODE == adapter->device_mode))) {
Jeff Johnsond377dce2017-10-04 10:32:42 -0700529 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800530 if (eConnectionState_NotConnected ==
Jeff Johnsond377dce2017-10-04 10:32:42 -0700531 sta_ctx->conn_info.connState) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800532 pInfo->state = WIFI_DISCONNECTED;
533 }
534 if (eConnectionState_Connecting ==
Jeff Johnsond377dce2017-10-04 10:32:42 -0700535 sta_ctx->conn_info.connState) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700536 hdd_err("Session ID %d, Connection is in progress",
Jeff Johnson1b780e42017-10-31 14:11:45 -0700537 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800538 pInfo->state = WIFI_ASSOCIATING;
539 }
540 if ((eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -0700541 sta_ctx->conn_info.connState)
542 && (false == sta_ctx->conn_info.uIsAuthenticated)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800543 staMac =
Jeff Johnson1e851a12017-10-28 14:36:12 -0700544 (uint8_t *) &(adapter->mac_addr.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545 bytes[0]);
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700546 hdd_err("client " MAC_ADDRESS_STR
547 " is in the middle of WPS/EAPOL exchange.",
548 MAC_ADDR_ARRAY(staMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800549 pInfo->state = WIFI_AUTHENTICATING;
550 }
551 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -0700552 sta_ctx->conn_info.connState) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800553 pInfo->state = WIFI_ASSOCIATED;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530554 qdf_copy_macaddr(&pInfo->bssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -0700555 &sta_ctx->conn_info.bssId);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530556 qdf_mem_copy(pInfo->ssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -0700557 sta_ctx->conn_info.SSID.SSID.ssId,
558 sta_ctx->conn_info.SSID.SSID.length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800559 /*
560 * NULL Terminate the string
561 */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700562 pInfo->ssid[sta_ctx->conn_info.SSID.SSID.length] = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800563 }
564 }
565
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530566 qdf_mem_copy(pInfo->countryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800567 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
568
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530569 qdf_mem_copy(pInfo->apCountryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800570 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
571
572 return true;
573}
574
575/**
576 * hdd_link_layer_process_peer_stats() - This function is called after
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700577 * @adapter: Pointer to device adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800578 * @more_data: More data
579 * @pData: Pointer to stats data
580 *
581 * Receiving Link Layer Peer statistics from FW.This function converts
582 * the firmware data to the NL data and sends the same to the kernel/upper
583 * layers.
584 *
585 * Return: None
586 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700587static void hdd_link_layer_process_peer_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800588 u32 more_data,
589 tpSirWifiPeerStat pData)
590{
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700591 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800592 tpSirWifiPeerStat pWifiPeerStat;
593 tpSirWifiPeerInfo pWifiPeerInfo;
594 struct sk_buff *vendor_event;
Sushant Kaushik7a535882015-11-02 13:31:21 +0530595 int status, i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800596 struct nlattr *peers;
597 int numRate;
598
Dustin Brown491d54b2018-03-14 12:39:11 -0700599 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530600
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800601 pWifiPeerStat = pData;
602
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700603 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530604 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800605 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800606
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800607 hdd_debug("LL_STATS_PEER_ALL : numPeers %u, more data = %u",
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700608 pWifiPeerStat->numPeers, more_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800609
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800610 /*
611 * Allocate a size of 4096 for the peer stats comprising
612 * each of size = sizeof (tSirWifiPeerInfo) + numRate *
613 * sizeof (tSirWifiRateStat).Each field is put with an
614 * NL attribute.The size of 4096 is considered assuming
615 * that number of rates shall not exceed beyond 50 with
616 * the sizeof (tSirWifiRateStat) being 32.
617 */
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700618 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800619 LL_STATS_EVENT_BUF_SIZE);
620
621 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700622 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800623 return;
624 }
625
626 if (nla_put_u32(vendor_event,
627 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
628 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
629 nla_put_u32(vendor_event,
630 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
631 more_data) ||
632 nla_put_u32(vendor_event,
633 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
634 pWifiPeerStat->numPeers)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700635 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800636
637 kfree_skb(vendor_event);
638 return;
639 }
640
641 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
642 pWifiPeerStat->peerInfo);
643
644 if (pWifiPeerStat->numPeers) {
645 struct nlattr *peerInfo;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700646
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800647 peerInfo = nla_nest_start(vendor_event,
648 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO);
649 if (peerInfo == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700650 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800651 kfree_skb(vendor_event);
652 return;
653 }
654
655 for (i = 1; i <= pWifiPeerStat->numPeers; i++) {
656 peers = nla_nest_start(vendor_event, i);
657 if (peers == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700658 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800659 kfree_skb(vendor_event);
660 return;
661 }
662
663 numRate = pWifiPeerInfo->numRate;
664
665 if (false ==
666 put_wifi_peer_info(pWifiPeerInfo, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700667 hdd_err("put_wifi_peer_info fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800668 kfree_skb(vendor_event);
669 return;
670 }
671
672 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
673 pWifiPeerStat->
674 peerInfo +
675 (i *
676 sizeof
677 (tSirWifiPeerInfo))
678 +
679 (numRate *
680 sizeof
681 (tSirWifiRateStat)));
682 nla_nest_end(vendor_event, peers);
683 }
684 nla_nest_end(vendor_event, peerInfo);
685 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700686
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800687 cfg80211_vendor_cmd_reply(vendor_event);
Dustin Browne74003f2018-03-14 12:51:58 -0700688 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800689}
690
691/**
692 * hdd_link_layer_process_iface_stats() - This function is called after
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700693 * @adapter: Pointer to device adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800694 * @pData: Pointer to stats data
695 * @num_peers: Number of peers
696 *
697 * Receiving Link Layer Interface statistics from FW.This function converts
698 * the firmware data to the NL data and sends the same to the kernel/upper
699 * layers.
700 *
701 * Return: None
702 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700703static void hdd_link_layer_process_iface_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800704 tpSirWifiIfaceStat pData,
705 u32 num_peers)
706{
707 tpSirWifiIfaceStat pWifiIfaceStat;
708 struct sk_buff *vendor_event;
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700709 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800710 int status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800711
Dustin Brown491d54b2018-03-14 12:39:11 -0700712 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530713
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800714 pWifiIfaceStat = pData;
715
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700716 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530717 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800718 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800719
720 /*
721 * Allocate a size of 4096 for the interface stats comprising
722 * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered
723 * assuming that all these fit with in the limit.Please take
724 * a call on the limit based on the data requirements on
725 * interface statistics.
726 */
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700727 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800728 LL_STATS_EVENT_BUF_SIZE);
729
730 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700731 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732 return;
733 }
734
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800735 hdd_debug("WMI_LINK_STATS_IFACE Data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800736
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700737 if (false == hdd_get_interface_info(adapter, &pWifiIfaceStat->info)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700738 hdd_err("hdd_get_interface_info get fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800739 kfree_skb(vendor_event);
740 return;
741 }
742
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800743 if (false ==
744 put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700745 hdd_err("put_wifi_iface_stats fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800746 kfree_skb(vendor_event);
747 return;
748 }
749
750 cfg80211_vendor_cmd_reply(vendor_event);
Dustin Browne74003f2018-03-14 12:51:58 -0700751 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800752}
753
754/**
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700755 * hdd_llstats_radio_fill_channels() - radio stats fill channels
756 * @adapter: Pointer to device adapter
757 * @radiostat: Pointer to stats data
758 * @vendor_event: vendor event
759 *
760 * Return: 0 on success; errno on failure
761 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700762static int hdd_llstats_radio_fill_channels(struct hdd_adapter *adapter,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700763 tSirWifiRadioStat *radiostat,
764 struct sk_buff *vendor_event)
765{
766 tSirWifiChannelStats *channel_stats;
767 struct nlattr *chlist;
768 struct nlattr *chinfo;
769 int i;
770
771 chlist = nla_nest_start(vendor_event,
772 QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
773 if (chlist == NULL) {
774 hdd_err("nla_nest_start failed");
775 return -EINVAL;
776 }
777
778 for (i = 0; i < radiostat->numChannels; i++) {
779 channel_stats = (tSirWifiChannelStats *) ((uint8_t *)
780 radiostat->channels +
781 (i * sizeof(tSirWifiChannelStats)));
782
783 chinfo = nla_nest_start(vendor_event, i);
784 if (chinfo == NULL) {
785 hdd_err("nla_nest_start failed");
786 return -EINVAL;
787 }
788
789 if (nla_put_u32(vendor_event,
790 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
791 channel_stats->channel.width) ||
792 nla_put_u32(vendor_event,
793 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
794 channel_stats->channel.centerFreq) ||
795 nla_put_u32(vendor_event,
796 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
797 channel_stats->channel.centerFreq0) ||
798 nla_put_u32(vendor_event,
799 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
800 channel_stats->channel.centerFreq1) ||
801 nla_put_u32(vendor_event,
802 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
803 channel_stats->onTime) ||
804 nla_put_u32(vendor_event,
805 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
806 channel_stats->ccaBusyTime)) {
807 hdd_err("nla_put failed");
808 return -EINVAL;
809 }
810 nla_nest_end(vendor_event, chinfo);
811 }
812 nla_nest_end(vendor_event, chlist);
813
814 return 0;
815}
816
817/**
818 * hdd_llstats_post_radio_stats() - post radio stats
819 * @adapter: Pointer to device adapter
820 * @more_data: More data
821 * @radiostat: Pointer to stats data
822 * @num_radio: Number of radios
823 *
824 * Return: 0 on success; errno on failure
825 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700826static int hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700827 u32 more_data,
828 tSirWifiRadioStat *radiostat,
829 u32 num_radio)
830{
831 struct sk_buff *vendor_event;
Jeff Johnson5eb1e682017-08-28 11:42:15 -0700832 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700833 int ret;
834
835 /*
836 * Allocate a size of 4096 for the Radio stats comprising
837 * sizeof (tSirWifiRadioStat) + numChannels * sizeof
838 * (tSirWifiChannelStats).Each channel data is put with an
839 * NL attribute.The size of 4096 is considered assuming that
840 * number of channels shall not exceed beyond 60 with the
841 * sizeof (tSirWifiChannelStats) being 24 bytes.
842 */
843
844 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(
845 hdd_ctx->wiphy,
846 LL_STATS_EVENT_BUF_SIZE);
847
848 if (!vendor_event) {
849 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
850 return -ENOMEM;
851 }
852
853 if (nla_put_u32(vendor_event,
854 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
855 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
856 nla_put_u32(vendor_event,
857 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
858 more_data) ||
859 nla_put_u32(vendor_event,
860 QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
861 num_radio) ||
862 nla_put_u32(vendor_event,
863 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
864 radiostat->radio) ||
865 nla_put_u32(vendor_event,
866 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
867 radiostat->onTime) ||
868 nla_put_u32(vendor_event,
869 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
870 radiostat->txTime) ||
871 nla_put_u32(vendor_event,
872 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
873 radiostat->rxTime) ||
874 nla_put_u32(vendor_event,
875 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
876 radiostat->onTimeScan) ||
877 nla_put_u32(vendor_event,
878 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
879 radiostat->onTimeNbd) ||
880 nla_put_u32(vendor_event,
881 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
882 radiostat->onTimeGscan) ||
883 nla_put_u32(vendor_event,
884 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
885 radiostat->onTimeRoamScan) ||
886 nla_put_u32(vendor_event,
887 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
888 radiostat->onTimePnoScan) ||
889 nla_put_u32(vendor_event,
890 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
891 radiostat->onTimeHs20) ||
892 nla_put_u32(vendor_event,
893 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
894 radiostat->total_num_tx_power_levels) ||
895 nla_put_u32(vendor_event,
896 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
897 radiostat->numChannels)) {
898 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
899 goto failure;
900 }
901
902 if (radiostat->total_num_tx_power_levels) {
903 if (nla_put(vendor_event,
904 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
905 sizeof(u32) *
906 radiostat->total_num_tx_power_levels,
907 radiostat->tx_time_per_power_level)) {
908 hdd_err("nla_put fail");
909 goto failure;
910 }
911 }
912
913 if (radiostat->numChannels) {
914 ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
915 vendor_event);
916 if (ret)
917 goto failure;
918 }
919
920 cfg80211_vendor_cmd_reply(vendor_event);
921 return 0;
922
923failure:
924 kfree_skb(vendor_event);
925 return -EINVAL;
926}
927
928/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 * hdd_link_layer_process_radio_stats() - This function is called after
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700930 * @adapter: Pointer to device adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931 * @more_data: More data
932 * @pData: Pointer to stats data
933 * @num_radios: Number of radios
934 *
935 * Receiving Link Layer Radio statistics from FW.This function converts
936 * the firmware data to the NL data and sends the same to the kernel/upper
937 * layers.
938 *
939 * Return: None
940 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700941static void hdd_link_layer_process_radio_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800942 u32 more_data,
943 tpSirWifiRadioStat pData,
944 u32 num_radio)
945{
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700946 int status, i, nr, ret;
947 tSirWifiRadioStat *pWifiRadioStat = pData;
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700948 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949
Dustin Brown491d54b2018-03-14 12:39:11 -0700950 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530951
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700952 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530953 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800954 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800955
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800956 hdd_debug("LL_STATS_RADIO: number of radios: %u", num_radio);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800957
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700958 for (i = 0; i < num_radio; i++) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800959 hdd_debug("LL_STATS_RADIO"
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700960 " radio: %u onTime: %u txTime: %u rxTime: %u"
961 " onTimeScan: %u onTimeNbd: %u"
962 " onTimeGscan: %u onTimeRoamScan: %u"
963 " onTimePnoScan: %u onTimeHs20: %u"
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -0800964 " numChannels: %u total_num_tx_pwr_levels: %u"
965 " on_time_host_scan: %u, on_time_lpi_scan: %u",
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700966 pWifiRadioStat->radio, pWifiRadioStat->onTime,
967 pWifiRadioStat->txTime, pWifiRadioStat->rxTime,
968 pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd,
969 pWifiRadioStat->onTimeGscan,
970 pWifiRadioStat->onTimeRoamScan,
971 pWifiRadioStat->onTimePnoScan,
972 pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels,
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -0800973 pWifiRadioStat->total_num_tx_power_levels,
974 pWifiRadioStat->on_time_host_scan,
975 pWifiRadioStat->on_time_lpi_scan);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700976 pWifiRadioStat++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800977 }
978
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700979 pWifiRadioStat = pData;
980 for (nr = 0; nr < num_radio; nr++) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700981 ret = hdd_llstats_post_radio_stats(adapter, more_data,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700982 pWifiRadioStat, num_radio);
983 if (ret)
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700984 return;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700985
986 pWifiRadioStat++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700987 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700988
Dustin Browne74003f2018-03-14 12:51:58 -0700989 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990}
991
992/**
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800993 * hdd_ll_process_radio_stats() - Wrapper function for cfg80211/debugfs
994 * @adapter: Pointer to device adapter
995 * @more_data: More data
996 * @data: Pointer to stats data
997 * @num_radios: Number of radios
998 * @resp_id: Response ID from FW
999 *
1000 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1001 * function which calls cfg80211/debugfs functions based on the response ID.
1002 *
1003 * Return: None
1004 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001005static void hdd_ll_process_radio_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001006 uint32_t more_data, void *data, uint32_t num_radio,
1007 uint32_t resp_id)
1008{
1009 if (DEBUGFS_LLSTATS_REQID == resp_id)
1010 hdd_debugfs_process_radio_stats(adapter, more_data,
1011 (tpSirWifiRadioStat)data, num_radio);
1012 else
1013 hdd_link_layer_process_radio_stats(adapter, more_data,
1014 (tpSirWifiRadioStat)data, num_radio);
1015}
1016
1017/**
1018 * hdd_ll_process_iface_stats() - Wrapper function for cfg80211/debugfs
1019 * @adapter: Pointer to device adapter
1020 * @data: Pointer to stats data
1021 * @num_peers: Number of peers
1022 * @resp_id: Response ID from FW
1023 *
1024 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1025 * function which calls cfg80211/debugfs functions based on the response ID.
1026 *
1027 * Return: None
1028 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001029static void hdd_ll_process_iface_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001030 void *data, uint32_t num_peers, uint32_t resp_id)
1031{
1032 if (DEBUGFS_LLSTATS_REQID == resp_id)
1033 hdd_debugfs_process_iface_stats(adapter,
1034 (tpSirWifiIfaceStat) data, num_peers);
1035 else
1036 hdd_link_layer_process_iface_stats(adapter,
1037 (tpSirWifiIfaceStat) data, num_peers);
1038}
1039
1040/**
1041 * hdd_ll_process_peer_stats() - Wrapper function for cfg80211/debugfs
1042 * @adapter: Pointer to device adapter
1043 * @more_data: More data
1044 * @data: Pointer to stats data
1045 * @resp_id: Response ID from FW
1046 *
1047 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1048 * function which calls cfg80211/debugfs functions based on the response ID.
1049 *
1050 * Return: None
1051 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001052static void hdd_ll_process_peer_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001053 uint32_t more_data, void *data, uint32_t resp_id)
1054{
1055 if (DEBUGFS_LLSTATS_REQID == resp_id)
1056 hdd_debugfs_process_peer_stats(adapter, data);
1057 else
1058 hdd_link_layer_process_peer_stats(adapter, more_data,
1059 (tpSirWifiPeerStat) data);
1060}
1061
1062/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001063 * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called
1064 * @ctx: Pointer to hdd context
1065 * @indType: Indication type
1066 * @pRsp: Pointer to response
1067 *
1068 * After receiving Link Layer indications from FW.This callback converts the
1069 * firmware data to the NL data and send the same to the kernel/upper layers.
1070 *
1071 * Return: None
1072 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301073void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001074 int indType, void *pRsp)
1075{
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001076 struct hdd_context *hdd_ctx = (struct hdd_context *) ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001077 struct hdd_ll_stats_context *context;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001078 struct hdd_adapter *adapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001079 tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp;
1080 int status;
1081
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001082 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301083 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001085
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001086 adapter = hdd_get_adapter_by_vdev(hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001087 linkLayerStatsResults->ifaceId);
1088
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001089 if (NULL == adapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001090 hdd_err("vdev_id %d does not exist with host",
1091 linkLayerStatsResults->ifaceId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001092 return;
1093 }
1094
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001095 hdd_debug("Link Layer Indication indType: %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096
1097 switch (indType) {
1098 case SIR_HAL_LL_STATS_RESULTS_RSP:
1099 {
Jeff Johnson36e74c42017-09-18 08:15:42 -07001100 hdd_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %pK",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301101 linkLayerStatsResults->paramId,
1102 linkLayerStatsResults->ifaceId,
1103 linkLayerStatsResults->rspId,
1104 linkLayerStatsResults->moreResultToFollow,
1105 linkLayerStatsResults->num_radio,
1106 linkLayerStatsResults->results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107
1108 context = &ll_stats_context;
1109 spin_lock(&context->context_lock);
1110 /* validate response received from target */
1111 if ((context->request_id != linkLayerStatsResults->rspId) ||
1112 !(context->request_bitmap & linkLayerStatsResults->paramId)) {
1113 spin_unlock(&context->context_lock);
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001114 hdd_err("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001115 context->request_id, linkLayerStatsResults->rspId,
1116 context->request_bitmap, linkLayerStatsResults->paramId);
1117 return;
1118 }
1119 spin_unlock(&context->context_lock);
1120
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001121 if (linkLayerStatsResults->paramId & WMI_LINK_STATS_RADIO) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001122 hdd_ll_process_radio_stats(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001123 linkLayerStatsResults->moreResultToFollow,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001124 linkLayerStatsResults->results,
1125 linkLayerStatsResults->num_radio,
1126 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001127
1128 spin_lock(&context->context_lock);
1129 if (!linkLayerStatsResults->moreResultToFollow)
1130 context->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
1131 spin_unlock(&context->context_lock);
1132
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001133 } else if (linkLayerStatsResults->paramId &
1134 WMI_LINK_STATS_IFACE) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001135 hdd_ll_process_iface_stats(adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001136 linkLayerStatsResults->results,
1137 linkLayerStatsResults->num_peers,
1138 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001139
1140 spin_lock(&context->context_lock);
Srinivas Dasari6946a792015-09-28 15:01:49 +05301141 /* Firmware doesn't send peerstats event if no peers are
1142 * connected. HDD should not wait for any peerstats in
1143 * this case and return the status to middleware after
1144 * receiving iface stats
1145 */
1146 if (!linkLayerStatsResults->num_peers)
1147 context->request_bitmap &=
1148 ~(WMI_LINK_STATS_ALL_PEER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001149 context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
1150 spin_unlock(&context->context_lock);
1151
1152 } else if (linkLayerStatsResults->
1153 paramId & WMI_LINK_STATS_ALL_PEER) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001154 hdd_ll_process_peer_stats(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001155 linkLayerStatsResults->moreResultToFollow,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001156 linkLayerStatsResults->results,
1157 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001158
1159 spin_lock(&context->context_lock);
1160 if (!linkLayerStatsResults->moreResultToFollow)
1161 context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
1162 spin_unlock(&context->context_lock);
1163
1164 } else {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001165 hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001166 }
1167
1168 spin_lock(&context->context_lock);
1169 /* complete response event if all requests are completed */
1170 if (0 == context->request_bitmap)
1171 complete(&context->response_event);
1172 spin_unlock(&context->context_lock);
1173
1174 break;
1175 }
1176 default:
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001177 hdd_warn("invalid event type %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001178 break;
1179 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001180}
1181
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301182void hdd_lost_link_info_cb(void *context,
1183 struct sir_lost_link_info *lost_link_info)
1184{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001185 struct hdd_context *hdd_ctx = (struct hdd_context *)context;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301186 int status;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001187 struct hdd_adapter *adapter;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301188
1189 status = wlan_hdd_validate_context(hdd_ctx);
1190 if (0 != status)
1191 return;
1192
1193 if (NULL == lost_link_info) {
1194 hdd_err("lost_link_info is NULL");
1195 return;
1196 }
1197
1198 adapter = hdd_get_adapter_by_vdev(hdd_ctx, lost_link_info->vdev_id);
1199 if (NULL == adapter) {
1200 hdd_err("invalid adapter");
1201 return;
1202 }
1203
1204 adapter->rssi_on_disconnect = lost_link_info->rssi;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001205 hdd_debug("rssi on disconnect %d", adapter->rssi_on_disconnect);
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301206}
1207
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001208const struct
1209nla_policy
1210 qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1211 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1212 .type = NLA_U32},
1213 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1214 .type = NLA_U32},
1215};
1216
1217/**
1218 * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1219 * @wiphy: Pointer to wiphy
1220 * @wdev: Pointer to wdev
1221 * @data: Pointer to data
1222 * @data_len: Data length
1223 *
1224 * Return: int
1225 */
1226static int
1227__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1228 struct wireless_dev *wdev,
1229 const void *data,
1230 int data_len)
1231{
1232 int status;
1233 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
1234 tSirLLStatsSetReq LinkLayerStatsSetReq;
1235 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001236 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001237 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001238
Dustin Brownfdf17c12018-03-14 12:55:34 -07001239 hdd_enter_dev(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301240
Anurag Chouhan6d760662016-02-20 16:05:43 +05301241 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001242 hdd_err("Command not allowed in FTM mode");
1243 return -EPERM;
1244 }
1245
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001246 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301247 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001248 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249
Dustin Brown4ea21db2018-01-05 14:13:17 -08001250 if (wlan_cfg80211_nla_parse(tb_vendor,
1251 QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1252 (struct nlattr *)data, data_len,
1253 qca_wlan_vendor_ll_set_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001254 hdd_err("maximum attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001255 return -EINVAL;
1256 }
1257
1258 if (!tb_vendor
1259 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001260 hdd_err("MPDU size Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001261 return -EINVAL;
1262 }
1263
1264 if (!tb_vendor
1265 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001266 hdd_err("Stats Gathering Not Present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001267 return -EINVAL;
1268 }
1269
1270 /* Shall take the request Id if the Upper layers pass. 1 For now. */
1271 LinkLayerStatsSetReq.reqId = 1;
1272
1273 LinkLayerStatsSetReq.mpduSizeThreshold =
1274 nla_get_u32(tb_vendor
1275 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1276
1277 LinkLayerStatsSetReq.aggressiveStatisticsGathering =
1278 nla_get_u32(tb_vendor
1279 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1280
Jeff Johnson1b780e42017-10-31 14:11:45 -07001281 LinkLayerStatsSetReq.staId = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001282
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001283 hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301284 LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId,
1285 LinkLayerStatsSetReq.mpduSizeThreshold,
1286 LinkLayerStatsSetReq.aggressiveStatisticsGathering);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001287
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001288 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(hdd_ctx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001289 &LinkLayerStatsSetReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001290 hdd_err("sme_ll_stats_set_req Failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001291 return -EINVAL;
1292 }
1293
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001294 adapter->is_link_layer_stats_set = true;
Dustin Browne74003f2018-03-14 12:51:58 -07001295 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001296 return 0;
1297}
1298
1299/**
1300 * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1301 * @wiphy: Pointer to wiphy
1302 * @wdev: Pointer to wdev
1303 * @data: Pointer to data
1304 * @data_len: Data length
1305 *
1306 * Return: 0 if success, non-zero for failure
1307 */
1308int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1309 struct wireless_dev *wdev,
1310 const void *data,
1311 int data_len)
1312{
1313 int ret = 0;
1314
1315 cds_ssr_protect(__func__);
1316 ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
1317 cds_ssr_unprotect(__func__);
1318
1319 return ret;
1320}
1321
1322const struct
1323nla_policy
1324 qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1325 /* Unsigned 32bit value provided by the caller issuing the GET stats
1326 * command. When reporting
1327 * the stats results, the driver uses the same value to indicate
1328 * which GET request the results
1329 * correspond to.
1330 */
1331 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1332
1333 /* Unsigned 32bit value . bit mask to identify what statistics are
Jeff Johnson8bb78c32017-01-12 08:42:50 -08001334 * requested for retrieval
1335 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001336 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1337};
1338
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001339static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001340 tSirLLStatsGetReq *req)
1341{
1342 unsigned long rc;
1343 struct hdd_ll_stats_context *context;
1344
1345 context = &ll_stats_context;
1346 spin_lock(&context->context_lock);
1347 context->request_id = req->reqId;
1348 context->request_bitmap = req->paramIdMask;
1349 INIT_COMPLETION(context->response_event);
1350 spin_unlock(&context->context_lock);
1351
1352 if (QDF_STATUS_SUCCESS !=
1353 sme_ll_stats_get_req(hdd_ctx->hHal, req)) {
1354 hdd_err("sme_ll_stats_get_req Failed");
1355 return -EINVAL;
1356 }
1357
1358 rc = wait_for_completion_timeout(&context->response_event,
1359 msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
1360 if (!rc) {
1361 hdd_err("Target response timed out request id %d request bitmap 0x%x",
1362 context->request_id, context->request_bitmap);
1363 return -ETIMEDOUT;
1364 }
1365
1366 return 0;
1367}
1368
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001369int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001370 uint32_t req_mask)
1371{
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001372 int ret;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001373 tSirLLStatsGetReq get_req;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001374 struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001375 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001376
Dustin Brown491d54b2018-03-14 12:39:11 -07001377 hdd_enter();
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001378
1379 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1380 hdd_warn("Command not allowed in FTM mode");
1381 return -EPERM;
1382 }
1383
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001384 ret = wlan_hdd_validate_context(hdd_ctx);
1385 if (0 != ret)
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001386 return -EINVAL;
1387
Jeff Johnson690fe952017-10-25 11:48:39 -07001388 if (hddstactx->hdd_reassoc_scenario) {
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001389 hdd_err("Roaming in progress, cannot process the request");
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001390 return -EBUSY;
1391 }
1392
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001393 if (!adapter->is_link_layer_stats_set)
1394 hdd_info("is_link_layer_stats_set: %d; STATs will be all zero",
1395 adapter->is_link_layer_stats_set);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001396
1397 get_req.reqId = req_id;
1398 get_req.paramIdMask = req_mask;
Jeff Johnson1b780e42017-10-31 14:11:45 -07001399 get_req.staId = adapter->session_id;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001400
1401 rtnl_lock();
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001402 ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001403 rtnl_unlock();
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001404 if (0 != ret)
1405 hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
Jeff Johnson1b780e42017-10-31 14:11:45 -07001406 req_id, req_mask, adapter->session_id);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001407
Dustin Browne74003f2018-03-14 12:51:58 -07001408 hdd_exit();
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001409 return ret;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001410
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001411}
1412
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001413/**
1414 * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1415 * @wiphy: Pointer to wiphy
1416 * @wdev: Pointer to wdev
1417 * @data: Pointer to data
1418 * @data_len: Data length
1419 *
1420 * Return: int
1421 */
1422static int
1423__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1424 struct wireless_dev *wdev,
1425 const void *data,
1426 int data_len)
1427{
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001428 int ret;
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001429 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001430 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1431 tSirLLStatsGetReq LinkLayerStatsGetReq;
1432 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001433 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1434 struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001435
Kapil Guptabf4943c2016-10-13 12:15:39 +05301436 /* ENTER() intentionally not used in a frequently invoked API */
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301437
Anurag Chouhan6d760662016-02-20 16:05:43 +05301438 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001439 hdd_err("Command not allowed in FTM mode");
1440 return -EPERM;
1441 }
1442
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001443 ret = wlan_hdd_validate_context(hdd_ctx);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001444 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001447 if (!adapter->is_link_layer_stats_set) {
1448 hdd_warn("is_link_layer_stats_set: %d",
1449 adapter->is_link_layer_stats_set);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001450 return -EINVAL;
1451 }
1452
Jeff Johnson690fe952017-10-25 11:48:39 -07001453 if (hddstactx->hdd_reassoc_scenario) {
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001454 hdd_err("Roaming in progress, cannot process the request");
Anurag Chouhan22520002016-09-03 16:20:32 +05301455 return -EBUSY;
1456 }
1457
Dustin Brown4ea21db2018-01-05 14:13:17 -08001458 if (wlan_cfg80211_nla_parse(tb_vendor,
1459 QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1460 (struct nlattr *)data, data_len,
1461 qca_wlan_vendor_ll_get_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001462 hdd_err("max attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001463 return -EINVAL;
1464 }
1465
1466 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001467 hdd_err("Request Id Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468 return -EINVAL;
1469 }
1470
1471 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001472 hdd_err("Req Mask Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001473 return -EINVAL;
1474 }
1475
1476 LinkLayerStatsGetReq.reqId =
1477 nla_get_u32(tb_vendor
1478 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1479 LinkLayerStatsGetReq.paramIdMask =
1480 nla_get_u32(tb_vendor
1481 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1482
Jeff Johnson1b780e42017-10-31 14:11:45 -07001483 LinkLayerStatsGetReq.staId = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001484
Jeff Johnson1b780e42017-10-31 14:11:45 -07001485 if (wlan_hdd_validate_session_id(adapter->session_id)) {
1486 hdd_err("invalid session id: %d", adapter->session_id);
yeshwanth sriram guntuka08e995b2017-04-26 12:32:12 +05301487 return -EINVAL;
1488 }
1489
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001490 ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &LinkLayerStatsGetReq);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001491 if (0 != ret) {
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001492 hdd_err("Failed to send LL stats request (id:%u)",
1493 LinkLayerStatsGetReq.reqId);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001494 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001495 }
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001496
Dustin Browne74003f2018-03-14 12:51:58 -07001497 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498 return 0;
1499}
1500
1501/**
1502 * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1503 * @wiphy: Pointer to wiphy
1504 * @wdev: Pointer to wdev
1505 * @data: Pointer to data
1506 * @data_len: Data length
1507 *
1508 * Return: 0 if success, non-zero for failure
1509 */
1510int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1511 struct wireless_dev *wdev,
1512 const void *data,
1513 int data_len)
1514{
1515 int ret = 0;
1516
1517 cds_ssr_protect(__func__);
1518 ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1519 cds_ssr_unprotect(__func__);
1520
1521 return ret;
1522}
1523
1524const struct
1525nla_policy
1526 qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1527 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1528 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1529 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1530 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1531};
1532
1533/**
1534 * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1535 * @wiphy: Pointer to wiphy
1536 * @wdev: Pointer to wdev
1537 * @data: Pointer to data
1538 * @data_len: Data length
1539 *
1540 * Return: int
1541 */
1542static int
1543__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1544 struct wireless_dev *wdev,
1545 const void *data,
1546 int data_len)
1547{
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001548 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1550 tSirLLStatsClearReq LinkLayerStatsClearReq;
1551 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001552 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553 u32 statsClearReqMask;
1554 u8 stopReq;
1555 int status;
1556 struct sk_buff *temp_skbuff;
1557
Dustin Brownfdf17c12018-03-14 12:55:34 -07001558 hdd_enter_dev(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301559
Anurag Chouhan6d760662016-02-20 16:05:43 +05301560 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001561 hdd_err("Command not allowed in FTM mode");
1562 return -EPERM;
1563 }
1564
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001565 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301566 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001567 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001568
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001569 if (!adapter->is_link_layer_stats_set) {
1570 hdd_warn("is_link_layer_stats_set : %d",
1571 adapter->is_link_layer_stats_set);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572 return -EINVAL;
1573 }
1574
Dustin Brown4ea21db2018-01-05 14:13:17 -08001575 if (wlan_cfg80211_nla_parse(tb_vendor,
1576 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1577 (struct nlattr *)data, data_len,
1578 qca_wlan_vendor_ll_clr_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001579 hdd_err("STATS_CLR_MAX is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580 return -EINVAL;
1581 }
1582
1583 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1584 !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001585 hdd_err("Error in LL_STATS CLR CONFIG PARA");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586 return -EINVAL;
1587 }
1588
1589 statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1590 nla_get_u32(tb_vendor
1591 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1592
1593 stopReq = LinkLayerStatsClearReq.stopReq =
1594 nla_get_u8(tb_vendor
1595 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1596
1597 /*
1598 * Shall take the request Id if the Upper layers pass. 1 For now.
1599 */
1600 LinkLayerStatsClearReq.reqId = 1;
1601
Jeff Johnson1b780e42017-10-31 14:11:45 -07001602 LinkLayerStatsClearReq.staId = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001604 hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301605 LinkLayerStatsClearReq.reqId,
1606 LinkLayerStatsClearReq.staId,
1607 LinkLayerStatsClearReq.statsClearReqMask,
1608 LinkLayerStatsClearReq.stopReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001609
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001610 if (QDF_STATUS_SUCCESS == sme_ll_stats_clear_req(hdd_ctx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611 &LinkLayerStatsClearReq)) {
1612 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1613 2 *
1614 sizeof(u32) +
1615 2 *
1616 NLMSG_HDRLEN);
1617 if (temp_skbuff != NULL) {
1618 if (nla_put_u32(temp_skbuff,
1619 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1620 statsClearReqMask) ||
1621 nla_put_u32(temp_skbuff,
1622 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1623 stopReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001624 hdd_err("LL_STATS_CLR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625 kfree_skb(temp_skbuff);
1626 return -EINVAL;
1627 }
1628
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001629 /* If the ask is to stop the stats collection
1630 * as part of clear (stopReq = 1), ensure
1631 * that no further requests of get go to the
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001632 * firmware by having is_link_layer_stats_set set
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001633 * to 0. However it the stopReq as part of
1634 * the clear request is 0, the request to get
1635 * the statistics are honoured as in this case
1636 * the firmware is just asked to clear the
1637 * statistics.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638 */
1639 if (stopReq == 1)
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001640 adapter->is_link_layer_stats_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641
1642 return cfg80211_vendor_cmd_reply(temp_skbuff);
1643 }
Dustin Browne74003f2018-03-14 12:51:58 -07001644 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645 return -ENOMEM;
1646 }
1647
1648 return -EINVAL;
1649}
1650
1651/**
1652 * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1653 * @wiphy: Pointer to wiphy
1654 * @wdev: Pointer to wdev
1655 * @data: Pointer to data
1656 * @data_len: Data length
1657 *
1658 * Return: 0 if success, non-zero for failure
1659 */
1660int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1661 struct wireless_dev *wdev,
1662 const void *data,
1663 int data_len)
1664{
1665 int ret = 0;
1666
1667 cds_ssr_protect(__func__);
1668 ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
1669 cds_ssr_unprotect(__func__);
1670
1671 return ret;
1672}
1673
Zhang Qianca38fb12016-12-23 11:10:48 +08001674/**
Qiwei Cai3719efe2018-06-11 21:09:29 +08001675 * wlan_hdd_clear_link_layer_stats() - clear link layer stats
1676 * @adapter: pointer to adapter
1677 *
1678 * Wrapper function to clear link layer stats.
1679 * return - void
1680 */
1681void wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter)
1682{
1683 tSirLLStatsClearReq link_layer_stats_clear_req;
1684 tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter);
1685
1686 link_layer_stats_clear_req.statsClearReqMask = WIFI_STATS_IFACE_AC |
1687 WIFI_STATS_IFACE_ALL_PEER;
1688 link_layer_stats_clear_req.stopReq = 0;
1689 link_layer_stats_clear_req.reqId = 1;
1690 link_layer_stats_clear_req.staId = adapter->session_id;
1691 sme_ll_stats_clear_req(hal, &link_layer_stats_clear_req);
1692}
1693
1694/**
Zhang Qianca38fb12016-12-23 11:10:48 +08001695 * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
1696 * @wifi_peer_info: peer information
1697 * @vendor_event: buffer for vendor event
1698 *
1699 * Return: 0 success
1700 */
1701static inline int
1702hdd_populate_per_peer_ps_info(tSirWifiPeerInfo *wifi_peer_info,
1703 struct sk_buff *vendor_event)
1704{
1705 if (!wifi_peer_info) {
1706 hdd_err("Invalid pointer to peer info.");
1707 return -EINVAL;
1708 }
1709
1710 if (nla_put_u32(vendor_event,
1711 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
1712 wifi_peer_info->power_saving) ||
1713 nla_put(vendor_event,
1714 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
1715 QDF_MAC_ADDR_SIZE, &wifi_peer_info->peerMacAddress)) {
1716 hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
1717 return -EINVAL;
1718 }
1719 return 0;
1720}
1721
1722/**
1723 * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
1724 * @data: stats for peer STA
1725 * @vendor_event: buffer for vendor event
1726 *
1727 * Return: 0 success
1728 */
1729static int hdd_populate_wifi_peer_ps_info(tSirWifiPeerStat *data,
1730 struct sk_buff *vendor_event)
1731{
1732 uint32_t peer_num, i;
1733 tSirWifiPeerInfo *wifi_peer_info;
1734 struct nlattr *peer_info, *peers;
1735
1736 if (!data) {
1737 hdd_err("Invalid pointer to Wifi peer stat.");
1738 return -EINVAL;
1739 }
1740
1741 peer_num = data->numPeers;
1742 if (peer_num == 0) {
1743 hdd_err("Peer number is zero.");
1744 return -EINVAL;
1745 }
1746
1747 if (nla_put_u32(vendor_event,
1748 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
1749 peer_num)) {
1750 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1751 return -EINVAL;
1752 }
1753
1754 peer_info = nla_nest_start(vendor_event,
1755 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
1756 if (peer_info == NULL) {
1757 hdd_err("nla_nest_start failed");
1758 return -EINVAL;
1759 }
1760
1761 for (i = 0; i < peer_num; i++) {
1762 wifi_peer_info = &data->peerInfo[i];
1763 peers = nla_nest_start(vendor_event, i);
1764
1765 if (peers == NULL) {
1766 hdd_err("nla_nest_start failed");
1767 return -EINVAL;
1768 }
1769
1770 if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
1771 return -EINVAL;
1772
1773 nla_nest_end(vendor_event, peers);
1774 }
1775 nla_nest_end(vendor_event, peer_info);
1776
1777 return 0;
1778}
1779
1780/**
1781 * hdd_populate_tx_failure_info() - populate TX failure info
1782 * @tx_fail: TX failure info
1783 * @skb: buffer for vendor event
1784 *
1785 * Return: 0 Success
1786 */
1787static inline int
1788hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
1789 struct sk_buff *skb)
1790{
1791 int status = 0;
1792
1793 if (tx_fail == NULL || skb == NULL)
1794 return -EINVAL;
1795
1796 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
1797 tx_fail->tid) ||
1798 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
1799 tx_fail->msdu_num) ||
1800 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
1801 tx_fail->status)) {
1802 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1803 status = -EINVAL;
1804 }
1805
1806 return status;
1807}
1808
1809/**
Zhang Qian4ead8f02017-03-27 14:21:47 +08001810 * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event
1811 * @info: cca info array for all channels
1812 * @vendor_event: vendor event buffer
1813 *
1814 * Return: 0 Success, EINVAL failure
1815 */
1816static int
1817hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca,
1818 struct sk_buff *vendor_event)
1819{
1820 /* There might be no CCA info for a channel */
1821 if (!cca)
1822 return 0;
1823
1824 if (nla_put_u32(vendor_event,
1825 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
1826 cca->idle_time) ||
1827 nla_put_u32(vendor_event,
1828 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
1829 cca->tx_time) ||
1830 nla_put_u32(vendor_event,
1831 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
1832 cca->rx_in_bss_time) ||
1833 nla_put_u32(vendor_event,
1834 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
1835 cca->rx_out_bss_time) ||
1836 nla_put_u32(vendor_event,
1837 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
1838 cca->rx_busy_time) ||
1839 nla_put_u32(vendor_event,
1840 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
1841 cca->rx_in_bad_cond_time) ||
1842 nla_put_u32(vendor_event,
1843 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
1844 cca->tx_in_bad_cond_time) ||
1845 nla_put_u32(vendor_event,
1846 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
1847 cca->wlan_not_avail_time) ||
1848 nla_put_u32(vendor_event,
1849 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
1850 cca->vdev_id)) {
1851 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1852 return -EINVAL;
1853 }
1854 return 0;
1855}
1856
1857/**
1858 * hdd_populate_wifi_signal_info - put chain signal info
1859 * @info: RF chain signal info
1860 * @skb: vendor event buffer
1861 *
1862 * Return: 0 Success, EINVAL failure
1863 */
1864static int
1865hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal,
1866 struct sk_buff *skb)
1867{
Zhang Qian303ebe92017-05-18 13:59:07 +08001868 uint32_t i, chain_count;
Zhang Qian4ead8f02017-03-27 14:21:47 +08001869 struct nlattr *chains, *att;
1870
1871 /* There might be no signal info for a peer */
1872 if (!peer_signal)
1873 return 0;
1874
Zhang Qian303ebe92017-05-18 13:59:07 +08001875 chain_count = peer_signal->num_chain < WIFI_MAX_CHAINS ?
1876 peer_signal->num_chain : WIFI_MAX_CHAINS;
Zhang Qian4ead8f02017-03-27 14:21:47 +08001877 if (nla_put_u32(skb,
1878 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
Zhang Qian303ebe92017-05-18 13:59:07 +08001879 chain_count)) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001880 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1881 return -EINVAL;
1882 }
1883
1884 att = nla_nest_start(skb,
1885 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL);
1886 if (!att) {
1887 hdd_err("nla_nest_start failed");
1888 return -EINVAL;
1889 }
1890
Zhang Qian303ebe92017-05-18 13:59:07 +08001891 for (i = 0; i < chain_count; i++) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001892 chains = nla_nest_start(skb, i);
1893
1894 if (!chains) {
1895 hdd_err("nla_nest_start failed");
1896 return -EINVAL;
1897 }
1898
Zhang Qian303ebe92017-05-18 13:59:07 +08001899 hdd_debug("SNR=%d, NF=%d, Rx=%d, Tx=%d",
1900 peer_signal->per_ant_snr[i],
1901 peer_signal->nf[i],
1902 peer_signal->per_ant_rx_mpdus[i],
1903 peer_signal->per_ant_tx_mpdus[i]);
Zhang Qian4ead8f02017-03-27 14:21:47 +08001904 if (nla_put_u32(skb,
1905 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
1906 peer_signal->per_ant_snr[i]) ||
1907 nla_put_u32(skb,
1908 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
Zhang Qian303ebe92017-05-18 13:59:07 +08001909 peer_signal->nf[i]) ||
1910 nla_put_u32(skb,
1911 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
1912 peer_signal->per_ant_rx_mpdus[i]) ||
1913 nla_put_u32(skb,
1914 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1915 peer_signal->per_ant_tx_mpdus[i])) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001916 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1917 return -EINVAL;
1918 }
1919 nla_nest_end(skb, chains);
1920 }
1921 nla_nest_end(skb, att);
1922
1923 return 0;
1924}
1925
1926/**
1927 * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info
1928 * @info: tx info
1929 * @skb: vendor event buffer
1930 *
1931 * Return: 0 Success, EINVAL failure
1932 */
1933static int
1934hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats,
1935 struct sk_buff *skb)
1936{
1937 uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay;
1938
1939 /* There might be no TX info for a peer */
1940 if (!tx_stats)
1941 return 0;
1942
1943 agg_size = tx_stats->mpdu_aggr_size;
1944 succ_mcs = tx_stats->success_mcs;
1945 fail_mcs = tx_stats->fail_mcs;
1946 delay = tx_stats->delay;
1947
1948 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
1949 tx_stats->msdus) ||
1950 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1951 tx_stats->mpdus) ||
1952 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
1953 tx_stats->ppdus) ||
1954 nla_put_u32(skb,
1955 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
1956 tx_stats->bytes) ||
1957 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
1958 tx_stats->drops) ||
1959 nla_put_u32(skb,
1960 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
1961 tx_stats->drop_bytes) ||
1962 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
1963 tx_stats->retries) ||
1964 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
1965 tx_stats->failed) ||
1966 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
1967 tx_stats->aggr_len) ||
1968 nla_put_u32(skb,
1969 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
1970 tx_stats->success_mcs_len) ||
1971 nla_put_u32(skb,
1972 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
1973 tx_stats->fail_mcs_len) ||
1974 nla_put_u32(skb,
1975 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
1976 tx_stats->delay_len))
1977 goto put_attr_fail;
1978
1979 if (agg_size) {
1980 if (nla_put(skb,
1981 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
1982 tx_stats->aggr_len, agg_size))
1983 goto put_attr_fail;
1984 }
1985
1986 if (succ_mcs) {
1987 if (nla_put(skb,
1988 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
1989 tx_stats->success_mcs_len, succ_mcs))
1990 goto put_attr_fail;
1991 }
1992
1993 if (fail_mcs) {
1994 if (nla_put(skb,
1995 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
1996 tx_stats->fail_mcs_len, fail_mcs))
1997 goto put_attr_fail;
1998 }
1999
2000 if (delay) {
2001 if (nla_put(skb,
2002 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
2003 tx_stats->delay_len, delay))
2004 goto put_attr_fail;
2005 }
2006 return 0;
2007
2008put_attr_fail:
2009 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2010 return -EINVAL;
2011}
2012
2013/**
2014 * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info
2015 * @info: rx info
2016 * @skb: vendor event buffer
2017 *
2018 * Return: 0 Success, EINVAL failure
2019 */
2020static int
2021hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats,
2022 struct sk_buff *skb)
2023{
2024 uint32_t *mcs, *aggr;
2025
2026 /* There might be no RX info for a peer */
2027 if (!rx_stats)
2028 return 0;
2029
2030 aggr = rx_stats->mpdu_aggr;
2031 mcs = rx_stats->mcs;
2032
2033 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
2034 rx_stats->mpdus) ||
2035 nla_put_u32(skb,
2036 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
2037 rx_stats->bytes) ||
2038 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
2039 rx_stats->ppdus) ||
2040 nla_put_u32(skb,
2041 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
2042 rx_stats->ppdu_bytes) ||
2043 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
2044 rx_stats->mpdu_lost) ||
2045 nla_put_u32(skb,
2046 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
2047 rx_stats->mpdu_retry) ||
2048 nla_put_u32(skb,
2049 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
2050 rx_stats->mpdu_dup) ||
2051 nla_put_u32(skb,
2052 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
2053 rx_stats->mpdu_discard) ||
2054 nla_put_u32(skb,
2055 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
2056 rx_stats->aggr_len) ||
2057 nla_put_u32(skb,
2058 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
2059 rx_stats->mcs_len))
2060 goto put_attr_fail;
2061
2062 if (aggr) {
2063 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
2064 rx_stats->aggr_len, aggr))
2065 goto put_attr_fail;
2066 }
2067
2068 if (mcs) {
2069 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
2070 rx_stats->mcs_len, mcs))
2071 goto put_attr_fail;
2072 }
2073
2074 return 0;
2075
2076put_attr_fail:
2077 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2078 return -EINVAL;
2079}
2080
2081/**
2082 * hdd_populate_wifi_wmm_ac_info() - put WMM AC info
2083 * @info: per AC stats
2084 * @skb: vendor event buffer
2085 *
2086 * Return: 0 Success, EINVAL failure
2087 */
2088static int
2089hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats,
2090 struct sk_buff *skb)
2091{
2092 struct nlattr *wmm;
2093
2094 wmm = nla_nest_start(skb, ac_stats->type);
2095 if (!wmm)
2096 goto nest_start_fail;
2097
2098 if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) ||
2099 hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb))
2100 goto put_attr_fail;
2101
2102 nla_nest_end(skb, wmm);
2103 return 0;
2104
2105nest_start_fail:
2106 hdd_err("nla_nest_start failed");
2107 return -EINVAL;
2108
2109put_attr_fail:
2110 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2111 return -EINVAL;
2112}
2113
2114/**
2115 * hdd_populate_wifi_ll_ext_peer_info() - put per peer info
2116 * @info: peer stats
2117 * @skb: vendor event buffer
2118 *
2119 * Return: 0 Success, EINVAL failure
2120 */
2121static int
2122hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers,
2123 struct sk_buff *skb)
2124{
2125 uint32_t i;
2126 struct nlattr *wmm_ac;
2127
2128 if (nla_put_u32(skb,
2129 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
2130 peers->peer_id) ||
2131 nla_put_u32(skb,
2132 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
2133 peers->vdev_id) ||
2134 nla_put_u32(skb,
2135 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
2136 peers->sta_ps_inds) ||
2137 nla_put_u32(skb,
2138 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
2139 peers->sta_ps_durs) ||
2140 nla_put_u32(skb,
2141 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
2142 peers->rx_probe_reqs) ||
2143 nla_put_u32(skb,
2144 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
2145 peers->rx_oth_mgmts) ||
2146 nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
2147 QDF_MAC_ADDR_SIZE, peers->mac_address) ||
2148 hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) {
2149 hdd_err("put peer signal attr failed");
2150 return -EINVAL;
2151 }
2152
2153 wmm_ac = nla_nest_start(skb,
2154 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS);
2155 if (!wmm_ac) {
2156 hdd_err("nla_nest_start failed");
2157 return -EINVAL;
2158 }
2159
2160 for (i = 0; i < WLAN_MAX_AC; i++) {
2161 if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) {
2162 hdd_err("put WMM AC attr failed");
2163 return -EINVAL;
2164 }
2165 }
2166
2167 nla_nest_end(skb, wmm_ac);
2168 return 0;
2169}
2170
2171/**
2172 * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats
2173 * @info: link layer stats
2174 * @skb: vendor event buffer
2175 *
2176 * Return: 0 Success, EINVAL failure
2177 */
2178static int
2179hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats,
2180 struct sk_buff *skb)
2181{
2182 uint32_t i;
2183 struct nlattr *peer, *peer_info, *channels, *channel_info;
2184
2185 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
2186 stats->trigger_cond_id) ||
2187 nla_put_u32(skb,
2188 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
2189 stats->cca_chgd_bitmap) ||
2190 nla_put_u32(skb,
2191 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
2192 stats->sig_chgd_bitmap) ||
2193 nla_put_u32(skb,
2194 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
2195 stats->tx_chgd_bitmap) ||
2196 nla_put_u32(skb,
2197 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
2198 stats->rx_chgd_bitmap) ||
2199 nla_put_u32(skb,
2200 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
2201 stats->channel_num) ||
2202 nla_put_u32(skb,
2203 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
2204 stats->peer_num)) {
2205 goto put_attr_fail;
2206 }
2207
2208 channels = nla_nest_start(skb,
2209 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS);
2210 if (!channels) {
2211 hdd_err("nla_nest_start failed");
2212 return -EINVAL;
2213 }
2214
2215 for (i = 0; i < stats->channel_num; i++) {
2216 channel_info = nla_nest_start(skb, i);
2217 if (!channel_info) {
2218 hdd_err("nla_nest_start failed");
2219 return -EINVAL;
2220 }
2221
2222 if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb))
2223 goto put_attr_fail;
2224 nla_nest_end(skb, channel_info);
2225 }
2226 nla_nest_end(skb, channels);
2227
2228 peer_info = nla_nest_start(skb,
2229 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER);
2230 if (!peer_info) {
2231 hdd_err("nla_nest_start failed");
2232 return -EINVAL;
2233 }
2234
2235 for (i = 0; i < stats->peer_num; i++) {
2236 peer = nla_nest_start(skb, i);
2237 if (!peer) {
2238 hdd_err("nla_nest_start failed");
2239 return -EINVAL;
2240 }
2241
2242 if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i],
2243 skb))
2244 goto put_attr_fail;
2245 nla_nest_end(skb, peer);
2246 }
2247
2248 nla_nest_end(skb, peer_info);
2249 return 0;
2250
2251put_attr_fail:
2252 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2253 return -EINVAL;
2254}
2255
2256/**
Zhang Qianca38fb12016-12-23 11:10:48 +08002257 * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
2258 * @ctx: HDD context
2259 * @rsp: msg from FW
2260 *
2261 * This function is an extension of
2262 * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
2263 * monitoring parameters offloaded to NL data and send the same to the
2264 * kernel/upper layers.
2265 *
2266 * Return: None
2267 */
Jeff Johnson2d292122018-06-02 21:02:02 -07002268void wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx,
Zhang Qianca38fb12016-12-23 11:10:48 +08002269 tSirLLStatsResults *rsp)
2270{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002271 struct hdd_context *hdd_ctx;
Zhang Qianca38fb12016-12-23 11:10:48 +08002272 struct sk_buff *skb = NULL;
2273 uint32_t param_id, index;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07002274 struct hdd_adapter *adapter = NULL;
Zhang Qianca38fb12016-12-23 11:10:48 +08002275 tSirLLStatsResults *linkLayer_stats_results;
2276 tSirWifiPeerStat *peer_stats;
2277 uint8_t *results;
2278 int status;
2279
Dustin Brown491d54b2018-03-14 12:39:11 -07002280 hdd_enter();
Zhang Qianca38fb12016-12-23 11:10:48 +08002281
2282 if (!ctx) {
2283 hdd_err("Invalid HDD context.");
2284 return;
2285 }
2286
2287 if (!rsp) {
2288 hdd_err("Invalid result.");
2289 return;
2290 }
2291
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002292 hdd_ctx = (struct hdd_context *)ctx;
Zhang Qianca38fb12016-12-23 11:10:48 +08002293 linkLayer_stats_results = rsp;
2294
2295 status = wlan_hdd_validate_context(hdd_ctx);
2296 if (0 != status)
2297 return;
2298
2299 adapter = hdd_get_adapter_by_vdev(hdd_ctx,
2300 linkLayer_stats_results->ifaceId);
2301
Zhang Qian4ead8f02017-03-27 14:21:47 +08002302 if (!adapter) {
Zhang Qianca38fb12016-12-23 11:10:48 +08002303 hdd_err("vdev_id %d does not exist with host.",
2304 linkLayer_stats_results->ifaceId);
2305 return;
2306 }
2307
2308 index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
2309 skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2310 NULL, LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
2311 index, GFP_KERNEL);
2312 if (!skb) {
2313 hdd_err("cfg80211_vendor_event_alloc failed.");
2314 return;
2315 }
2316
2317 results = linkLayer_stats_results->results;
2318 param_id = linkLayer_stats_results->paramId;
Jeff Johnson36e74c42017-09-18 08:15:42 -07002319 hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %pK",
Zhang Qianca38fb12016-12-23 11:10:48 +08002320 linkLayer_stats_results->paramId,
2321 linkLayer_stats_results->ifaceId,
2322 linkLayer_stats_results->results);
2323 if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
2324 peer_stats = (tSirWifiPeerStat *)results;
2325 status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
2326 } else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
2327 struct sir_wifi_iface_tx_fail *tx_fail;
2328
2329 tx_fail = (struct sir_wifi_iface_tx_fail *)results;
2330 status = hdd_populate_tx_failure_info(tx_fail, skb);
2331 } else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
2332 hdd_info("MAC counters stats");
Zhang Qian4ead8f02017-03-27 14:21:47 +08002333 status = hdd_populate_wifi_ll_ext_stats(
2334 (struct sir_wifi_ll_ext_stats *)
2335 rsp->results, skb);
Zhang Qianca38fb12016-12-23 11:10:48 +08002336 } else {
2337 hdd_info("Unknown link layer stats");
2338 status = -EINVAL;
2339 }
2340
2341 if (status == 0)
2342 cfg80211_vendor_event(skb, GFP_KERNEL);
2343 else
2344 kfree_skb(skb);
Dustin Browne74003f2018-03-14 12:51:58 -07002345 hdd_exit();
Zhang Qianca38fb12016-12-23 11:10:48 +08002346}
2347
Zhang Qian4ead8f02017-03-27 14:21:47 +08002348static const struct nla_policy
2349qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = {
2350 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = {
2351 .type = NLA_U32
2352 },
2353 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = {
2354 .type = NLA_U32
2355 },
2356 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = {
2357 .type = NLA_U32
2358 },
2359 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = {
2360 .type = NLA_U32
2361 },
2362 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = {
2363 .type = NLA_U32
2364 },
2365 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = {
2366 .type = NLA_U32
2367 },
2368 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = {
2369 .type = NLA_U32
2370 },
2371 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = {
2372 .type = NLA_U32
2373 },
2374 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = {
2375 .type = NLA_U32
2376 },
2377 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = {
2378 .type = NLA_U32
2379 },
2380 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = {
2381 .type = NLA_U32
2382 },
2383 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = {
2384 .type = NLA_U32
2385 },
2386 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = {
2387 .type = NLA_U32
2388 },
2389 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = {
2390 .type = NLA_U32
2391 },
2392 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = {
2393 .type = NLA_U32
2394 },
2395 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = {
2396 .type = NLA_U32
2397 },
2398 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = {
2399 .type = NLA_U32
2400 },
2401 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = {
2402 .type = NLA_U32
2403 },
2404 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = {
2405 .type = NLA_U32
2406 },
2407 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = {
2408 .type = NLA_U32
2409 },
2410 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = {
2411 .type = NLA_U32
2412 },
2413 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = {
2414 .type = NLA_U32
2415 },
2416 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = {
2417 .type = NLA_U32
2418 },
2419 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = {
2420 .type = NLA_U32
2421 },
2422 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = {
2423 .type = NLA_U32
2424 },
2425 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = {
2426 .type = NLA_U32
2427 },
2428 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = {
2429 .type = NLA_U32
2430 },
2431 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = {
2432 .type = NLA_U32
2433 },
2434 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = {
2435 .type = NLA_U32
2436 },
2437 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = {
2438 .type = NLA_U32
2439 },
2440 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = {
2441 .type = NLA_U32
2442 },
2443 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = {
2444 .type = NLA_U32
2445 },
2446 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = {
2447 .type = NLA_U32
2448 },
2449 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = {
2450 .type = NLA_U32
2451 },
2452 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = {
2453 .type = NLA_U32
2454 },
2455 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = {
2456 .type = NLA_U32
2457 },
2458 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = {
2459 .type = NLA_U32
2460 },
2461 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = {
2462 .type = NLA_U32
2463 },
2464 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = {
2465 .type = NLA_U32
2466 },
2467 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = {
2468 .type = NLA_U32
2469 },
2470 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = {
2471 .type = NLA_U32
2472 },
2473 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = {
2474 .type = NLA_U32
2475 },
2476 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = {
2477 .type = NLA_U32
2478 },
2479 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = {
2480 .type = NLA_U32
2481 },
2482};
2483
2484/**
2485 * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2486 * @wiphy: wiphy handle
2487 * @wdev: wdev handle
2488 * @data: user layer input
2489 * @data_len: length of user layer input
2490 *
2491 * this function is called in ssr protected environment.
2492 *
2493 * return: 0 success, none zero for failure
2494 */
2495static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2496 struct wireless_dev *wdev,
2497 const void *data,
2498 int data_len)
2499{
2500 int status;
2501 uint32_t period;
2502 struct net_device *dev = wdev->netdev;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07002503 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002504 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Zhang Qian4ead8f02017-03-27 14:21:47 +08002505 struct sir_ll_ext_stats_threshold thresh = {0,};
2506 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1];
2507
Dustin Brownfdf17c12018-03-14 12:55:34 -07002508 hdd_enter_dev(dev);
Zhang Qian4ead8f02017-03-27 14:21:47 +08002509
2510 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2511 hdd_warn("command not allowed in ftm mode");
2512 return -EPERM;
2513 }
2514
2515 status = wlan_hdd_validate_context(hdd_ctx);
2516 if (0 != status)
2517 return -EPERM;
2518
Dustin Brown4ea21db2018-01-05 14:13:17 -08002519 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX,
2520 (struct nlattr *)data, data_len,
2521 qca_wlan_vendor_ll_ext_policy)) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08002522 hdd_err("maximum attribute not present");
2523 return -EPERM;
2524 }
2525
2526 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) {
2527 period = nla_get_u32(tb[
2528 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]);
2529
2530 if (period != 0 && period < LL_STATS_MIN_PERIOD)
2531 period = LL_STATS_MIN_PERIOD;
2532
2533 /*
2534 * Only enable/disbale counters.
2535 * Keep the last threshold settings.
2536 */
2537 goto set_period;
2538 }
2539
2540 /* global thresh is not enabled */
2541 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) {
2542 thresh.global = false;
2543 hdd_warn("global thresh is not set");
2544 } else {
2545 thresh.global_threshold = nla_get_u32(tb[
2546 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]);
2547 thresh.global = true;
2548 hdd_debug("globle thresh is %d", thresh.global_threshold);
2549 }
2550
2551 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) {
2552 thresh.global = false;
2553 hdd_warn("global thresh is not enabled");
2554 } else {
2555 thresh.global = nla_get_u32(tb[
2556 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]);
2557 hdd_debug("global is %d", thresh.global);
2558 }
2559
2560 thresh.enable_bitmap = false;
2561 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) {
2562 thresh.tx_bitmap = nla_get_u32(tb[
2563 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]);
2564 thresh.enable_bitmap = true;
2565 }
2566
2567 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) {
2568 thresh.rx_bitmap = nla_get_u32(tb[
2569 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]);
2570 thresh.enable_bitmap = true;
2571 }
2572
2573 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) {
2574 thresh.cca_bitmap = nla_get_u32(tb[
2575 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]);
2576 thresh.enable_bitmap = true;
2577 }
2578
2579 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) {
2580 thresh.signal_bitmap = nla_get_u32(tb[
2581 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]);
2582 thresh.enable_bitmap = true;
2583 }
2584
2585 if (!thresh.global && !thresh.enable_bitmap) {
2586 hdd_warn("threshold will be disabled.");
2587 thresh.enable = false;
2588
2589 /* Just disable threshold */
2590 goto set_thresh;
2591 } else {
2592 thresh.enable = true;
2593 }
2594
2595 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) {
2596 thresh.tx.msdu = nla_get_u32(tb[
2597 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]);
2598 }
2599
2600 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) {
2601 thresh.tx.mpdu = nla_get_u32(tb[
2602 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]);
2603 }
2604
2605 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) {
2606 thresh.tx.ppdu = nla_get_u32(tb[
2607 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]);
2608 }
2609
2610 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) {
2611 thresh.tx.bytes = nla_get_u32(tb[
2612 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]);
2613 }
2614
2615 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) {
2616 thresh.tx.msdu_drop = nla_get_u32(
2617 tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]);
2618 }
2619
2620 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) {
2621 thresh.tx.byte_drop = nla_get_u32(tb[
2622 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]);
2623 }
2624
2625 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) {
2626 thresh.tx.mpdu_retry = nla_get_u32(tb[
2627 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]);
2628 }
2629
2630 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) {
2631 thresh.tx.mpdu_fail = nla_get_u32(tb[
2632 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]);
2633 }
2634
2635 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) {
2636 thresh.tx.ppdu_fail = nla_get_u32(tb[
2637 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]);
2638 }
2639
2640 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) {
2641 thresh.tx.aggregation = nla_get_u32(tb[
2642 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]);
2643 }
2644
2645 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) {
2646 thresh.tx.succ_mcs = nla_get_u32(tb[
2647 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]);
2648 }
2649
2650 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) {
2651 thresh.tx.fail_mcs = nla_get_u32(tb[
2652 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]);
2653 }
2654
2655 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) {
2656 thresh.tx.delay = nla_get_u32(tb[
2657 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]);
2658 }
2659
2660 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) {
2661 thresh.rx.mpdu = nla_get_u32(tb[
2662 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]);
2663 }
2664
2665 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) {
2666 thresh.rx.bytes = nla_get_u32(tb[
2667 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]);
2668 }
2669
2670 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) {
2671 thresh.rx.ppdu = nla_get_u32(tb[
2672 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]);
2673 }
2674
2675 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) {
2676 thresh.rx.ppdu_bytes = nla_get_u32(tb[
2677 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]);
2678 }
2679
2680 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) {
2681 thresh.rx.mpdu_lost = nla_get_u32(tb[
2682 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]);
2683 }
2684
2685 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) {
2686 thresh.rx.mpdu_retry = nla_get_u32(tb[
2687 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]);
2688 }
2689
2690 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) {
2691 thresh.rx.mpdu_dup = nla_get_u32(tb[
2692 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]);
2693 }
2694
2695 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) {
2696 thresh.rx.mpdu_discard = nla_get_u32(tb[
2697 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]);
2698 }
2699
2700 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) {
2701 thresh.rx.aggregation = nla_get_u32(tb[
2702 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]);
2703 }
2704
2705 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) {
2706 thresh.rx.mcs = nla_get_u32(tb[
2707 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]);
2708 }
2709
2710 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) {
2711 thresh.rx.ps_inds = nla_get_u32(tb[
2712 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]);
2713 }
2714
2715 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) {
2716 thresh.rx.ps_durs = nla_get_u32(tb[
2717 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]);
2718 }
2719
2720 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) {
2721 thresh.rx.probe_reqs = nla_get_u32(tb[
2722 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]);
2723 }
2724
2725 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) {
2726 thresh.rx.other_mgmt = nla_get_u32(tb[
2727 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]);
2728 }
2729
2730 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) {
2731 thresh.cca.idle_time = nla_get_u32(tb[
2732 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]);
2733 }
2734
2735 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) {
2736 thresh.cca.tx_time = nla_get_u32(tb[
2737 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]);
2738 }
2739
2740 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) {
2741 thresh.cca.rx_in_bss_time = nla_get_u32(tb[
2742 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]);
2743 }
2744
2745 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) {
2746 thresh.cca.rx_out_bss_time = nla_get_u32(tb[
2747 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]);
2748 }
2749
2750 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) {
2751 thresh.cca.rx_busy_time = nla_get_u32(tb[
2752 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]);
2753 }
2754
2755 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) {
2756 thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[
2757 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]);
2758 }
2759
2760 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) {
2761 thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[
2762 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]);
2763 }
2764
2765 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) {
2766 thresh.cca.wlan_not_avail_time = nla_get_u32(tb[
2767 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]);
2768 }
2769
2770 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) {
2771 thresh.signal.snr = nla_get_u32(tb[
2772 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]);
2773 }
2774
2775 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) {
2776 thresh.signal.nf = nla_get_u32(tb[
2777 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]);
2778 }
2779
2780set_thresh:
2781 hdd_info("send thresh settings to target");
2782 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_thresh(hdd_ctx->hHal,
2783 &thresh)) {
2784 hdd_err("sme_ll_stats_set_thresh failed.");
2785 return -EINVAL;
2786 }
2787 return 0;
2788
2789set_period:
2790 hdd_info("send period to target");
Jeff Johnson1b780e42017-10-31 14:11:45 -07002791 status = wma_cli_set_command(adapter->session_id,
Zhang Qian4ead8f02017-03-27 14:21:47 +08002792 WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD,
2793 period, PDEV_CMD);
2794 if (status) {
2795 hdd_err("wma_cli_set_command set_period failed.");
2796 return -EINVAL;
2797 }
2798 return 0;
2799}
2800
2801/**
2802 * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2803 * @wiphy: wiphy handle
2804 * @wdev: wdev handle
2805 * @data: user layer input
2806 * @data_len: length of user layer input
2807 *
2808 * return: 0 success, einval failure
2809 */
2810int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2811 struct wireless_dev *wdev,
2812 const void *data,
2813 int data_len)
2814{
2815 int ret;
2816
2817 cds_ssr_protect(__func__);
2818 ret = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev,
2819 data, data_len);
2820 cds_ssr_unprotect(__func__);
2821
2822 return ret;
2823}
Qiwei Cai3719efe2018-06-11 21:09:29 +08002824
2825/**
2826 * hdd_init_ll_stats_ctx() - initialize link layer stats context
2827 *
2828 * Return: none
2829 */
2830inline void hdd_init_ll_stats_ctx(void)
2831{
2832 spin_lock_init(&ll_stats_context.context_lock);
2833 init_completion(&ll_stats_context.response_event);
2834 ll_stats_context.request_bitmap = 0;
2835}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
2837
2838#ifdef WLAN_FEATURE_STATS_EXT
2839/**
2840 * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2841 * @wiphy: Pointer to wiphy
2842 * @wdev: Pointer to wdev
2843 * @data: Pointer to data
2844 * @data_len: Data length
2845 *
2846 * Return: int
2847 */
2848static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2849 struct wireless_dev *wdev,
2850 const void *data,
2851 int data_len)
2852{
2853 tStatsExtRequestReq stats_ext_req;
2854 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002855 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002856 int ret_val;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302857 QDF_STATUS status;
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002858 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002859
Dustin Brownfdf17c12018-03-14 12:55:34 -07002860 hdd_enter_dev(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002861
2862 ret_val = wlan_hdd_validate_context(hdd_ctx);
2863 if (ret_val)
2864 return ret_val;
2865
Anurag Chouhan6d760662016-02-20 16:05:43 +05302866 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002867 hdd_err("Command not allowed in FTM mode");
2868 return -EPERM;
2869 }
2870
2871 stats_ext_req.request_data_len = data_len;
2872 stats_ext_req.request_data = (void *)data;
2873
Jeff Johnson1b780e42017-10-31 14:11:45 -07002874 status = sme_stats_ext_request(adapter->session_id, &stats_ext_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002875
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302876 if (QDF_STATUS_SUCCESS != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002877 ret_val = -EINVAL;
2878
2879 return ret_val;
2880}
2881
2882/**
2883 * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2884 * @wiphy: Pointer to wiphy
2885 * @wdev: Pointer to wdev
2886 * @data: Pointer to data
2887 * @data_len: Data length
2888 *
2889 * Return: int
2890 */
2891int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2892 struct wireless_dev *wdev,
2893 const void *data,
2894 int data_len)
2895{
2896 int ret;
2897
2898 cds_ssr_protect(__func__);
2899 ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
2900 data, data_len);
2901 cds_ssr_unprotect(__func__);
2902
2903 return ret;
2904}
2905
2906/**
2907 * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback
2908 * @ctx: Pointer to HDD context
2909 * @msg: Message received
2910 *
2911 * Return: nothing
2912 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05302913void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002914 tStatsExtEvent *msg)
2915{
2916
Jeff Johnsonf645abf2017-09-03 09:07:46 -07002917 struct hdd_context *hdd_ctx = (struct hdd_context *) ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002918 struct sk_buff *vendor_event;
2919 int status;
2920 int ret_val;
2921 tStatsExtEvent *data = msg;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002922 struct hdd_adapter *adapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002923
Jeff Johnsonf645abf2017-09-03 09:07:46 -07002924 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302925 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002926 return;
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302927
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002928 adapter = hdd_get_adapter_by_vdev(hdd_ctx, data->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002929
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002930 if (NULL == adapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002931 hdd_err("vdev_id %d does not exist with host", data->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002932 return;
2933 }
2934
Jeff Johnsonf645abf2017-09-03 09:07:46 -07002935 vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002936 NULL,
2937 data->event_data_len +
2938 sizeof(uint32_t) +
2939 NLMSG_HDRLEN + NLMSG_HDRLEN,
2940 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2941 GFP_KERNEL);
2942
2943 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002944 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002945 return;
2946 }
2947
2948 ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002949 adapter->dev->ifindex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002950 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002951 hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002952 kfree_skb(vendor_event);
2953
2954 return;
2955 }
2956
2957 ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
2958 data->event_data_len, data->event_data);
2959
2960 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002961 hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002962 kfree_skb(vendor_event);
2963
2964 return;
2965 }
2966
2967 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2968
2969}
lifeng66831662017-05-19 16:01:35 +08002970
2971void wlan_hdd_cfg80211_stats_ext2_callback(void *ctx,
2972 struct sir_sme_rx_aggr_hole_ind *pmsg)
2973{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002974 struct hdd_context *hdd_ctx = (struct hdd_context *)ctx;
lifeng66831662017-05-19 16:01:35 +08002975 int status;
2976 uint32_t data_size, hole_info_size;
2977 struct sk_buff *vendor_event;
2978
2979 status = wlan_hdd_validate_context(hdd_ctx);
2980 if (0 != status)
2981 return;
2982
2983 if (NULL == pmsg) {
2984 hdd_err("msg received here is null");
2985 return;
2986 }
2987
2988 hole_info_size = (pmsg->hole_cnt)*sizeof(pmsg->hole_info_array[0]);
2989 data_size = sizeof(struct sir_sme_rx_aggr_hole_ind) + hole_info_size;
2990
2991 vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2992 NULL,
2993 data_size + NLMSG_HDRLEN + NLMSG_HDRLEN,
2994 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2995 GFP_KERNEL);
2996
2997 if (!vendor_event) {
2998 hdd_err("vendor_event_alloc failed for STATS_EXT2");
2999 return;
3000 }
3001
3002 if (nla_put_u32(vendor_event,
3003 QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM,
3004 pmsg->hole_cnt)) {
3005 hdd_err("%s put fail",
3006 "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM");
3007 kfree_skb(vendor_event);
3008 return;
3009 }
3010 if (nla_put(vendor_event,
3011 QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO,
3012 hole_info_size,
3013 (void *)(pmsg->hole_info_array))) {
3014 hdd_err("%s put fail",
3015 "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO");
3016 kfree_skb(vendor_event);
3017 return;
3018 }
3019
3020 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
3021}
3022
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003023#endif /* End of WLAN_FEATURE_STATS_EXT */
3024
Dustin Brown32cb4792017-06-15 15:33:42 -07003025#ifdef LINKSPEED_DEBUG_ENABLED
3026#define linkspeed_dbg(format, args...) pr_info(format, ## args)
3027#else
3028#define linkspeed_dbg(format, args...)
3029#endif /* LINKSPEED_DEBUG_ENABLED */
3030
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003031/**
Dustin Brown0e4479e2017-07-14 14:47:39 -07003032 * wlan_hdd_fill_summary_stats() - populate station_info summary stats
3033 * @stats: summary stats to use as a source
3034 * @info: kernel station_info struct to use as a destination
3035 *
3036 * Return: None
3037 */
3038static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
3039 struct station_info *info)
3040{
3041 int i;
3042
3043 info->rx_packets = stats->rx_frm_cnt;
3044 info->tx_packets = 0;
3045 info->tx_retries = 0;
3046 info->tx_failed = 0;
3047
3048 for (i = 0; i < WIFI_MAX_AC; ++i) {
3049 info->tx_packets += stats->tx_frm_cnt[i];
3050 info->tx_retries += stats->multiple_retry_cnt[i];
3051 info->tx_failed += stats->fail_cnt[i];
3052 }
3053
Naveen Rawat23183d62018-04-12 11:19:01 -07003054 info->filled |= HDD_INFO_TX_PACKETS |
3055 HDD_INFO_TX_RETRIES |
3056 HDD_INFO_TX_FAILED |
3057 HDD_INFO_RX_PACKETS;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003058}
3059
3060/**
3061 * wlan_hdd_get_sap_stats() - get aggregate SAP stats
3062 * @adapter: sap adapter to get stats for
3063 * @info: kernel station_info struct to populate
3064 *
3065 * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to
3066 * support "station dump" and "station get" for SAP vdevs, even though they
3067 * aren't technically stations.
3068 *
3069 * Return: errno
3070 */
3071static int
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003072wlan_hdd_get_sap_stats(struct hdd_adapter *adapter, struct station_info *info)
Dustin Brown0e4479e2017-07-14 14:47:39 -07003073{
Naveen Rawatfa2a1002018-05-17 16:06:37 -07003074 int ret;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003075
Naveen Rawatfa2a1002018-05-17 16:06:37 -07003076 ret = wlan_hdd_get_station_stats(adapter);
3077 if (ret) {
3078 hdd_err("Failed to get SAP stats; status:%d", ret);
3079 return ret;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003080 }
3081
3082 wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, info);
3083
3084 return 0;
3085}
3086
3087/**
Will Huang496b36c2017-07-11 16:38:50 +08003088 * hdd_get_max_rate_legacy() - get max rate for legacy mode
3089 * @stainfo: stainfo pointer
3090 * @rssidx: rssi index
3091 *
3092 * This function will get max rate for legacy mode
3093 *
3094 * Return: max rate on success, otherwise 0
3095 */
Jeff Johnson82155922017-09-30 16:54:14 -07003096static uint32_t hdd_get_max_rate_legacy(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003097 uint8_t rssidx)
3098{
3099 uint32_t maxrate = 0;
3100 /*Minimum max rate, 6Mbps*/
3101 int maxidx = 12;
3102 int i;
3103
3104 /* check supported rates */
3105 if (stainfo->max_supp_idx != 0xff &&
3106 maxidx < stainfo->max_supp_idx)
3107 maxidx = stainfo->max_supp_idx;
3108
3109 /* check extended rates */
3110 if (stainfo->max_ext_idx != 0xff &&
3111 maxidx < stainfo->max_ext_idx)
3112 maxidx = stainfo->max_ext_idx;
3113
3114 for (i = 0; QDF_ARRAY_SIZE(supported_data_rate); i++) {
3115 if (supported_data_rate[i].beacon_rate_index == maxidx)
3116 maxrate =
3117 supported_data_rate[i].supported_rate[rssidx];
3118 }
3119
3120 hdd_debug("maxrate %d", maxrate);
3121
3122 return maxrate;
3123}
3124
3125/**
3126 * hdd_get_max_rate_ht() - get max rate for ht mode
3127 * @stainfo: stainfo pointer
3128 * @stats: fw txrx status pointer
3129 * @rate_flags: rate flags
3130 * @nss: number of streams
3131 * @maxrate: returned max rate buffer pointer
3132 * @max_mcs_idx: max mcs idx
3133 * @report_max: report max rate or actual rate
3134 *
3135 * This function will get max rate for ht mode
3136 *
3137 * Return: None
3138 */
Jeff Johnson82155922017-09-30 16:54:14 -07003139static void hdd_get_max_rate_ht(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003140 struct hdd_fw_txrx_stats *stats,
3141 uint32_t rate_flags,
3142 uint8_t nss,
3143 uint32_t *maxrate,
3144 uint8_t *max_mcs_idx,
3145 bool report_max)
3146{
3147 struct index_data_rate_type *supported_mcs_rate;
3148 uint32_t tmprate;
3149 uint8_t flag = 0, mcsidx;
3150 int8_t rssi = stats->rssi;
3151 int mode;
3152 int i;
3153
Naveen Rawatea1564b2018-05-17 15:56:11 -07003154 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003155 mode = 1;
3156 else
3157 mode = 0;
3158
Naveen Rawatea1564b2018-05-17 15:56:11 -07003159 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003160 flag |= 1;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003161 if (rate_flags & TX_RATE_SGI)
Will Huang496b36c2017-07-11 16:38:50 +08003162 flag |= 2;
3163
3164 supported_mcs_rate = (struct index_data_rate_type *)
3165 ((nss == 1) ? &supported_mcs_rate_nss1 :
3166 &supported_mcs_rate_nss2);
3167
3168 if (stainfo->max_mcs_idx == 0xff) {
3169 hdd_err("invalid max_mcs_idx");
3170 /* report real mcs idx */
3171 mcsidx = stats->tx_rate.mcs;
3172 } else {
3173 mcsidx = stainfo->max_mcs_idx;
3174 }
3175
3176 if (!report_max) {
3177 for (i = 0; i < mcsidx; i++) {
3178 if (rssi <= rssi_mcs_tbl[mode][i]) {
3179 mcsidx = i;
3180 break;
3181 }
3182 }
3183 if (mcsidx < stats->tx_rate.mcs)
3184 mcsidx = stats->tx_rate.mcs;
3185 }
3186
3187 tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
3188
3189 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3190
3191 *maxrate = tmprate;
3192 *max_mcs_idx = mcsidx;
3193}
3194
3195/**
3196 * hdd_get_max_rate_vht() - get max rate for vht mode
3197 * @stainfo: stainfo pointer
3198 * @stats: fw txrx status pointer
3199 * @rate_flags: rate flags
3200 * @nss: number of streams
3201 * @maxrate: returned max rate buffer pointer
3202 * @max_mcs_idx: max mcs idx
3203 * @report_max: report max rate or actual rate
3204 *
3205 * This function will get max rate for vht mode
3206 *
3207 * Return: None
3208 */
Jeff Johnson82155922017-09-30 16:54:14 -07003209static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003210 struct hdd_fw_txrx_stats *stats,
3211 uint32_t rate_flags,
3212 uint8_t nss,
3213 uint32_t *maxrate,
3214 uint8_t *max_mcs_idx,
3215 bool report_max)
3216{
3217 struct index_vht_data_rate_type *supported_vht_mcs_rate;
3218 uint32_t tmprate = 0;
3219 uint32_t vht_max_mcs;
3220 uint8_t flag = 0, mcsidx = INVALID_MCS_IDX;
3221 int8_t rssi = stats->rssi;
3222 int mode;
3223 int i;
3224
3225 supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
3226 ((nss == 1) ?
3227 &supported_vht_mcs_rate_nss1 :
3228 &supported_vht_mcs_rate_nss2);
3229
Naveen Rawatea1564b2018-05-17 15:56:11 -07003230 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003231 mode = 2;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003232 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003233 mode = 1;
3234 else
3235 mode = 0;
3236
3237 if (rate_flags &
Naveen Rawatea1564b2018-05-17 15:56:11 -07003238 (TX_RATE_VHT20 | TX_RATE_VHT40 | TX_RATE_VHT80)) {
Will Huang496b36c2017-07-11 16:38:50 +08003239 vht_max_mcs =
3240 (enum data_rate_11ac_max_mcs)
3241 (stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK);
Naveen Rawatea1564b2018-05-17 15:56:11 -07003242 if (rate_flags & TX_RATE_SGI)
Will Huang496b36c2017-07-11 16:38:50 +08003243 flag |= 1;
3244
3245 if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) {
3246 mcsidx = 7;
3247 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) {
3248 mcsidx = 8;
3249 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) {
3250 /*
3251 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3252 * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6
3253 * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8
3254 */
Naveen Rawatea1564b2018-05-17 15:56:11 -07003255 if ((rate_flags & TX_RATE_VHT20) &&
Will Huang496b36c2017-07-11 16:38:50 +08003256 (nss != 3 && nss != 6))
3257 mcsidx = 8;
3258 else
3259 mcsidx = 9;
3260 } else {
3261 hdd_err("invalid vht_max_mcs");
3262 /* report real mcs idx */
3263 mcsidx = stats->tx_rate.mcs;
3264 }
3265
3266 if (!report_max) {
3267 for (i = 0; i <= mcsidx; i++) {
3268 if (rssi <= rssi_mcs_tbl[mode][i]) {
3269 mcsidx = i;
3270 break;
3271 }
3272 }
3273 if (mcsidx < stats->tx_rate.mcs)
3274 mcsidx = stats->tx_rate.mcs;
3275 }
3276
Naveen Rawatea1564b2018-05-17 15:56:11 -07003277 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003278 tmprate =
3279 supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag];
Naveen Rawatea1564b2018-05-17 15:56:11 -07003280 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003281 tmprate =
3282 supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag];
Naveen Rawatea1564b2018-05-17 15:56:11 -07003283 else if (rate_flags & TX_RATE_VHT20)
Will Huang496b36c2017-07-11 16:38:50 +08003284 tmprate =
3285 supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag];
3286 }
3287
3288 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3289
3290 *maxrate = tmprate;
3291 *max_mcs_idx = mcsidx;
3292}
3293
3294#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
3295/**
3296 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3297 * @stainfo: stainfo pointer
3298 * @rate_flags: HDD rate flags
3299 * @mcsidx: mcs index
3300 * @nss: number of streams
3301 * @vht: vht mode or not
3302 *
3303 * This function will fill ch width and mcs flags
3304 *
3305 * Return: None
3306 */
3307static void hdd_fill_bw_mcs(struct station_info *sinfo,
3308 uint8_t rate_flags,
3309 uint8_t mcsidx,
3310 uint8_t nss,
3311 bool vht)
3312{
3313 if (vht) {
3314 sinfo->txrate.nss = nss;
3315 sinfo->txrate.mcs = mcsidx;
3316 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003317 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003318 sinfo->txrate.bw = RATE_INFO_BW_80;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003319 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003320 sinfo->txrate.bw = RATE_INFO_BW_40;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003321 else if (rate_flags & TX_RATE_VHT20)
Will Huang496b36c2017-07-11 16:38:50 +08003322 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3323 } else {
3324 sinfo->txrate.mcs = (nss - 1) << 3;
3325 sinfo->txrate.mcs |= mcsidx;
3326 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003327 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003328 sinfo->txrate.bw = RATE_INFO_BW_40;
3329 }
3330}
3331#else
3332/**
3333 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3334 * @stainfo: stainfo pointer
3335 * @rate_flags: HDD rate flags
3336 * @mcsidx: mcs index
3337 * @nss: number of streams
3338 * @vht: vht mode or not
3339 *
3340 * This function will fill ch width and mcs flags
3341 *
3342 * Return: None
3343 */
3344static void hdd_fill_bw_mcs(struct station_info *sinfo,
3345 uint8_t rate_flags,
3346 uint8_t mcsidx,
3347 uint8_t nss,
3348 bool vht)
3349{
3350 if (vht) {
3351 sinfo->txrate.nss = nss;
3352 sinfo->txrate.mcs = mcsidx;
3353 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003354 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003355 sinfo->txrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003356 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003357 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003358 else if (rate_flags & TX_RATE_VHT20)
Will Huang496b36c2017-07-11 16:38:50 +08003359 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3360 } else {
3361 sinfo->txrate.mcs = (nss - 1) << 3;
3362 sinfo->txrate.mcs |= mcsidx;
3363 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003364 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003365 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
3366 }
3367}
3368#endif
3369
3370/**
3371 * hdd_fill_bw_mcs_vht() - fill ch width and mcs flags for VHT mode
3372 * @stainfo: stainfo pointer
3373 * @rate_flags: HDD rate flags
3374 * @mcsidx: mcs index
3375 * @nss: number of streams
3376 *
3377 * This function will fill ch width and mcs flags for VHT mode
3378 *
3379 * Return: None
3380 */
3381static void hdd_fill_bw_mcs_vht(struct station_info *sinfo,
3382 uint8_t rate_flags,
3383 uint8_t mcsidx,
3384 uint8_t nss)
3385{
3386 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, true);
3387}
3388
3389/**
3390 * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
3391 * @sinfo: station_info struct pointer
3392 * @rate_flags: HDD rate flags
3393 * @mcsidx: mcs index
3394 * @nss: number of streams
3395 * @maxrate: data rate (kbps)
3396 *
3397 * This function will fill rate info of sinfo struct
3398 *
3399 * Return: None
3400 */
3401static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
3402 uint32_t rate_flags,
3403 uint8_t mcsidx,
3404 uint8_t nss,
3405 uint32_t maxrate)
3406{
Naveen Rawatea1564b2018-05-17 15:56:11 -07003407 if (rate_flags & TX_RATE_LEGACY) {
Will Huang496b36c2017-07-11 16:38:50 +08003408 /* provide to the UI in units of 100kbps */
3409 sinfo->txrate.legacy = maxrate;
3410 } else {
3411 /* must be MCS */
3412 if (rate_flags &
Naveen Rawatea1564b2018-05-17 15:56:11 -07003413 (TX_RATE_VHT80 |
3414 TX_RATE_VHT40 |
3415 TX_RATE_VHT20))
Will Huang496b36c2017-07-11 16:38:50 +08003416 hdd_fill_bw_mcs_vht(sinfo, rate_flags, mcsidx, nss);
3417
Naveen Rawatea1564b2018-05-17 15:56:11 -07003418 if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40))
Will Huang496b36c2017-07-11 16:38:50 +08003419 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, false);
3420
Naveen Rawatea1564b2018-05-17 15:56:11 -07003421 if (rate_flags & TX_RATE_SGI) {
Will Huang496b36c2017-07-11 16:38:50 +08003422 if (!(sinfo->txrate.flags & RATE_INFO_FLAGS_VHT_MCS))
3423 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3424 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3425 }
3426 }
3427
3428 hdd_info("flag %x mcs %d legacy %d nss %d",
3429 sinfo->txrate.flags,
3430 sinfo->txrate.mcs,
3431 sinfo->txrate.legacy,
3432 sinfo->txrate.nss);
3433}
3434
3435/**
3436 * hdd_fill_station_info_flags() - fill flags of sinfo struct
3437 * @sinfo: station_info struct pointer
3438 *
3439 * This function will fill flags of sinfo struct
3440 *
3441 * Return: None
3442 */
3443static void hdd_fill_station_info_flags(struct station_info *sinfo)
3444{
Naveen Rawat23183d62018-04-12 11:19:01 -07003445 sinfo->filled |= HDD_INFO_SIGNAL |
3446 HDD_INFO_TX_BYTES |
3447 HDD_INFO_TX_BYTES64 |
3448 HDD_INFO_TX_BITRATE |
3449 HDD_INFO_TX_PACKETS |
3450 HDD_INFO_TX_RETRIES |
3451 HDD_INFO_TX_FAILED |
3452 HDD_INFO_RX_BYTES |
3453 HDD_INFO_RX_BYTES64 |
3454 HDD_INFO_RX_PACKETS |
3455 HDD_INFO_INACTIVE_TIME |
3456 HDD_INFO_CONNECTED_TIME;
Will Huang496b36c2017-07-11 16:38:50 +08003457}
3458
3459/**
3460 * hdd_fill_rate_info() - fill rate info of sinfo
3461 * @sinfo: station_info struct pointer
3462 * @stainfo: stainfo pointer
3463 * @stats: fw txrx status pointer
3464 * @cfg: hdd config pointer
3465 *
3466 * This function will fill rate info of sinfo
3467 *
3468 * Return: None
3469 */
3470static void hdd_fill_rate_info(struct station_info *sinfo,
Jeff Johnson82155922017-09-30 16:54:14 -07003471 struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003472 struct hdd_fw_txrx_stats *stats,
3473 struct hdd_config *cfg)
3474{
3475 uint8_t rate_flags;
3476 uint8_t mcsidx = 0xff;
3477 uint32_t myrate, maxrate, tmprate;
3478 int rssidx;
3479 int nss = 1;
3480
3481 hdd_info("reportMaxLinkSpeed %d", cfg->reportMaxLinkSpeed);
3482
3483 /* convert to 100kbps expected in rate table */
3484 myrate = stats->tx_rate.rate / 100;
3485 rate_flags = stainfo->rate_flags;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003486 if (!(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003487 nss = stainfo->nss;
3488 if (eHDD_LINK_SPEED_REPORT_ACTUAL == cfg->reportMaxLinkSpeed) {
3489 /* Get current rate flags if report actual */
3490 if (stats->tx_rate.rate_flags)
3491 rate_flags =
3492 stats->tx_rate.rate_flags;
3493 nss = stats->tx_rate.nss;
3494 }
3495
3496 if (stats->tx_rate.mcs == INVALID_MCS_IDX)
Naveen Rawatea1564b2018-05-17 15:56:11 -07003497 rate_flags = TX_RATE_LEGACY;
Will Huang496b36c2017-07-11 16:38:50 +08003498 }
3499
3500 if (eHDD_LINK_SPEED_REPORT_ACTUAL != cfg->reportMaxLinkSpeed) {
3501 /* we do not want to necessarily report the current speed */
3502 if (eHDD_LINK_SPEED_REPORT_MAX == cfg->reportMaxLinkSpeed) {
3503 /* report the max possible speed */
3504 rssidx = 0;
3505 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
3506 cfg->reportMaxLinkSpeed) {
3507 /* report the max possible speed with RSSI scaling */
3508 if (stats->rssi >= cfg->linkSpeedRssiHigh) {
3509 /* report the max possible speed */
3510 rssidx = 0;
3511 } else if (stats->rssi >=
3512 cfg->linkSpeedRssiMid) {
3513 /* report middle speed */
3514 rssidx = 1;
3515 } else if (stats->rssi >=
3516 cfg->linkSpeedRssiLow) {
3517 /* report middle speed */
3518 rssidx = 2;
3519 } else {
3520 /* report actual speed */
3521 rssidx = 3;
3522 }
3523 } else {
3524 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
3525 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
3526 cfg->reportMaxLinkSpeed);
3527 rssidx = 0;
3528 }
3529
3530 maxrate = hdd_get_max_rate_legacy(stainfo, rssidx);
3531
3532 /*
3533 * Get MCS Rate Set --
3534 * Only if we are connected in non legacy mode and not
3535 * reporting actual speed
3536 */
3537 if ((rssidx != 3) &&
Naveen Rawatea1564b2018-05-17 15:56:11 -07003538 !(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003539 hdd_get_max_rate_vht(stainfo,
3540 stats,
3541 rate_flags,
3542 nss,
3543 &tmprate,
3544 &mcsidx,
3545 rssidx == 0);
3546
3547 if (maxrate < tmprate &&
3548 mcsidx != INVALID_MCS_IDX)
3549 maxrate = tmprate;
3550
3551 if (mcsidx == INVALID_MCS_IDX)
3552 hdd_get_max_rate_ht(stainfo,
3553 stats,
3554 rate_flags,
3555 nss,
3556 &tmprate,
3557 &mcsidx,
3558 rssidx == 0);
3559
3560 if (maxrate < tmprate &&
3561 mcsidx != INVALID_MCS_IDX)
3562 maxrate = tmprate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003563 } else if (!(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003564 maxrate = myrate;
3565 mcsidx = stats->tx_rate.mcs;
3566 }
3567
3568 /*
3569 * make sure we report a value at least as big as our
3570 * current rate
3571 */
3572 if ((maxrate < myrate) || (maxrate == 0)) {
3573 maxrate = myrate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003574 if (!(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003575 mcsidx = stats->tx_rate.mcs;
3576 /*
3577 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3578 * - MCS9 is valid for VHT20 when Nss = 3 or
3579 * Nss = 6
3580 * - MCS9 is not valid for VHT20 when
3581 * Nss = 1,2,4,5,7,8
3582 */
Naveen Rawatea1564b2018-05-17 15:56:11 -07003583 if ((rate_flags & TX_RATE_VHT20) &&
Will Huang496b36c2017-07-11 16:38:50 +08003584 (mcsidx > 8) &&
3585 (nss != 3 && nss != 6))
3586 mcsidx = 8;
3587 }
3588 }
3589 } else {
3590 /* report current rate instead of max rate */
3591 maxrate = myrate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003592 if (!(rate_flags & TX_RATE_LEGACY))
Will Huang496b36c2017-07-11 16:38:50 +08003593 mcsidx = stats->tx_rate.mcs;
3594 }
3595
3596 hdd_fill_sinfo_rate_info(sinfo,
3597 rate_flags,
3598 mcsidx,
3599 nss,
3600 maxrate);
3601}
3602
3603/**
3604 * wlan_hdd_fill_station_info() - fill station_info struct
3605 * @sinfo: station_info struct pointer
3606 * @stainfo: stainfo pointer
3607 * @stats: fw txrx status pointer
3608 * @cfg: hdd config pointer
3609 *
3610 * This function will fill station_info struct
3611 *
3612 * Return: None
3613 */
3614static void wlan_hdd_fill_station_info(struct station_info *sinfo,
Jeff Johnson82155922017-09-30 16:54:14 -07003615 struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003616 struct hdd_fw_txrx_stats *stats,
3617 struct hdd_config *cfg)
3618{
3619 qdf_time_t curr_time, dur;
3620
3621 curr_time = qdf_system_ticks();
3622 dur = curr_time - stainfo->assoc_ts;
3623 sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000;
3624 dur = curr_time - stainfo->last_tx_rx_ts;
3625 sinfo->inactive_time = qdf_system_ticks_to_msecs(dur);
3626 sinfo->signal = stats->rssi;
3627 sinfo->tx_bytes = stats->tx_bytes;
3628 sinfo->tx_packets = stats->tx_packets;
3629 sinfo->rx_bytes = stats->rx_bytes;
3630 sinfo->rx_packets = stats->rx_packets;
3631 sinfo->tx_failed = stats->tx_failed;
3632 sinfo->tx_retries = stats->tx_retries;
3633
3634 /* tx rate info */
3635 hdd_fill_rate_info(sinfo, stainfo, stats, cfg);
3636
3637 hdd_fill_station_info_flags(sinfo);
3638
3639 /* dump sta info*/
3640 hdd_info("dump stainfo");
3641 hdd_info("con_time %d inact_time %d tx_pkts %d rx_pkts %d",
3642 sinfo->connected_time, sinfo->inactive_time,
3643 sinfo->tx_packets, sinfo->rx_packets);
3644 hdd_info("failed %d retries %d tx_bytes %lld rx_bytes %lld",
3645 sinfo->tx_failed, sinfo->tx_retries,
3646 sinfo->tx_bytes, sinfo->rx_bytes);
3647 hdd_info("rssi %d mcs %d legacy %d nss %d flags %x",
3648 sinfo->signal, sinfo->txrate.mcs,
3649 sinfo->txrate.legacy, sinfo->txrate.nss,
3650 sinfo->txrate.flags);
3651}
3652
3653/**
3654 * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs
3655 * @rate: Data rate (100 kbps)
3656 * @nss: Number of streams
3657 * @mcs: HT mcs index
3658 *
3659 * This function is used to construct HT rate flag with rate, nss and mcs
3660 *
3661 * Return: rate flags for success, 0 on failure.
3662 */
3663static uint8_t hdd_get_rate_flags_ht(uint32_t rate,
3664 uint8_t nss,
3665 uint8_t mcs)
3666{
3667 struct index_data_rate_type *mcs_rate;
3668 uint8_t flags = 0;
3669
3670 mcs_rate = (struct index_data_rate_type *)
3671 ((nss == 1) ? &supported_mcs_rate_nss1 :
3672 &supported_mcs_rate_nss2);
3673
3674 if (rate == mcs_rate[mcs].supported_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003675 flags |= TX_RATE_HT20;
Will Huang496b36c2017-07-11 16:38:50 +08003676 } else if (rate == mcs_rate[mcs].supported_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003677 flags |= TX_RATE_HT40;
Will Huang496b36c2017-07-11 16:38:50 +08003678 } else if (rate == mcs_rate[mcs].supported_rate[2]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003679 flags |= TX_RATE_HT20;
3680 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003681 } else if (rate == mcs_rate[mcs].supported_rate[3]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003682 flags |= TX_RATE_HT40;
3683 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003684 } else {
3685 hdd_err("invalid params rate %d nss %d mcs %d",
3686 rate, nss, mcs);
3687 }
3688
3689 return flags;
3690}
3691
3692/**
3693 * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs
3694 * @rate: Data rate (100 kbps)
3695 * @nss: Number of streams
3696 * @mcs: VHT mcs index
3697 *
3698 * This function is used to construct VHT rate flag with rate, nss and mcs
3699 *
3700 * Return: rate flags for success, 0 on failure.
3701 */
3702static uint8_t hdd_get_rate_flags_vht(uint32_t rate,
3703 uint8_t nss,
3704 uint8_t mcs)
3705{
3706 struct index_vht_data_rate_type *mcs_rate;
3707 uint8_t flags = 0;
3708
3709 mcs_rate = (struct index_vht_data_rate_type *)
3710 ((nss == 1) ?
3711 &supported_vht_mcs_rate_nss1 :
3712 &supported_vht_mcs_rate_nss2);
3713
3714 if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003715 flags |= TX_RATE_VHT80;
Will Huang496b36c2017-07-11 16:38:50 +08003716 } else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003717 flags |= TX_RATE_VHT80;
3718 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003719 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003720 flags |= TX_RATE_VHT40;
Will Huang496b36c2017-07-11 16:38:50 +08003721 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003722 flags |= TX_RATE_VHT40;
3723 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003724 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003725 flags |= TX_RATE_VHT20;
Will Huang496b36c2017-07-11 16:38:50 +08003726 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003727 flags |= TX_RATE_VHT20;
3728 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003729 } else {
3730 hdd_err("invalid params rate %d nss %d mcs %d",
3731 rate, nss, mcs);
3732 }
3733
3734 return flags;
3735}
3736
3737/**
3738 * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs
3739 * @rate: Data rate (100 kbps)
3740 * @mode: Tx/Rx mode
3741 * @nss: Number of streams
3742 * @mcs: Mcs index
3743 *
3744 * This function is used to construct rate flag with rate, nss and mcs
3745 *
3746 * Return: rate flags for success, 0 on failure.
3747 */
3748static uint8_t hdd_get_rate_flags(uint32_t rate,
3749 uint8_t mode,
3750 uint8_t nss,
3751 uint8_t mcs)
3752{
3753 uint8_t flags = 0;
3754
3755 if (mode == SIR_SME_PHY_MODE_HT)
3756 flags = hdd_get_rate_flags_ht(rate, nss, mcs);
3757 else if (mode == SIR_SME_PHY_MODE_VHT)
3758 flags = hdd_get_rate_flags_vht(rate, nss, mcs);
3759 else
3760 hdd_err("invalid mode param %d", mode);
3761
3762 return flags;
3763}
3764
3765/**
3766 * wlan_hdd_fill_rate_info() - fill HDD rate info from SIR peer info
3767 * @ap_ctx: AP Context
3768 * @peer_info: SIR peer info pointer
3769 *
3770 * This function is used to fill HDD rate info rom SIR peer info
3771 *
3772 * Return: None
3773 */
Jeff Johnson87251032017-08-29 13:31:11 -07003774static void wlan_hdd_fill_rate_info(struct hdd_ap_ctx *ap_ctx,
Will Huang496b36c2017-07-11 16:38:50 +08003775 struct sir_peer_info_ext *peer_info)
3776{
3777 uint8_t flags;
3778 uint32_t rate_code;
3779
3780 /* tx rate info */
3781 ap_ctx->txrx_stats.tx_rate.rate = peer_info->tx_rate;
3782 rate_code = peer_info->tx_rate_code;
3783
3784 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3785 WMI_RATE_PREAMBLE_HT)
3786 ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_HT;
3787 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3788 WMI_RATE_PREAMBLE_VHT)
3789 ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_VHT;
3790 else
3791 ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
3792
3793 ap_ctx->txrx_stats.tx_rate.nss =
3794 WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3795 ap_ctx->txrx_stats.tx_rate.mcs =
3796 WMI_GET_HW_RATECODE_RATE_V1(rate_code);
3797
3798 flags = hdd_get_rate_flags(ap_ctx->txrx_stats.tx_rate.rate / 100,
3799 ap_ctx->txrx_stats.tx_rate.mode,
3800 ap_ctx->txrx_stats.tx_rate.nss,
3801 ap_ctx->txrx_stats.tx_rate.mcs);
3802
3803 ap_ctx->txrx_stats.tx_rate.rate_flags = flags;
3804
3805 hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x",
3806 ap_ctx->txrx_stats.tx_rate.mode,
3807 ap_ctx->txrx_stats.tx_rate.nss,
3808 ap_ctx->txrx_stats.tx_rate.mcs,
3809 ap_ctx->txrx_stats.tx_rate.rate_flags,
3810 flags);
3811
3812 /* rx rate info */
3813 ap_ctx->txrx_stats.rx_rate.rate = peer_info->rx_rate;
3814 rate_code = peer_info->rx_rate_code;
3815
3816 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3817 WMI_RATE_PREAMBLE_HT)
3818 ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_HT;
3819 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3820 WMI_RATE_PREAMBLE_VHT)
3821 ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_VHT;
3822 else
3823 ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
3824
3825 ap_ctx->txrx_stats.rx_rate.nss =
3826 WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3827 ap_ctx->txrx_stats.rx_rate.mcs =
3828 WMI_GET_HW_RATECODE_RATE_V1(rate_code);
3829
3830 flags = hdd_get_rate_flags(ap_ctx->txrx_stats.rx_rate.rate / 100,
3831 ap_ctx->txrx_stats.rx_rate.mode,
3832 ap_ctx->txrx_stats.rx_rate.nss,
3833 ap_ctx->txrx_stats.rx_rate.mcs);
3834
3835 ap_ctx->txrx_stats.rx_rate.rate_flags = flags;
3836
3837 hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x",
3838 ap_ctx->txrx_stats.rx_rate.mode,
3839 ap_ctx->txrx_stats.rx_rate.nss,
3840 ap_ctx->txrx_stats.rx_rate.mcs,
3841 ap_ctx->txrx_stats.rx_rate.rate_flags,
3842 flags);
3843}
3844
3845int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3846 struct net_device *dev,
3847 const u8 *mac,
3848 struct station_info *sinfo);
3849
3850/**
3851 * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
3852 * @wiphy: pointer to wiphy
3853 * @dev: pointer to net_device structure
3854 * @mac: request peer mac address
3855 * @sinfo: pointer to station_info struct
3856 *
3857 * This function will get remote peer info from fw and fill sinfo struct
3858 *
3859 * Return: 0 on success, otherwise error value
3860 */
3861int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3862 struct net_device *dev,
3863 const u8 *mac,
3864 struct station_info *sinfo)
3865{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003866 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07003867 struct hdd_context *hddctx = wiphy_priv(wiphy);
Jeff Johnson87251032017-08-29 13:31:11 -07003868 struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
Jeff Johnson82155922017-09-30 16:54:14 -07003869 struct hdd_station_info *stainfo = NULL;
Will Huang496b36c2017-07-11 16:38:50 +08003870 struct hdd_config *cfg;
3871 struct qdf_mac_addr macaddr;
3872 struct sir_peer_info_ext peer_info;
3873 int status;
3874 int i;
3875
3876 status = wlan_hdd_validate_context(hddctx);
3877 if (status != 0)
3878 return status;
3879
3880 cfg = hddctx->config;
3881
3882 hdd_debug("get peer %pM info", mac);
3883
3884 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003885 if (!qdf_mem_cmp(adapter->sta_info[i].sta_mac.bytes,
Will Huang496b36c2017-07-11 16:38:50 +08003886 mac,
3887 QDF_MAC_ADDR_SIZE)) {
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003888 stainfo = &adapter->sta_info[i];
Will Huang496b36c2017-07-11 16:38:50 +08003889 break;
3890 }
3891 }
3892
3893 if (!stainfo) {
3894 hdd_err("peer %pM not found", mac);
3895 return -EINVAL;
3896 }
3897
3898 qdf_mem_copy(macaddr.bytes, mac, QDF_MAC_ADDR_SIZE);
3899 status = wlan_hdd_get_peer_info(adapter, macaddr, &peer_info);
3900 if (status) {
3901 hdd_err("fail to get peer info from fw");
3902 return -EPERM;
3903 }
3904
3905 qdf_mem_zero(&ap_ctx->txrx_stats, sizeof(ap_ctx->txrx_stats));
3906 ap_ctx->txrx_stats.tx_packets = peer_info.tx_packets;
3907 ap_ctx->txrx_stats.tx_bytes = peer_info.tx_bytes;
3908 ap_ctx->txrx_stats.rx_packets = peer_info.rx_packets;
3909 ap_ctx->txrx_stats.rx_bytes = peer_info.rx_bytes;
3910 ap_ctx->txrx_stats.tx_retries = peer_info.tx_retries;
3911 ap_ctx->txrx_stats.tx_failed = peer_info.tx_failed;
3912 ap_ctx->txrx_stats.rssi =
3913 peer_info.rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM;
3914 wlan_hdd_fill_rate_info(ap_ctx, &peer_info);
3915
3916 wlan_hdd_fill_station_info(sinfo, stainfo, &ap_ctx->txrx_stats, cfg);
3917
3918 return status;
3919}
3920
3921/**
Naveen Rawat374d7982018-04-12 10:56:09 -07003922 * wlan_hdd_get_sta_stats() - get aggregate STA stats
3923 * @wiphy: wireless phy
3924 * @adapter: STA adapter to get stats for
3925 * @mac: mac address of sta
3926 * @sinfo: kernel station_info struct to populate
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927 *
Naveen Rawat374d7982018-04-12 10:56:09 -07003928 * Fetch the vdev-level aggregate stats for the given STA adapter. This is to
3929 * support "station dump" and "station get" for STA vdevs
3930 *
3931 * Return: errno
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003932 */
Naveen Rawat374d7982018-04-12 10:56:09 -07003933static int wlan_hdd_get_sta_stats(struct wiphy *wiphy,
3934 struct hdd_adapter *adapter,
3935 const uint8_t *mac,
3936 struct station_info *sinfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003937{
Jeff Johnsond377dce2017-10-04 10:32:42 -07003938 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
3939 int ssidlen = sta_ctx->conn_info.SSID.SSID.length;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003940 uint8_t rate_flags;
Dustin Brown905cdc72016-11-16 16:51:10 -08003941 uint8_t mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003942
Jeff Johnsonf645abf2017-09-03 09:07:46 -07003943 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
3944 struct hdd_config *pCfg = hdd_ctx->config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003945
3946 uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
3947 uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX;
3948 uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
3949 uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
3950 uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET];
3951 uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET;
3952 uint16_t maxRate = 0;
Anurag Chouhan5de8d172016-07-13 14:44:28 +05303953 int8_t snr = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003954 uint16_t myRate;
3955 uint16_t currentRate = 0;
3956 uint8_t maxSpeedMCS = 0;
3957 uint8_t maxMCSIdx = 0;
3958 uint8_t rateFlag = 1;
3959 uint8_t i, j, rssidx;
3960 uint8_t nss = 1;
Naveen Rawat374d7982018-04-12 10:56:09 -07003961 int mode = 0, maxHtIdx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003962 struct index_vht_data_rate_type *supported_vht_mcs_rate;
3963 struct index_data_rate_type *supported_mcs_rate;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303964#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
3965 bool rssi_stats_valid = false;
3966#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003967
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003968 uint32_t vht_mcs_map;
Will Huang496b36c2017-07-11 16:38:50 +08003969 enum data_rate_11ac_max_mcs vht_max_mcs;
Rajeev Kumar Sirasanagandlab13b7772017-01-24 15:28:29 +05303970 int32_t rcpi_value;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003971
Jeff Johnsond377dce2017-10-04 10:32:42 -07003972 if ((eConnectionState_Associated != sta_ctx->conn_info.connState) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003973 (0 == ssidlen)) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003974 hdd_debug("Not associated or Invalid ssidlen, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003975 ssidlen);
3976 /*To keep GUI happy */
3977 return 0;
3978 }
3979
Jeff Johnson690fe952017-10-25 11:48:39 -07003980 if (sta_ctx->hdd_reassoc_scenario) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003981 hdd_debug("Roaming is in progress, cannot continue with this request");
Sachin Ahujafeedeba2016-09-13 21:54:16 +05303982 /*
3983 * supplicant reports very low rssi to upper layer
3984 * and handover happens to cellular.
3985 * send the cached rssi when get_station
3986 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003987 sinfo->signal = adapter->rssi;
Naveen Rawat23183d62018-04-12 11:19:01 -07003988 sinfo->filled |= HDD_INFO_SIGNAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003989 return 0;
3990 }
3991
Rajeev Kumar Sirasanagandlab13b7772017-01-24 15:28:29 +05303992 if (hdd_ctx->rcpi_enabled)
3993 wlan_hdd_get_rcpi(adapter, (uint8_t *)mac, &rcpi_value,
3994 RCPI_MEASUREMENT_TYPE_AVG_MGMT);
3995
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003996 wlan_hdd_get_station_stats(adapter);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05303997
Paul Zhangb1f35df2018-04-16 12:19:01 +08003998 adapter->rssi = adapter->hdd_stats.summary_stat.rssi;
3999 snr = adapter->hdd_stats.summary_stat.snr;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05304000
4001 /* for new connection there might be no valid previous RSSI */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004002 if (!adapter->rssi) {
4003 hdd_get_rssi_snr_by_bssid(adapter,
Jeff Johnsond377dce2017-10-04 10:32:42 -07004004 sta_ctx->conn_info.bssId.bytes,
Paul Zhangb1f35df2018-04-16 12:19:01 +08004005 &adapter->rssi, &snr);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05304006 }
4007
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004008 sinfo->signal = adapter->rssi;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004009 hdd_debug("snr: %d, rssi: %d",
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004010 adapter->hdd_stats.summary_stat.snr,
4011 adapter->hdd_stats.summary_stat.rssi);
Jeff Johnsond377dce2017-10-04 10:32:42 -07004012 sta_ctx->conn_info.signal = sinfo->signal;
4013 sta_ctx->conn_info.noise =
4014 sta_ctx->conn_info.signal - snr;
Ashish Kumar Dhanotiya36d19b02018-02-22 00:59:49 +05304015 sta_ctx->cache_conn_info.signal = sinfo->signal;
4016 sta_ctx->cache_conn_info.noise = sta_ctx->conn_info.noise;
Naveen Rawat23183d62018-04-12 11:19:01 -07004017 sinfo->filled |= HDD_INFO_SIGNAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004018
Jeff Johnson71396692016-09-23 15:41:52 -07004019 /*
4020 * we notify connect to lpass here instead of during actual
4021 * connect processing because rssi info is not accurate during
4022 * actual connection. lpass will ensure the notification is
4023 * only processed once per association.
4024 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004025 hdd_lpass_notify_connect(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004026
Jeff Johnson861dd4f2017-10-24 10:10:40 -07004027 rate_flags = adapter->hdd_stats.class_a_stat.tx_rate_flags;
4028 mcs_index = adapter->hdd_stats.class_a_stat.mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004029
4030 /* convert to the UI units of 100kbps */
Jeff Johnson861dd4f2017-10-24 10:10:40 -07004031 myRate = adapter->hdd_stats.class_a_stat.tx_rate * 5;
Naveen Rawatea1564b2018-05-17 15:56:11 -07004032 if (!(rate_flags & TX_RATE_LEGACY)) {
Jeff Johnson861dd4f2017-10-24 10:10:40 -07004033 nss = adapter->hdd_stats.class_a_stat.nss;
Liangwei Dong05475a72017-08-09 13:39:57 +09004034 if ((nss > 1) &&
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004035 policy_mgr_is_current_hwmode_dbs(hdd_ctx->hdd_psoc) &&
4036 !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->hdd_psoc)) {
Liangwei Dong05475a72017-08-09 13:39:57 +09004037 hdd_debug("Hw mode is DBS, Reduce nss(%d) to 1", nss);
Agrawal Ashish569ad262017-05-01 14:06:36 +05304038 nss--;
4039 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004040
4041 if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) {
4042 /* Get current rate flags if report actual */
Hanumanth Reddy Pothula063cbe92017-08-08 23:22:01 +05304043 /* WMA fails to find mcs_index for legacy tx rates */
4044 if (mcs_index == INVALID_MCS_IDX && myRate)
Naveen Rawatea1564b2018-05-17 15:56:11 -07004045 rate_flags = TX_RATE_LEGACY;
Hanumanth Reddy Pothula063cbe92017-08-08 23:22:01 +05304046 else
4047 rate_flags =
Jeff Johnson861dd4f2017-10-24 10:10:40 -07004048 adapter->hdd_stats.class_a_stat.mcs_rate_flags;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004049 }
4050
Dustin Brown905cdc72016-11-16 16:51:10 -08004051 if (mcs_index == INVALID_MCS_IDX)
4052 mcs_index = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004053 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004054
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004055 hdd_debug("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d",
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004056 sinfo->signal, pCfg->reportMaxLinkSpeed, myRate,
4057 (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid,
Dustin Brown905cdc72016-11-16 16:51:10 -08004058 (int)pCfg->linkSpeedRssiLow, (int)rate_flags, (int)mcs_index);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004059
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07004060 /* assume basic BW. anything else will override this later */
Dustin Brown32cb4792017-06-15 15:33:42 -07004061 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_20);
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07004062
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004063 if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) {
4064 /* we do not want to necessarily report the current speed */
4065 if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) {
4066 /* report the max possible speed */
4067 rssidx = 0;
4068 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
4069 pCfg->reportMaxLinkSpeed) {
4070 /* report the max possible speed with RSSI scaling */
4071 if (sinfo->signal >= pCfg->linkSpeedRssiHigh) {
4072 /* report the max possible speed */
4073 rssidx = 0;
4074 } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) {
4075 /* report middle speed */
4076 rssidx = 1;
4077 } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) {
4078 /* report middle speed */
4079 rssidx = 2;
4080 } else {
4081 /* report actual speed */
4082 rssidx = 3;
4083 }
4084 } else {
4085 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004086 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004087 pCfg->reportMaxLinkSpeed);
4088 rssidx = 0;
4089 }
4090
4091 maxRate = 0;
4092
4093 /* Get Basic Rate Set */
4094 if (0 !=
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004095 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(adapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004096 WNI_CFG_OPERATIONAL_RATE_SET,
4097 OperationalRates,
4098 &ORLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004099 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004100 /*To keep GUI happy */
4101 return 0;
4102 }
4103
4104 for (i = 0; i < ORLeng; i++) {
4105 for (j = 0;
4106 j < ARRAY_SIZE(supported_data_rate); j++) {
4107 /* Validate Rate Set */
4108 if (supported_data_rate[j].beacon_rate_index ==
4109 (OperationalRates[i] & 0x7F)) {
4110 currentRate =
4111 supported_data_rate[j].
4112 supported_rate[rssidx];
4113 break;
4114 }
4115 }
4116 /* Update MAX rate */
4117 maxRate =
4118 (currentRate > maxRate) ? currentRate : maxRate;
4119 }
4120
4121 /* Get Extended Rate Set */
4122 if (0 !=
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004123 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(adapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004124 WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
4125 ExtendedRates, &ERLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004126 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004127 /*To keep GUI happy */
4128 return 0;
4129 }
4130
4131 for (i = 0; i < ERLeng; i++) {
4132 for (j = 0;
4133 j < ARRAY_SIZE(supported_data_rate); j++) {
4134 if (supported_data_rate[j].beacon_rate_index ==
4135 (ExtendedRates[i] & 0x7F)) {
4136 currentRate =
4137 supported_data_rate[j].
4138 supported_rate[rssidx];
4139 break;
4140 }
4141 }
4142 /* Update MAX rate */
4143 maxRate =
4144 (currentRate > maxRate) ? currentRate : maxRate;
4145 }
Jeff Johnson8bb78c32017-01-12 08:42:50 -08004146 /*
4147 * Get MCS Rate Set --
4148 * Only if we are connected in non legacy mode and not
4149 * reporting actual speed
4150 */
Naveen Rawatea1564b2018-05-17 15:56:11 -07004151 if ((3 != rssidx) && !(rate_flags & TX_RATE_LEGACY)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004152 if (0 !=
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004153 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(adapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004154 WNI_CFG_CURRENT_MCS_SET, MCSRates,
4155 &MCSLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004156 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004157 /*To keep GUI happy */
4158 return 0;
4159 }
4160 rateFlag = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004161 supported_vht_mcs_rate =
4162 (struct index_vht_data_rate_type *)
4163 ((nss ==
4164 1) ? &supported_vht_mcs_rate_nss1 :
4165 &supported_vht_mcs_rate_nss2);
4166
Naveen Rawatea1564b2018-05-17 15:56:11 -07004167 if (rate_flags & TX_RATE_VHT80)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004168 mode = 2;
Naveen Rawatea1564b2018-05-17 15:56:11 -07004169 else if ((rate_flags & TX_RATE_VHT40) ||
4170 (rate_flags & TX_RATE_HT40))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004171 mode = 1;
4172 else
4173 mode = 0;
4174
Jeff Johnsonfa7d9602018-05-06 11:25:31 -07004175 /* VHT80 rate has separate rate table */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004176 if (rate_flags &
Naveen Rawatea1564b2018-05-17 15:56:11 -07004177 (TX_RATE_VHT20 | TX_RATE_VHT40 |
4178 TX_RATE_VHT80)) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004179 sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(adapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004180 WNI_CFG_VHT_TX_MCS_MAP,
4181 &vht_mcs_map);
Will Huang496b36c2017-07-11 16:38:50 +08004182 vht_max_mcs = (enum data_rate_11ac_max_mcs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004183 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
Naveen Rawatea1564b2018-05-17 15:56:11 -07004184 if (rate_flags & TX_RATE_SGI)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004185 rateFlag |= 1;
Dustin Brown32cb4792017-06-15 15:33:42 -07004186
Will Huang496b36c2017-07-11 16:38:50 +08004187 if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004188 maxMCSIdx = 7;
Will Huang496b36c2017-07-11 16:38:50 +08004189 else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004190 maxMCSIdx = 8;
Will Huang496b36c2017-07-11 16:38:50 +08004191 else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs)
Dustin Brown32cb4792017-06-15 15:33:42 -07004192 maxMCSIdx = 9;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004193
4194 if (rssidx != 0) {
4195 for (i = 0; i <= maxMCSIdx; i++) {
4196 if (sinfo->signal <=
4197 rssi_mcs_tbl[mode][i]) {
4198 maxMCSIdx = i;
4199 break;
4200 }
4201 }
4202 }
4203
Naveen Rawatea1564b2018-05-17 15:56:11 -07004204 if (rate_flags & TX_RATE_VHT80) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004205 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08004206 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004207 supported_VHT80_rate[rateFlag];
4208 maxRate =
4209 supported_vht_mcs_rate[maxMCSIdx].
4210 supported_VHT80_rate[rateFlag];
Naveen Rawatea1564b2018-05-17 15:56:11 -07004211 } else if (rate_flags & TX_RATE_VHT40) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004212 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08004213 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004214 supported_VHT40_rate[rateFlag];
4215 maxRate =
4216 supported_vht_mcs_rate[maxMCSIdx].
4217 supported_VHT40_rate[rateFlag];
Naveen Rawatea1564b2018-05-17 15:56:11 -07004218 } else if (rate_flags & TX_RATE_VHT20) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004219 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08004220 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004221 supported_VHT20_rate[rateFlag];
4222 maxRate =
4223 supported_vht_mcs_rate[maxMCSIdx].
4224 supported_VHT20_rate[rateFlag];
4225 }
4226
4227 maxSpeedMCS = 1;
4228 if (currentRate > maxRate)
4229 maxRate = currentRate;
4230
Kiran Kumar Lokere9a733a72016-02-17 19:01:15 -08004231 } else {
Naveen Rawatea1564b2018-05-17 15:56:11 -07004232 if (rate_flags & TX_RATE_HT40)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004233 rateFlag |= 1;
Naveen Rawatea1564b2018-05-17 15:56:11 -07004234 if (rate_flags & TX_RATE_SGI)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004235 rateFlag |= 2;
4236
4237 supported_mcs_rate =
4238 (struct index_data_rate_type *)
4239 ((nss ==
4240 1) ? &supported_mcs_rate_nss1 :
4241 &supported_mcs_rate_nss2);
4242
4243 maxHtIdx = MAX_HT_MCS_IDX;
4244 if (rssidx != 0) {
4245 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
4246 if (sinfo->signal <=
4247 rssi_mcs_tbl[mode][i]) {
4248 maxHtIdx = i + 1;
4249 break;
4250 }
4251 }
4252 }
4253
4254 for (i = 0; i < MCSLeng; i++) {
4255 for (j = 0; j < maxHtIdx; j++) {
4256 if (supported_mcs_rate[j].
4257 beacon_rate_index ==
4258 MCSRates[i]) {
4259 currentRate =
4260 supported_mcs_rate[j].
4261 supported_rate
4262 [rateFlag];
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05304263 maxMCSIdx =
4264 supported_mcs_rate[j].
4265 beacon_rate_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004266 break;
4267 }
4268 }
4269
4270 if ((j < MAX_HT_MCS_IDX)
4271 && (currentRate > maxRate)) {
4272 maxRate = currentRate;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004273 }
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05304274 maxSpeedMCS = 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004275 }
Yeshwanth Sriram Guntukad18c7a22018-02-02 15:22:30 +05304276 if (nss == 2)
4277 maxMCSIdx += MAX_HT_MCS_IDX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004278 }
4279 }
4280
Naveen Rawatea1564b2018-05-17 15:56:11 -07004281 else if (!(rate_flags & TX_RATE_LEGACY)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004282 maxRate = myRate;
4283 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08004284 maxMCSIdx = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004285 }
4286 /* report a value at least as big as current rate */
4287 if ((maxRate < myRate) || (0 == maxRate)) {
4288 maxRate = myRate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07004289 if (rate_flags & TX_RATE_LEGACY) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004290 maxSpeedMCS = 0;
4291 } else {
4292 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08004293 maxMCSIdx = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004294 }
4295 }
4296
Naveen Rawatea1564b2018-05-17 15:56:11 -07004297 if (rate_flags & TX_RATE_LEGACY) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004298 sinfo->txrate.legacy = maxRate;
Dustin Brown32cb4792017-06-15 15:33:42 -07004299 linkspeed_dbg("Reporting legacy rate %d\n",
4300 sinfo->txrate.legacy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004301 } else {
4302 sinfo->txrate.mcs = maxMCSIdx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004303 sinfo->txrate.nss = nss;
Dustin Brown32cb4792017-06-15 15:33:42 -07004304
Naveen Rawatea1564b2018-05-17 15:56:11 -07004305 if (rate_flags & TX_RATE_VHT80)
Dustin Brown32cb4792017-06-15 15:33:42 -07004306 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_80);
Naveen Rawatea1564b2018-05-17 15:56:11 -07004307 else if (rate_flags & TX_RATE_VHT40)
Dustin Brown32cb4792017-06-15 15:33:42 -07004308 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_40);
Visweswara Tanuku1a10e942018-04-09 15:03:53 +05304309 else if (rate_flags & TX_RATE_VHT20)
4310 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_20);
Dustin Brown32cb4792017-06-15 15:33:42 -07004311
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004312 if (rate_flags &
Naveen Rawatea1564b2018-05-17 15:56:11 -07004313 (TX_RATE_HT20 | TX_RATE_HT40)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004314 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07004315 if (rate_flags & TX_RATE_HT40)
Dustin Brown32cb4792017-06-15 15:33:42 -07004316 hdd_set_rate_bw(&sinfo->txrate,
4317 HDD_RATE_BW_40);
Visweswara Tanukubc115202018-04-09 15:20:11 +05304318 else if (rate_flags & TX_RATE_HT20)
4319 hdd_set_rate_bw(&sinfo->txrate,
4320 HDD_RATE_BW_20);
Yeshwanth Sriram Guntukad18c7a22018-02-02 15:22:30 +05304321 } else {
4322 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004323 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004324
Naveen Rawatea1564b2018-05-17 15:56:11 -07004325 if (rate_flags & TX_RATE_SGI) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004326 if (!
4327 (sinfo->txrate.
4328 flags & RATE_INFO_FLAGS_VHT_MCS))
4329 sinfo->txrate.flags |=
4330 RATE_INFO_FLAGS_MCS;
4331 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
4332 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004333 linkspeed_dbg("Reporting MCS rate %d flags %x\n",
4334 sinfo->txrate.mcs, sinfo->txrate.flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004335 }
4336 } else {
4337 /* report current rate instead of max rate */
4338
Naveen Rawatea1564b2018-05-17 15:56:11 -07004339 if (rate_flags & TX_RATE_LEGACY) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004340 /* provide to the UI in units of 100kbps */
4341 sinfo->txrate.legacy = myRate;
Dustin Brown32cb4792017-06-15 15:33:42 -07004342 linkspeed_dbg("Reporting actual legacy rate %d\n",
4343 sinfo->txrate.legacy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004344 } else {
4345 /* must be MCS */
Dustin Brown905cdc72016-11-16 16:51:10 -08004346 sinfo->txrate.mcs = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004347 sinfo->txrate.nss = nss;
Dustin Brown32cb4792017-06-15 15:33:42 -07004348
Naveen Rawatea1564b2018-05-17 15:56:11 -07004349 if (rate_flags & TX_RATE_VHT80)
Dustin Brown32cb4792017-06-15 15:33:42 -07004350 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_80);
Naveen Rawatea1564b2018-05-17 15:56:11 -07004351 else if (rate_flags & TX_RATE_VHT40)
Dustin Brown32cb4792017-06-15 15:33:42 -07004352 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_40);
4353
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004354 if (rate_flags &
Naveen Rawatea1564b2018-05-17 15:56:11 -07004355 (TX_RATE_HT20 | TX_RATE_HT40)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004356 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07004357 if (rate_flags & TX_RATE_HT40)
Dustin Brown32cb4792017-06-15 15:33:42 -07004358 hdd_set_rate_bw(&sinfo->txrate,
4359 HDD_RATE_BW_40);
Yeshwanth Sriram Guntukad18c7a22018-02-02 15:22:30 +05304360 } else {
4361 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004362 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004363
Naveen Rawatea1564b2018-05-17 15:56:11 -07004364 if (rate_flags & TX_RATE_SGI) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004365 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
4366 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
4367 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004368
4369 linkspeed_dbg("Reporting actual MCS rate %d flags %x\n",
4370 sinfo->txrate.mcs, sinfo->txrate.flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004371 }
4372 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004373
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004374 wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, sinfo);
4375 sinfo->tx_bytes = adapter->stats.tx_bytes;
4376 sinfo->rx_bytes = adapter->stats.rx_bytes;
4377 sinfo->rx_packets = adapter->stats.rx_packets;
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004378
Jeff Johnsond377dce2017-10-04 10:32:42 -07004379 qdf_mem_copy(&sta_ctx->conn_info.txrate,
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304380 &sinfo->txrate, sizeof(sinfo->txrate));
Ashish Kumar Dhanotiya36d19b02018-02-22 00:59:49 +05304381 qdf_mem_copy(&sta_ctx->cache_conn_info.txrate,
4382 &sinfo->txrate, sizeof(sinfo->txrate));
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304383
Naveen Rawat23183d62018-04-12 11:19:01 -07004384 sinfo->filled |= HDD_INFO_TX_BITRATE |
4385 HDD_INFO_TX_BYTES |
4386 HDD_INFO_RX_BYTES |
4387 HDD_INFO_RX_PACKETS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004388
Naveen Rawatea1564b2018-05-17 15:56:11 -07004389 if (rate_flags & TX_RATE_LEGACY)
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004390 hdd_debug("Reporting legacy rate %d pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304391 sinfo->txrate.legacy, sinfo->tx_packets,
4392 sinfo->rx_packets);
4393 else
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004394 hdd_debug("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304395 sinfo->txrate.mcs, sinfo->txrate.flags,
4396 sinfo->tx_packets, sinfo->rx_packets);
4397
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304398#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
4399 sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
4400 for (i = 0; i < NUM_CHAINS_MAX; i++) {
4401 sinfo->chain_signal_avg[i] =
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004402 adapter->hdd_stats.per_chain_rssi_stats.rssi[i];
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304403 sinfo->chains |= 1 << i;
4404 if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
4405 sinfo->chain_signal_avg[i] != 0)
4406 sinfo->signal_avg = sinfo->chain_signal_avg[i];
4407
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004408 hdd_debug("RSSI for chain %d, vdev_id %d is %d",
Jeff Johnson1b780e42017-10-31 14:11:45 -07004409 i, adapter->session_id, sinfo->chain_signal_avg[i]);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304410
4411 if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
4412 rssi_stats_valid = true;
4413 }
4414
4415 if (rssi_stats_valid) {
Naveen Rawat23183d62018-04-12 11:19:01 -07004416 sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG;
4417 sinfo->filled |= HDD_INFO_SIGNAL_AVG;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304418 }
4419#endif
4420
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304421 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004422 TRACE_CODE_HDD_CFG80211_GET_STA,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004423 adapter->session_id, maxRate));
Dustin Brown32cb4792017-06-15 15:33:42 -07004424
Dustin Browne74003f2018-03-14 12:51:58 -07004425 hdd_exit();
Dustin Brown32cb4792017-06-15 15:33:42 -07004426
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427 return 0;
4428}
4429
4430/**
Naveen Rawat374d7982018-04-12 10:56:09 -07004431 * __wlan_hdd_cfg80211_get_station() - get station statistics
4432 * @wiphy: Pointer to wiphy
4433 * @dev: Pointer to network device
4434 * @mac: Pointer to mac
4435 * @sinfo: Pointer to station info
4436 *
4437 * Return: 0 for success, non-zero for failure
4438 */
4439static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4440 struct net_device *dev,
4441 const uint8_t *mac,
4442 struct station_info *sinfo)
4443{
4444 int status;
4445 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4446 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
4447
4448 hdd_enter_dev(dev);
4449
4450 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
4451 hdd_err("Command not allowed in FTM mode");
4452 return -EINVAL;
4453 }
4454
4455 status = wlan_hdd_validate_context(hdd_ctx);
4456 if (status)
4457 return status;
4458
4459 if (wlan_hdd_validate_session_id(adapter->session_id)) {
4460 hdd_err("invalid session id: %d", adapter->session_id);
4461 return -EINVAL;
4462 }
4463
4464 if (adapter->device_mode == QDF_SAP_MODE)
4465 return wlan_hdd_get_sap_stats(adapter, sinfo);
4466 else
4467 return wlan_hdd_get_sta_stats(wiphy, adapter, mac, sinfo);
4468}
4469
4470/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471 * wlan_hdd_cfg80211_get_station() - get station statistics
4472 * @wiphy: Pointer to wiphy
4473 * @dev: Pointer to network device
4474 * @mac: Pointer to mac
4475 * @sinfo: Pointer to station info
4476 *
4477 * Return: 0 for success, non-zero for failure
4478 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004479int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4480 struct net_device *dev, const uint8_t *mac,
4481 struct station_info *sinfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004482{
4483 int ret;
4484
4485 cds_ssr_protect(__func__);
4486 ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4487 cds_ssr_unprotect(__func__);
4488
4489 return ret;
4490}
4491
4492/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304493 * __wlan_hdd_cfg80211_dump_station() - dump station statistics
4494 * @wiphy: Pointer to wiphy
4495 * @dev: Pointer to network device
4496 * @idx: variable to determine whether to get stats or not
4497 * @mac: Pointer to mac
4498 * @sinfo: Pointer to station info
4499 *
4500 * Return: 0 for success, non-zero for failure
4501 */
4502static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4503 struct net_device *dev,
4504 int idx, u8 *mac,
4505 struct station_info *sinfo)
4506{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07004507 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304508
4509 hdd_debug("%s: idx %d", __func__, idx);
4510 if (idx != 0)
4511 return -ENOENT;
4512 qdf_mem_copy(mac, hdd_ctx->config->intfMacAddr[0].bytes,
4513 QDF_MAC_ADDR_SIZE);
4514 return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4515}
4516
4517/**
4518 * wlan_hdd_cfg80211_dump_station() - dump station statistics
4519 * @wiphy: Pointer to wiphy
4520 * @dev: Pointer to network device
4521 * @idx: variable to determine whether to get stats or not
4522 * @mac: Pointer to mac
4523 * @sinfo: Pointer to station info
4524 *
4525 * Return: 0 for success, non-zero for failure
4526 */
4527int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4528 struct net_device *dev,
4529 int idx, u8 *mac,
4530 struct station_info *sinfo)
4531{
4532 int ret;
4533
4534 cds_ssr_protect(__func__);
4535 ret = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
4536 cds_ssr_unprotect(__func__);
4537 return ret;
4538}
4539
4540/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004541 * hdd_get_stats() - Function to retrieve interface statistics
4542 * @dev: pointer to network device
4543 *
4544 * This function is the ndo_get_stats method for all netdevs
4545 * registered with the kernel
4546 *
4547 * Return: pointer to net_device_stats structure
4548 */
4549struct net_device_stats *hdd_get_stats(struct net_device *dev)
4550{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07004551 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004552
Dustin Brownfdf17c12018-03-14 12:55:34 -07004553 hdd_enter_dev(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004554 return &adapter->stats;
4555}
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304556
4557
4558/*
4559 * time = cycle_count * cycle
4560 * cycle = 1 / clock_freq
4561 * Since the unit of clock_freq reported from
4562 * FW is MHZ, and we want to calculate time in
4563 * ms level, the result is
4564 * time = cycle / (clock_freq * 1000)
4565 */
4566#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
4567static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4568 struct scan_chan_info *chan_info,
4569 struct ieee80211_channel *channels)
4570{
4571 uint64_t clock_freq = chan_info->clock_freq * 1000;
4572
4573 if (channels->center_freq != (uint16_t)chan_info->freq)
4574 return false;
4575
4576 survey->channel = channels;
4577 survey->noise = chan_info->noise_floor;
4578 survey->filled = SURVEY_INFO_NOISE_DBM;
4579
4580 if (opfreq == chan_info->freq)
4581 survey->filled |= SURVEY_INFO_IN_USE;
4582
4583 if (clock_freq == 0)
4584 return true;
4585
Nirav Shaheb017be2018-02-15 11:20:58 +05304586 survey->time = qdf_do_div(chan_info->cycle_count, clock_freq);
4587
4588 survey->time_busy = qdf_do_div(chan_info->rx_clear_count, clock_freq);
4589
4590 survey->time_tx = qdf_do_div(chan_info->tx_frame_count, clock_freq);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304591
4592 survey->filled |= SURVEY_INFO_TIME |
4593 SURVEY_INFO_TIME_BUSY |
4594 SURVEY_INFO_TIME_TX;
4595 return true;
4596}
4597#else
4598static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4599 struct scan_chan_info *chan_info,
4600 struct ieee80211_channel *channels)
4601{
4602 uint64_t clock_freq = chan_info->clock_freq * 1000;
4603
4604 if (channels->center_freq != (uint16_t)chan_info->freq)
4605 return false;
4606
4607 survey->channel = channels;
4608 survey->noise = chan_info->noise_floor;
4609 survey->filled = SURVEY_INFO_NOISE_DBM;
4610
4611 if (opfreq == chan_info->freq)
4612 survey->filled |= SURVEY_INFO_IN_USE;
4613
4614 if (clock_freq == 0)
4615 return true;
4616
Nirav Shaheb017be2018-02-15 11:20:58 +05304617 survey->channel_time = qdf_do_div(chan_info->cycle_count, clock_freq);
4618
4619 survey->channel_time_busy = qdf_do_div(chan_info->rx_clear_count,
4620 clock_freq);
4621
4622 survey->channel_time_tx = qdf_do_div(chan_info->tx_frame_count,
4623 clock_freq);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304624
4625 survey->filled |= SURVEY_INFO_CHANNEL_TIME |
4626 SURVEY_INFO_CHANNEL_TIME_BUSY |
4627 SURVEY_INFO_CHANNEL_TIME_TX;
4628 return true;
4629}
4630#endif
4631
4632static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
Jeff Johnson32bd9742018-03-29 13:42:31 -07004633 struct hdd_adapter *adapter,
4634 struct survey_info *survey, int idx)
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304635{
4636 bool filled = false;
4637 int i, j = 0;
4638 uint32_t channel = 0, opfreq; /* Initialization Required */
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004639 struct hdd_context *hdd_ctx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304640
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004641 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson1b780e42017-10-31 14:11:45 -07004642 sme_get_operation_channel(hdd_ctx->hHal, &channel, adapter->session_id);
Jeff Johnson32bd9742018-03-29 13:42:31 -07004643 opfreq = wlan_reg_chan_to_freq(hdd_ctx->hdd_pdev, channel);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304644
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004645 mutex_lock(&hdd_ctx->chan_info_lock);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304646
Srinivas Girigowda5da651b2017-08-04 11:22:54 -07004647 for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) {
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304648 if (wiphy->bands[i] == NULL)
4649 continue;
4650
4651 for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
4652 struct ieee80211_supported_band *band = wiphy->bands[i];
Jeff Johnson4f7f7c62017-10-05 08:53:41 -07004653
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304654 filled = wlan_fill_survey_result(survey, opfreq,
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004655 &hdd_ctx->chan_info[idx],
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304656 &band->channels[j]);
4657 }
4658 }
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004659 mutex_unlock(&hdd_ctx->chan_info_lock);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304660
4661 return filled;
4662}
4663
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004664/**
4665 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
4666 * @wiphy: Pointer to wiphy
4667 * @dev: Pointer to network device
4668 * @idx: Index
4669 * @survey: Pointer to survey info
4670 *
4671 * Return: 0 for success, non-zero for failure
4672 */
4673static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4674 struct net_device *dev,
4675 int idx, struct survey_info *survey)
4676{
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004677 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004678 struct hdd_context *hdd_ctx;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004679 struct hdd_station_ctx *sta_ctx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304680 int status;
4681 bool filled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004682
Dustin Brownfdf17c12018-03-14 12:55:34 -07004683 hdd_enter_dev(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004684
Srinivas Girigowda6598eea2017-07-06 19:26:19 -07004685 hdd_debug("dump survey index: %d", idx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304686 if (idx > QDF_MAX_NUM_CHAN - 1)
4687 return -EINVAL;
4688
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004689 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004690 status = wlan_hdd_validate_context(hdd_ctx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304691 if (0 != status)
4692 return status;
4693
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004694 if (hdd_ctx->chan_info == NULL) {
Tushnim Bhattacharyya929afa42018-06-01 15:04:44 -07004695 hdd_debug("chan_info is NULL");
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304696 return -EINVAL;
4697 }
4698
4699 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004700 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004701 return -EINVAL;
4702 }
4703
Jeff Johnsond377dce2017-10-04 10:32:42 -07004704 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004705
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004706 if (hdd_ctx->config->fEnableSNRMonitoring == 0)
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304707 return -ENONET;
4708
Jeff Johnson690fe952017-10-25 11:48:39 -07004709 if (sta_ctx->hdd_reassoc_scenario) {
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304710 hdd_info("Roaming in progress, hence return");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004711 return -ENONET;
4712 }
4713
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004714 filled = wlan_hdd_update_survey_info(wiphy, adapter, survey, idx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304715
4716 if (!filled)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004717 return -ENONET;
Dustin Browne74003f2018-03-14 12:51:58 -07004718 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004719 return 0;
4720}
4721
4722/**
4723 * wlan_hdd_cfg80211_dump_survey() - get survey related info
4724 * @wiphy: Pointer to wiphy
4725 * @dev: Pointer to network device
4726 * @idx: Index
4727 * @survey: Pointer to survey info
4728 *
4729 * Return: 0 for success, non-zero for failure
4730 */
4731int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4732 struct net_device *dev,
4733 int idx, struct survey_info *survey)
4734{
4735 int ret;
4736
4737 cds_ssr_protect(__func__);
4738 ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
4739 cds_ssr_unprotect(__func__);
4740
4741 return ret;
4742}
Nirav Shahbf1b0332016-05-25 14:27:39 +05304743
4744/**
4745 * hdd_display_hif_stats() - display hif stats
4746 *
4747 * Return: none
4748 *
4749 */
4750void hdd_display_hif_stats(void)
4751{
4752 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
4753
4754 if (!hif_ctx)
4755 return;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -07004756
Nirav Shahbf1b0332016-05-25 14:27:39 +05304757 hif_display_stats(hif_ctx);
4758}
4759
4760/**
4761 * hdd_clear_hif_stats() - clear hif stats
4762 *
4763 * Return: none
4764 */
4765void hdd_clear_hif_stats(void)
4766{
4767 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
4768
4769 if (!hif_ctx)
4770 return;
4771 hif_clear_stats(hif_ctx);
4772}
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05304773
4774/**
4775 * hdd_is_rcpi_applicable() - validates RCPI request
4776 * @adapter: adapter upon which the measurement is requested
4777 * @mac_addr: peer addr for which measurement is requested
4778 * @rcpi_value: pointer to where the RCPI should be returned
4779 * @reassoc: used to return cached RCPI during reassoc
4780 *
4781 * Return: true for success, false for failure
4782 */
4783
4784static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter,
4785 struct qdf_mac_addr *mac_addr,
4786 int32_t *rcpi_value,
4787 bool *reassoc)
4788{
4789 struct hdd_station_ctx *hdd_sta_ctx;
4790
4791 if (adapter->device_mode == QDF_STA_MODE ||
4792 adapter->device_mode == QDF_P2P_CLIENT_MODE) {
4793 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4794 if (hdd_sta_ctx->conn_info.connState !=
4795 eConnectionState_Associated)
4796 return false;
4797
4798 if (hdd_sta_ctx->hdd_reassoc_scenario) {
4799 /* return the cached rcpi, if mac addr matches */
4800 hdd_debug("Roaming in progress, return cached RCPI");
4801 if (!qdf_mem_cmp(&adapter->rcpi.mac_addr,
4802 mac_addr, sizeof(*mac_addr))) {
4803 *rcpi_value = adapter->rcpi.rcpi;
4804 *reassoc = true;
4805 return true;
4806 }
4807 return false;
4808 }
4809
4810 if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssId,
4811 sizeof(*mac_addr))) {
4812 hdd_err("mac addr is different from bssid connected");
4813 return false;
4814 }
4815 } else if (adapter->device_mode == QDF_SAP_MODE ||
4816 adapter->device_mode == QDF_P2P_GO_MODE) {
4817 if (!test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) {
4818 hdd_err("Invalid rcpi request, softap not started");
4819 return false;
4820 }
4821
4822 /* check if peer mac addr is associated to softap */
4823 if (!hdd_is_peer_associated(adapter, mac_addr)) {
4824 hdd_err("invalid peer mac-addr: not associated");
4825 return false;
4826 }
4827 } else {
4828 hdd_err("Invalid rcpi request");
4829 return false;
4830 }
4831
4832 *reassoc = false;
4833 return true;
4834}
4835
4836/**
4837 * wlan_hdd_get_rcpi_cb() - callback function for rcpi response
4838 * @context: Pointer to rcpi context
4839 * @rcpi_req: Pointer to rcpi response
4840 *
4841 * Return: None
4842 */
4843static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr,
4844 int32_t rcpi, QDF_STATUS status)
4845{
4846 struct hdd_request *request;
4847 struct rcpi_info *priv;
4848
4849 if (!context) {
4850 hdd_err("No rcpi context");
4851 return;
4852 }
4853
4854 request = hdd_request_get(context);
4855 if (!request) {
4856 hdd_err("Obsolete RCPI request");
4857 return;
4858 }
4859
4860 priv = hdd_request_priv(request);
4861 priv->mac_addr = mac_addr;
4862
4863 if (!QDF_IS_STATUS_SUCCESS(status)) {
4864 priv->rcpi = 0;
4865 hdd_err("Error in computing RCPI");
4866 } else {
4867 priv->rcpi = rcpi;
4868 }
4869
4870 hdd_request_complete(request);
4871 hdd_request_put(request);
4872}
4873
4874/**
4875 * __wlan_hdd_get_rcpi() - local function to get RCPI
4876 * @adapter: adapter upon which the measurement is requested
4877 * @mac: peer addr for which measurement is requested
4878 * @rcpi_value: pointer to where the RCPI should be returned
4879 * @measurement_type: type of rcpi measurement
4880 *
4881 * Return: 0 for success, non-zero for failure
4882 */
4883static int __wlan_hdd_get_rcpi(struct hdd_adapter *adapter,
4884 uint8_t *mac,
4885 int32_t *rcpi_value,
4886 enum rcpi_measurement_type measurement_type)
4887{
4888 struct hdd_context *hdd_ctx;
4889 int status = 0, ret = 0;
4890 struct qdf_mac_addr mac_addr;
4891 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
4892 struct sme_rcpi_req *rcpi_req;
4893 void *cookie;
4894 struct rcpi_info *priv;
4895 struct hdd_request *request;
4896 static const struct hdd_request_params params = {
4897 .priv_size = sizeof(*priv),
4898 .timeout_ms = WLAN_WAIT_TIME_RCPI,
4899 };
4900 bool reassoc;
4901
Dustin Brown491d54b2018-03-14 12:39:11 -07004902 hdd_enter();
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05304903
4904 /* initialize the rcpi value to zero, useful in error cases */
4905 *rcpi_value = 0;
4906
4907 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
4908 hdd_err("Command not allowed in FTM mode");
4909 return -EINVAL;
4910 }
4911
4912 if (!adapter) {
4913 hdd_warn("adapter context is NULL");
4914 return -EINVAL;
4915 }
4916
4917 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
4918 status = wlan_hdd_validate_context(hdd_ctx);
4919 if (status)
4920 return -EINVAL;
4921
4922 if (!hdd_ctx->rcpi_enabled) {
4923 hdd_debug("RCPI not supported");
4924 return -EINVAL;
4925 }
4926
4927 if (!mac) {
4928 hdd_warn("RCPI peer mac-addr is NULL");
4929 return -EINVAL;
4930 }
4931
4932 qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE);
4933
4934 if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc))
4935 return -EINVAL;
4936 if (reassoc)
4937 return 0;
4938
4939 rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
4940 if (!rcpi_req) {
4941 hdd_err("unable to allocate memory for RCPI req");
4942 return -EINVAL;
4943 }
4944
4945 request = hdd_request_alloc(&params);
4946 if (!request) {
4947 hdd_err("Request allocation failure");
4948 qdf_mem_free(rcpi_req);
4949 return -ENOMEM;
4950 }
4951 cookie = hdd_request_cookie(request);
4952
4953 rcpi_req->mac_addr = mac_addr;
Jeff Johnson1b780e42017-10-31 14:11:45 -07004954 rcpi_req->session_id = adapter->session_id;
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05304955 rcpi_req->measurement_type = measurement_type;
4956 rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb;
4957 rcpi_req->rcpi_context = cookie;
4958
4959 qdf_status = sme_get_rcpi(hdd_ctx->hHal, rcpi_req);
4960 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
4961 hdd_err("Unable to retrieve RCPI");
4962 status = qdf_status_to_os_return(qdf_status);
4963 goto out;
4964 }
4965
4966 /* request was sent -- wait for the response */
4967 ret = hdd_request_wait_for_response(request);
4968 if (ret) {
4969 hdd_err("SME timed out while retrieving RCPI");
4970 status = -EINVAL;
4971 goto out;
4972 }
4973
4974 /* update the adapter with the fresh results */
4975 priv = hdd_request_priv(request);
4976 adapter->rcpi.mac_addr = priv->mac_addr;
4977 adapter->rcpi.rcpi = priv->rcpi;
4978 if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) {
4979 hdd_err("mis match of mac addr from call-back");
4980 status = -EINVAL;
4981 goto out;
4982 }
4983
4984 *rcpi_value = adapter->rcpi.rcpi;
4985 hdd_debug("RCPI = %d", *rcpi_value);
4986out:
4987 qdf_mem_free(rcpi_req);
4988 hdd_request_put(request);
4989
Dustin Browne74003f2018-03-14 12:51:58 -07004990 hdd_exit();
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05304991 return status;
4992}
4993
4994int wlan_hdd_get_rcpi(struct hdd_adapter *adapter, uint8_t *mac,
4995 int32_t *rcpi_value,
4996 enum rcpi_measurement_type measurement_type)
4997{
4998 int ret;
4999
5000 cds_ssr_protect(__func__);
5001 ret = __wlan_hdd_get_rcpi(adapter, mac, rcpi_value, measurement_type);
5002 cds_ssr_unprotect(__func__);
5003
5004 return ret;
5005}
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005006
Yu Wangc0b46f82018-03-09 16:04:15 +08005007#ifdef QCA_SUPPORT_CP_STATS
5008QDF_STATUS wlan_hdd_get_rssi(struct hdd_adapter *adapter, int8_t *rssi_value)
5009{
5010 int ret, i;
5011 struct hdd_station_ctx *sta_ctx;
5012 struct stats_event rssi_info;
5013
5014 if (NULL == adapter) {
5015 hdd_err("Invalid context, adapter");
5016 return QDF_STATUS_E_FAULT;
5017 }
5018 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
5019 hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
5020 cds_get_driver_state());
5021 /* return a cached value */
5022 *rssi_value = adapter->rssi;
5023 return QDF_STATUS_SUCCESS;
5024 }
5025
5026 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5027
5028 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
5029 hdd_debug("Not associated!, rssi on disconnect %d",
5030 adapter->rssi_on_disconnect);
5031 *rssi_value = adapter->rssi_on_disconnect;
5032 return QDF_STATUS_SUCCESS;
5033 }
5034
5035 if (sta_ctx->hdd_reassoc_scenario) {
5036 hdd_debug("Roaming in progress, return cached RSSI");
5037 *rssi_value = adapter->rssi;
5038 return QDF_STATUS_SUCCESS;
5039 }
5040
5041 ret = wlan_cfg80211_mc_cp_stats_get_peer_rssi(adapter->hdd_vdev,
5042 sta_ctx->conn_info.bssId.bytes,
5043 &rssi_info);
5044 if (ret) {
5045 hdd_err("Unable to retrieve peer rssi: %d", ret);
5046 wlan_cfg80211_mc_cp_stats_put_peer_rssi(&rssi_info);
5047 return ret;
5048 }
5049
5050 for (i = 0; i < rssi_info.num_peer_stats; i++) {
5051 if (!qdf_mem_cmp(rssi_info.peer_stats[i].peer_macaddr,
5052 sta_ctx->conn_info.bssId.bytes,
5053 WLAN_MACADDR_LEN)) {
5054 *rssi_value = rssi_info.peer_stats[i].peer_rssi;
5055 hdd_debug("RSSI = %d", *rssi_value);
5056 wlan_cfg80211_mc_cp_stats_put_peer_rssi(&rssi_info);
5057 return QDF_STATUS_SUCCESS;
5058 }
5059 }
5060
5061 wlan_cfg80211_mc_cp_stats_put_peer_rssi(&rssi_info);
5062 hdd_err("bss peer not present in returned result");
5063 return QDF_STATUS_E_FAULT;
5064}
5065#else /* QCA_SUPPORT_CP_STATS */
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005066struct rssi_priv {
5067 int8_t rssi;
5068};
5069
5070/**
5071 * hdd_get_rssi_cb() - "Get RSSI" callback function
5072 * @rssi: Current RSSI of the station
5073 * @sta_id: ID of the station
5074 * @context: opaque context originally passed to SME. HDD always passes
5075 * a cookie for the request context
5076 *
5077 * Return: None
5078 */
5079static void hdd_get_rssi_cb(int8_t rssi, uint32_t sta_id, void *context)
5080{
5081 struct hdd_request *request;
5082 struct rssi_priv *priv;
5083
5084 request = hdd_request_get(context);
5085 if (!request) {
5086 hdd_err("Obsolete request");
5087 return;
5088 }
5089
5090 priv = hdd_request_priv(request);
5091 priv->rssi = rssi;
5092 hdd_request_complete(request);
5093 hdd_request_put(request);
5094}
5095
5096QDF_STATUS wlan_hdd_get_rssi(struct hdd_adapter *adapter, int8_t *rssi_value)
5097{
5098 struct hdd_context *hdd_ctx;
5099 struct hdd_station_ctx *sta_ctx;
5100 QDF_STATUS hstatus;
5101 int ret;
5102 void *cookie;
5103 struct hdd_request *request;
5104 struct rssi_priv *priv;
5105 static const struct hdd_request_params params = {
5106 .priv_size = sizeof(*priv),
5107 .timeout_ms = WLAN_WAIT_TIME_STATS,
5108 };
5109
5110 if (NULL == adapter) {
5111 hdd_err("Invalid context, adapter");
5112 return QDF_STATUS_E_FAULT;
5113 }
5114 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
5115 hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
5116 cds_get_driver_state());
5117 /* return a cached value */
5118 *rssi_value = adapter->rssi;
5119 return QDF_STATUS_SUCCESS;
5120 }
5121
5122 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5123 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5124
5125 if (eConnectionState_Associated != sta_ctx->conn_info.connState) {
5126 hdd_debug("Not associated!, rssi on disconnect %d",
5127 adapter->rssi_on_disconnect);
5128 *rssi_value = adapter->rssi_on_disconnect;
5129 return QDF_STATUS_SUCCESS;
5130 }
5131
5132 if (sta_ctx->hdd_reassoc_scenario) {
5133 hdd_debug("Roaming in progress, return cached RSSI");
5134 *rssi_value = adapter->rssi;
5135 return QDF_STATUS_SUCCESS;
5136 }
5137
5138 request = hdd_request_alloc(&params);
5139 if (!request) {
5140 hdd_err("Request allocation failure, return cached RSSI");
5141 *rssi_value = adapter->rssi;
5142 return QDF_STATUS_SUCCESS;
5143 }
5144 cookie = hdd_request_cookie(request);
5145
5146 hstatus = sme_get_rssi(hdd_ctx->hHal, hdd_get_rssi_cb,
5147 sta_ctx->conn_info.staId[0],
5148 sta_ctx->conn_info.bssId, adapter->rssi,
5149 cookie);
5150 if (QDF_STATUS_SUCCESS != hstatus) {
5151 hdd_err("Unable to retrieve RSSI");
5152 /* we'll returned a cached value below */
5153 } else {
5154 /* request was sent -- wait for the response */
5155 ret = hdd_request_wait_for_response(request);
5156 if (ret) {
5157 hdd_warn("SME timed out while retrieving RSSI");
5158 /* we'll returned a cached value below */
5159 } else {
5160 /* update the adapter with the fresh results */
5161 priv = hdd_request_priv(request);
Paul Zhangb1f35df2018-04-16 12:19:01 +08005162
5163 adapter->rssi = priv->rssi;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005164
5165 /*
5166 * for new connection there might be no valid previous
5167 * RSSI.
5168 */
5169 if (!adapter->rssi) {
5170 hdd_get_rssi_snr_by_bssid(adapter,
5171 sta_ctx->conn_info.bssId.bytes,
5172 &adapter->rssi, NULL);
5173 }
5174 }
5175 }
5176
5177 /*
5178 * either we never sent a request, we sent a request and
5179 * received a response or we sent a request and timed out.
5180 * regardless we are done with the request.
5181 */
5182 hdd_request_put(request);
5183
5184 *rssi_value = adapter->rssi;
5185 hdd_debug("RSSI = %d", *rssi_value);
5186
5187 return QDF_STATUS_SUCCESS;
5188}
Yu Wangc0b46f82018-03-09 16:04:15 +08005189#endif /* QCA_SUPPORT_CP_STATS */
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005190
5191struct snr_priv {
5192 int8_t snr;
5193};
5194
5195/**
5196 * hdd_get_snr_cb() - "Get SNR" callback function
5197 * @snr: Current SNR of the station
5198 * @sta_id: ID of the station
5199 * @context: opaque context originally passed to SME. HDD always passes
5200 * a cookie for the request context
5201 *
5202 * Return: None
5203 */
5204static void hdd_get_snr_cb(int8_t snr, uint32_t sta_id, void *context)
5205{
5206 struct hdd_request *request;
5207 struct snr_priv *priv;
5208
5209 request = hdd_request_get(context);
5210 if (!request) {
5211 hdd_err("Obsolete request");
5212 return;
5213 }
5214
5215 /* propagate response back to requesting thread */
5216 priv = hdd_request_priv(request);
5217 priv->snr = snr;
5218 hdd_request_complete(request);
5219 hdd_request_put(request);
5220}
5221
5222QDF_STATUS wlan_hdd_get_snr(struct hdd_adapter *adapter, int8_t *snr)
5223{
5224 struct hdd_context *hdd_ctx;
5225 struct hdd_station_ctx *sta_ctx;
5226 QDF_STATUS hstatus;
5227 int valid;
5228 int ret;
5229 void *cookie;
5230 struct hdd_request *request;
5231 struct snr_priv *priv;
5232 static const struct hdd_request_params params = {
5233 .priv_size = sizeof(*priv),
5234 .timeout_ms = WLAN_WAIT_TIME_STATS,
5235 };
5236
5237 hdd_enter();
5238
5239 if (NULL == adapter) {
5240 hdd_err("Invalid context, adapter");
5241 return QDF_STATUS_E_FAULT;
5242 }
5243
5244 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5245
5246 valid = wlan_hdd_validate_context(hdd_ctx);
5247 if (0 != valid)
5248 return QDF_STATUS_E_FAULT;
5249
5250 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5251
5252 request = hdd_request_alloc(&params);
5253 if (!request) {
5254 hdd_err("Request allocation failure");
5255 return QDF_STATUS_E_FAULT;
5256 }
5257 cookie = hdd_request_cookie(request);
5258
5259 hstatus = sme_get_snr(hdd_ctx->hHal, hdd_get_snr_cb,
5260 sta_ctx->conn_info.staId[0],
5261 sta_ctx->conn_info.bssId, cookie);
5262 if (QDF_STATUS_SUCCESS != hstatus) {
5263 hdd_err("Unable to retrieve RSSI");
5264 /* we'll returned a cached value below */
5265 } else {
5266 /* request was sent -- wait for the response */
5267 ret = hdd_request_wait_for_response(request);
5268 if (ret) {
5269 hdd_err("SME timed out while retrieving SNR");
5270 /* we'll now returned a cached value below */
5271 } else {
5272 /* update the adapter with the fresh results */
5273 priv = hdd_request_priv(request);
5274 adapter->snr = priv->snr;
5275 }
5276 }
5277
5278 /*
5279 * either we never sent a request, we sent a request and
5280 * received a response or we sent a request and timed out.
5281 * regardless we are done with the request.
5282 */
5283 hdd_request_put(request);
5284
5285 *snr = adapter->snr;
5286 hdd_exit();
5287 return QDF_STATUS_SUCCESS;
5288}
5289
5290struct linkspeed_priv {
5291 tSirLinkSpeedInfo linkspeed_info;
5292};
5293
5294static void
5295hdd_get_link_speed_cb(tSirLinkSpeedInfo *linkspeed_info, void *context)
5296{
5297 struct hdd_request *request;
5298 struct linkspeed_priv *priv;
5299
5300 if (!linkspeed_info) {
5301 hdd_err("NULL linkspeed");
5302 return;
5303 }
5304
5305 request = hdd_request_get(context);
5306 if (!request) {
5307 hdd_err("Obsolete request");
5308 return;
5309 }
5310
5311 priv = hdd_request_priv(request);
5312 priv->linkspeed_info = *linkspeed_info;
5313 hdd_request_complete(request);
5314 hdd_request_put(request);
5315}
5316
5317int wlan_hdd_get_linkspeed_for_peermac(struct hdd_adapter *adapter,
5318 struct qdf_mac_addr *mac_address,
5319 uint32_t *linkspeed)
5320{
5321 int ret;
5322 QDF_STATUS status;
5323 void *cookie;
5324 tSirLinkSpeedInfo *linkspeed_info;
5325 struct hdd_request *request;
5326 struct linkspeed_priv *priv;
5327 static const struct hdd_request_params params = {
5328 .priv_size = sizeof(*priv),
5329 .timeout_ms = WLAN_WAIT_TIME_STATS,
5330 };
5331
5332 if ((!adapter) || (!linkspeed)) {
5333 hdd_err("NULL argument");
5334 return -EINVAL;
5335 }
5336
5337 request = hdd_request_alloc(&params);
5338 if (!request) {
5339 hdd_err("Request allocation failure");
5340 ret = -ENOMEM;
5341 goto return_cached_value;
5342 }
5343
5344 cookie = hdd_request_cookie(request);
5345 priv = hdd_request_priv(request);
5346
5347 linkspeed_info = &priv->linkspeed_info;
5348 qdf_copy_macaddr(&linkspeed_info->peer_macaddr, mac_address);
5349 status = sme_get_link_speed(WLAN_HDD_GET_HAL_CTX(adapter),
5350 linkspeed_info,
5351 cookie, hdd_get_link_speed_cb);
5352 if (QDF_IS_STATUS_ERROR(status)) {
5353 hdd_err("Unable to retrieve statistics for link speed");
5354 ret = qdf_status_to_os_return(status);
5355 goto cleanup;
5356 }
5357 ret = hdd_request_wait_for_response(request);
5358 if (ret) {
5359 hdd_err("SME timed out while retrieving link speed");
5360 goto cleanup;
5361 }
5362 adapter->estimated_linkspeed = linkspeed_info->estLinkSpeed;
5363
5364cleanup:
5365 /*
5366 * either we never sent a request, we sent a request and
5367 * received a response or we sent a request and timed out.
5368 * regardless we are done with the request.
5369 */
5370 hdd_request_put(request);
5371
5372return_cached_value:
5373 *linkspeed = adapter->estimated_linkspeed;
5374
5375 return ret;
5376}
5377
5378int wlan_hdd_get_link_speed(struct hdd_adapter *adapter, uint32_t *link_speed)
5379{
5380 struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter);
5381 struct hdd_station_ctx *hdd_stactx =
5382 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5383 int ret;
5384
5385 ret = wlan_hdd_validate_context(hddctx);
5386 if (ret)
5387 return ret;
5388
5389 /* Linkspeed is allowed only for P2P mode */
5390 if (adapter->device_mode != QDF_P2P_CLIENT_MODE) {
5391 hdd_err("Link Speed is not allowed in Device mode %s(%d)",
5392 hdd_device_mode_to_string(adapter->device_mode),
5393 adapter->device_mode);
5394 return -ENOTSUPP;
5395 }
5396
5397 if (eConnectionState_Associated != hdd_stactx->conn_info.connState) {
5398 /* we are not connected so we don't have a classAstats */
5399 *link_speed = 0;
5400 } else {
5401 struct qdf_mac_addr bssid;
5402
5403 qdf_copy_macaddr(&bssid, &hdd_stactx->conn_info.bssId);
5404
5405 ret = wlan_hdd_get_linkspeed_for_peermac(adapter, &bssid,
5406 link_speed);
5407 if (ret) {
5408 hdd_err("Unable to retrieve SME linkspeed");
5409 return ret;
5410 }
5411 /* linkspeed in units of 500 kbps */
5412 *link_speed = (*link_speed) / 500;
5413 }
5414 return 0;
5415}
5416
5417struct peer_rssi_priv {
5418 struct sir_peer_sta_info peer_sta_info;
5419};
5420
5421/**
5422 * hdd_get_peer_rssi_cb() - get peer station's rssi callback
5423 * @sta_rssi: pointer of peer information
5424 * @context: get rssi callback context
5425 *
5426 * This function will fill rssi information to rssi priv
5427 * adapter
5428 *
5429 */
5430static void hdd_get_peer_rssi_cb(struct sir_peer_info_resp *sta_rssi,
5431 void *context)
5432{
5433 struct hdd_request *request;
5434 struct peer_rssi_priv *priv;
5435 struct sir_peer_info *rssi_info;
5436 uint8_t peer_num;
5437
5438 if ((!sta_rssi)) {
5439 hdd_err("Bad param, sta_rssi [%pK]", sta_rssi);
5440 return;
5441 }
5442
5443 request = hdd_request_get(context);
5444 if (!request) {
5445 hdd_err("Obsolete request");
5446 return;
5447 }
5448
5449 priv = hdd_request_priv(request);
5450
5451 peer_num = sta_rssi->count;
5452 rssi_info = sta_rssi->info;
5453
5454 hdd_debug("%d peers", peer_num);
5455
5456 if (peer_num > MAX_PEER_STA) {
5457 hdd_warn("Exceed max peer sta to handle one time %d", peer_num);
5458 peer_num = MAX_PEER_STA;
5459 }
5460
5461 qdf_mem_copy(priv->peer_sta_info.info, rssi_info,
5462 peer_num * sizeof(*rssi_info));
5463 priv->peer_sta_info.sta_num = peer_num;
5464
5465 hdd_request_complete(request);
5466 hdd_request_put(request);
5467
5468}
5469
5470int wlan_hdd_get_peer_rssi(struct hdd_adapter *adapter,
5471 struct qdf_mac_addr *macaddress,
5472 struct sir_peer_sta_info *peer_sta_info)
5473{
5474 QDF_STATUS status;
5475 void *cookie;
5476 int ret;
5477 struct sir_peer_info_req rssi_req;
5478 struct hdd_request *request;
5479 struct peer_rssi_priv *priv;
5480 static const struct hdd_request_params params = {
5481 .priv_size = sizeof(*priv),
5482 .timeout_ms = WLAN_WAIT_TIME_STATS,
5483 };
5484
5485 if (!adapter || !macaddress || !peer_sta_info) {
5486 hdd_err("adapter [%pK], macaddress [%pK], peer_sta_info[%pK]",
5487 adapter, macaddress, peer_sta_info);
5488 return -EFAULT;
5489 }
5490
5491 request = hdd_request_alloc(&params);
5492 if (!request) {
5493 hdd_err("Request allocation failure");
5494 return -ENOMEM;
5495 }
5496
5497 cookie = hdd_request_cookie(request);
5498 priv = hdd_request_priv(request);
5499
5500 qdf_mem_copy(&rssi_req.peer_macaddr, macaddress,
5501 QDF_MAC_ADDR_SIZE);
5502 rssi_req.sessionid = adapter->session_id;
5503 status = sme_get_peer_info(WLAN_HDD_GET_HAL_CTX(adapter),
5504 rssi_req,
5505 cookie,
5506 hdd_get_peer_rssi_cb);
5507 if (status != QDF_STATUS_SUCCESS) {
5508 hdd_err("Unable to retrieve statistics for rssi");
5509 ret = -EFAULT;
5510 } else {
5511 ret = hdd_request_wait_for_response(request);
5512 if (ret) {
5513 hdd_err("SME timed out while retrieving rssi");
5514 ret = -EFAULT;
5515 } else {
5516 *peer_sta_info = priv->peer_sta_info;
5517 ret = 0;
5518 }
5519 }
5520
5521 hdd_request_put(request);
5522
5523 return ret;
5524}
5525
5526struct peer_info_priv {
5527 struct sir_peer_sta_ext_info peer_sta_ext_info;
5528};
5529
5530/**
5531 * wlan_hdd_get_peer_info_cb() - get peer info callback
5532 * @sta_info: pointer of peer information
5533 * @context: get peer info callback context
5534 *
5535 * This function will fill stats info to peer info priv
5536 *
5537 */
5538static void wlan_hdd_get_peer_info_cb(struct sir_peer_info_ext_resp *sta_info,
5539 void *context)
5540{
5541 struct hdd_request *request;
5542 struct peer_info_priv *priv;
5543 uint8_t sta_num;
5544
5545 if ((!sta_info) || (!context)) {
5546 hdd_err("Bad param, sta_info [%pK] context [%pK]",
5547 sta_info, context);
5548 return;
5549 }
5550
5551 if (!sta_info->count) {
5552 hdd_err("Fail to get remote peer info");
5553 return;
5554 }
5555
5556 if (sta_info->count > MAX_PEER_STA) {
5557 hdd_warn("Exceed max peer number %d", sta_info->count);
5558 sta_num = MAX_PEER_STA;
5559 } else {
5560 sta_num = sta_info->count;
5561 }
5562
5563 request = hdd_request_get(context);
5564 if (!request) {
5565 hdd_err("Obsolete request");
5566 return;
5567 }
5568
5569 priv = hdd_request_priv(request);
5570
5571 priv->peer_sta_ext_info.sta_num = sta_num;
5572 qdf_mem_copy(&priv->peer_sta_ext_info.info,
5573 sta_info->info,
5574 sta_num * sizeof(sta_info->info[0]));
5575
5576 hdd_request_complete(request);
5577 hdd_request_put(request);
5578}
5579
5580int wlan_hdd_get_peer_info(struct hdd_adapter *adapter,
5581 struct qdf_mac_addr macaddress,
5582 struct sir_peer_info_ext *peer_info_ext)
5583{
5584 QDF_STATUS status;
5585 void *cookie;
5586 int ret;
5587 struct sir_peer_info_ext_req peer_info_req;
5588 struct hdd_request *request;
5589 struct peer_info_priv *priv;
5590 static const struct hdd_request_params params = {
5591 .priv_size = sizeof(*priv),
5592 .timeout_ms = WLAN_WAIT_TIME_STATS,
5593 };
5594
5595 if (!adapter) {
5596 hdd_err("adapter is NULL");
5597 return -EFAULT;
5598 }
5599
5600 request = hdd_request_alloc(&params);
5601 if (!request) {
5602 hdd_err("Request allocation failure");
5603 return -ENOMEM;
5604 }
5605
5606 cookie = hdd_request_cookie(request);
5607 priv = hdd_request_priv(request);
5608
5609 qdf_mem_copy(&peer_info_req.peer_macaddr, &macaddress,
5610 QDF_MAC_ADDR_SIZE);
5611 peer_info_req.sessionid = adapter->session_id;
5612 peer_info_req.reset_after_request = 0;
5613 status = sme_get_peer_info_ext(WLAN_HDD_GET_HAL_CTX(adapter),
5614 &peer_info_req,
5615 cookie,
5616 wlan_hdd_get_peer_info_cb);
5617 if (status != QDF_STATUS_SUCCESS) {
5618 hdd_err("Unable to retrieve statistics for peer info");
5619 ret = -EFAULT;
5620 } else {
5621 ret = hdd_request_wait_for_response(request);
5622 if (ret) {
5623 hdd_err("SME timed out while retrieving peer info");
5624 ret = -EFAULT;
5625 } else {
5626 /* only support one peer by now */
5627 *peer_info_ext = priv->peer_sta_ext_info.info[0];
5628 ret = 0;
5629 }
5630 }
5631
5632 hdd_request_put(request);
5633
5634 return ret;
5635}
5636
Naveen Rawate8b1b822018-01-30 09:46:16 -08005637#ifndef QCA_SUPPORT_CP_STATS
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005638struct class_a_stats {
5639 tCsrGlobalClassAStatsInfo class_a_stats;
5640};
5641
5642/**
5643 * hdd_get_class_a_statistics_cb() - Get Class A stats callback function
5644 * @stats: pointer to Class A stats
5645 * @context: user context originally registered with SME (always the
5646 * cookie from the request context)
5647 *
5648 * Return: None
5649 */
5650static void hdd_get_class_a_statistics_cb(void *stats, void *context)
5651{
5652 struct hdd_request *request;
5653 struct class_a_stats *priv;
5654 tCsrGlobalClassAStatsInfo *returned_stats;
5655
5656 hdd_enter();
Ashish Kumar Dhanotiya5e138ea2018-05-18 19:59:07 +05305657 if (NULL == stats) {
5658 hdd_err("Bad param, stats");
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005659 return;
5660 }
5661
5662 request = hdd_request_get(context);
5663 if (!request) {
5664 hdd_err("Obsolete request");
5665 return;
5666 }
5667
5668 returned_stats = stats;
5669 priv = hdd_request_priv(request);
5670 priv->class_a_stats = *returned_stats;
5671 hdd_request_complete(request);
5672 hdd_request_put(request);
5673 hdd_exit();
5674}
5675
5676QDF_STATUS wlan_hdd_get_class_astats(struct hdd_adapter *adapter)
5677{
5678 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5679 QDF_STATUS hstatus;
5680 int ret;
5681 void *cookie;
5682 struct hdd_request *request;
5683 struct class_a_stats *priv;
5684 static const struct hdd_request_params params = {
5685 .priv_size = sizeof(*priv),
5686 .timeout_ms = WLAN_WAIT_TIME_STATS,
5687 };
5688
5689 if (NULL == adapter) {
5690 hdd_err("adapter is NULL");
5691 return QDF_STATUS_E_FAULT;
5692 }
5693 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
5694 hdd_debug("Recovery in Progress. State: 0x%x Ignore!!!",
5695 cds_get_driver_state());
5696 return QDF_STATUS_SUCCESS;
5697 }
5698
5699 request = hdd_request_alloc(&params);
5700 if (!request) {
5701 hdd_err("Request allocation failure");
5702 return QDF_STATUS_E_NOMEM;
5703 }
5704 cookie = hdd_request_cookie(request);
5705
5706 /* query only for Class A statistics (which include link speed) */
5707 hstatus = sme_get_statistics(WLAN_HDD_GET_HAL_CTX(adapter),
5708 eCSR_HDD, SME_GLOBAL_CLASSA_STATS,
5709 hdd_get_class_a_statistics_cb,
5710 sta_ctx->conn_info.staId[0],
5711 cookie, adapter->session_id);
5712 if (QDF_STATUS_SUCCESS != hstatus) {
5713 hdd_warn("Unable to retrieve Class A statistics");
5714 goto return_cached_results;
5715 }
5716
5717 /* request was sent -- wait for the response */
5718 ret = hdd_request_wait_for_response(request);
5719 if (ret) {
5720 hdd_warn("SME timed out while retrieving Class A statistics");
5721 goto return_cached_results;
5722 }
5723
5724 /* update the adapter with the fresh results */
5725 priv = hdd_request_priv(request);
5726 adapter->hdd_stats.class_a_stat = priv->class_a_stats;
5727
5728return_cached_results:
5729 /*
5730 * either we never sent a request, we sent a request and
5731 * received a response or we sent a request and timed out.
5732 * regardless we are done with the request.
5733 */
5734 hdd_request_put(request);
5735
5736 return QDF_STATUS_SUCCESS;
5737}
Naveen Rawate8b1b822018-01-30 09:46:16 -08005738#endif
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005739
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005740#ifdef QCA_SUPPORT_CP_STATS
5741int wlan_hdd_get_station_stats(struct hdd_adapter *adapter)
5742{
5743 int ret;
5744 uint8_t mcs_rate_flags;
5745 struct stats_event stats = {0};
5746
5747 ret = wlan_cfg80211_mc_cp_stats_get_station_stats(adapter->hdd_vdev,
5748 &stats);
5749
5750 if (!stats.vdev_summary_stats || !stats.vdev_chain_rssi) {
5751 hdd_err("summary_stats: %pK, chain_rssi: %pK",
5752 stats.vdev_summary_stats, stats.vdev_chain_rssi);
5753 return -EINVAL;
5754 }
5755
5756 /* save summary stats to legacy location */
5757 qdf_mem_copy(adapter->hdd_stats.summary_stat.retry_cnt,
5758 stats.vdev_summary_stats[0].stats.retry_cnt,
5759 sizeof(adapter->hdd_stats.summary_stat.retry_cnt));
5760 qdf_mem_copy(adapter->hdd_stats.summary_stat.multiple_retry_cnt,
5761 stats.vdev_summary_stats[0].stats.multiple_retry_cnt,
5762 sizeof(adapter->hdd_stats.summary_stat.multiple_retry_cnt));
5763 qdf_mem_copy(adapter->hdd_stats.summary_stat.tx_frm_cnt,
5764 stats.vdev_summary_stats[0].stats.tx_frm_cnt,
5765 sizeof(adapter->hdd_stats.summary_stat.tx_frm_cnt));
5766 qdf_mem_copy(adapter->hdd_stats.summary_stat.fail_cnt,
5767 stats.vdev_summary_stats[0].stats.fail_cnt,
5768 sizeof(adapter->hdd_stats.summary_stat.fail_cnt));
5769 adapter->hdd_stats.summary_stat.snr =
5770 stats.vdev_summary_stats[0].stats.snr;
5771 adapter->hdd_stats.summary_stat.rssi =
5772 stats.vdev_summary_stats[0].stats.rssi;
5773 adapter->hdd_stats.summary_stat.rx_frm_cnt =
5774 stats.vdev_summary_stats[0].stats.rx_frm_cnt;
5775 adapter->hdd_stats.summary_stat.frm_dup_cnt =
5776 stats.vdev_summary_stats[0].stats.frm_dup_cnt;
5777 adapter->hdd_stats.summary_stat.rts_fail_cnt =
5778 stats.vdev_summary_stats[0].stats.rts_fail_cnt;
5779 adapter->hdd_stats.summary_stat.ack_fail_cnt =
5780 stats.vdev_summary_stats[0].stats.ack_fail_cnt;
5781 adapter->hdd_stats.summary_stat.rts_succ_cnt =
5782 stats.vdev_summary_stats[0].stats.rts_succ_cnt;
5783 adapter->hdd_stats.summary_stat.rx_discard_cnt =
5784 stats.vdev_summary_stats[0].stats.rx_discard_cnt;
5785 adapter->hdd_stats.summary_stat.rx_error_cnt =
5786 stats.vdev_summary_stats[0].stats.rx_error_cnt;
5787
5788 /* save class a stats to legacy location */
5789 adapter->hdd_stats.class_a_stat.nss =
5790 wlan_vdev_mlme_get_nss(adapter->hdd_vdev);
5791 adapter->hdd_stats.class_a_stat.tx_rate = stats.tx_rate;
5792 adapter->hdd_stats.class_a_stat.tx_rate_flags = stats.tx_rate_flags;
5793 adapter->hdd_stats.class_a_stat.mcs_index =
5794 sme_get_mcs_idx(stats.tx_rate * 5, stats.tx_rate_flags,
5795 adapter->hdd_stats.class_a_stat.nss, &mcs_rate_flags);
5796 adapter->hdd_stats.class_a_stat.mcs_rate_flags = mcs_rate_flags;
5797
5798 /* save per chain rssi to legacy location */
5799 qdf_mem_copy(adapter->hdd_stats.per_chain_rssi_stats.rssi,
5800 stats.vdev_chain_rssi[0].chain_rssi,
5801 sizeof(stats.vdev_chain_rssi[0].chain_rssi));
5802
5803 wlan_cfg80211_mc_cp_stats_put_station_stats(&stats);
5804 return ret;
5805}
5806#else /* QCA_SUPPORT_CP_STATS */
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005807struct station_stats {
5808 tCsrSummaryStatsInfo summary_stats;
5809 tCsrGlobalClassAStatsInfo class_a_stats;
5810 struct csr_per_chain_rssi_stats_info per_chain_rssi_stats;
5811};
5812
5813/**
5814 * hdd_get_station_statistics_cb() - Get stats callback function
5815 * @stats: pointer to combined station stats
5816 * @context: user context originally registered with SME (always the
5817 * cookie from the request context)
5818 *
5819 * Return: None
5820 */
5821static void hdd_get_station_statistics_cb(void *stats, void *context)
5822{
5823 struct hdd_request *request;
5824 struct station_stats *priv;
5825 tCsrSummaryStatsInfo *summary_stats;
5826 tCsrGlobalClassAStatsInfo *class_a_stats;
5827 struct csr_per_chain_rssi_stats_info *per_chain_rssi_stats;
5828
5829 if ((NULL == stats) || (NULL == context)) {
5830 hdd_err("Bad param, pStats [%pK] pContext [%pK]",
5831 stats, context);
5832 return;
5833 }
5834
5835 request = hdd_request_get(context);
5836 if (!request) {
5837 hdd_err("Obsolete request");
5838 return;
5839 }
5840
5841 summary_stats = (tCsrSummaryStatsInfo *) stats;
5842 class_a_stats = (tCsrGlobalClassAStatsInfo *) (summary_stats + 1);
5843 per_chain_rssi_stats = (struct csr_per_chain_rssi_stats_info *)
5844 (class_a_stats + 1);
5845 priv = hdd_request_priv(request);
5846
5847 /* copy over the stats. do so as a struct copy */
5848 priv->summary_stats = *summary_stats;
5849 priv->class_a_stats = *class_a_stats;
5850 priv->per_chain_rssi_stats = *per_chain_rssi_stats;
5851
5852 hdd_request_complete(request);
5853 hdd_request_put(request);
5854}
5855
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005856int wlan_hdd_get_station_stats(struct hdd_adapter *adapter)
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005857{
5858 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5859 QDF_STATUS status;
5860 int errno;
5861 void *cookie;
5862 struct hdd_request *request;
5863 struct station_stats *priv;
5864 static const struct hdd_request_params params = {
5865 .priv_size = sizeof(*priv),
5866 .timeout_ms = WLAN_WAIT_TIME_STATS,
5867 };
5868
5869 if (NULL == adapter) {
5870 hdd_err("adapter is NULL");
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005871 return 0;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005872 }
5873
5874 request = hdd_request_alloc(&params);
5875 if (!request) {
5876 hdd_err("Request allocation failure");
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005877 return -ENOMEM;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005878 }
5879 cookie = hdd_request_cookie(request);
5880
5881 /* query only for Summary & Class A statistics */
5882 status = sme_get_statistics(WLAN_HDD_GET_HAL_CTX(adapter),
5883 eCSR_HDD,
5884 SME_SUMMARY_STATS |
5885 SME_GLOBAL_CLASSA_STATS |
5886 SME_PER_CHAIN_RSSI_STATS,
5887 hdd_get_station_statistics_cb,
5888 sta_ctx->conn_info.staId[0],
5889 cookie,
5890 adapter->session_id);
5891 if (QDF_IS_STATUS_ERROR(status)) {
5892 hdd_err("Failed to retrieve statistics, status %d", status);
5893 goto put_request;
5894 }
5895
5896 /* request was sent -- wait for the response */
5897 errno = hdd_request_wait_for_response(request);
5898 if (errno) {
5899 hdd_err("Failed to wait for statistics, errno %d", errno);
5900 goto put_request;
5901 }
5902
5903 /* update the adapter with the fresh results */
5904 priv = hdd_request_priv(request);
5905 adapter->hdd_stats.summary_stat = priv->summary_stats;
5906 adapter->hdd_stats.class_a_stat = priv->class_a_stats;
5907 adapter->hdd_stats.per_chain_rssi_stats = priv->per_chain_rssi_stats;
5908
5909put_request:
5910 /*
5911 * either we never sent a request, we sent a request and
5912 * received a response or we sent a request and timed out.
5913 * regardless we are done with the request.
5914 */
5915 hdd_request_put(request);
5916
5917 /* either callback updated adapter stats or it has cached data */
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005918 return 0;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005919}
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005920#endif /* QCA_SUPPORT_CP_STATS */
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005921
5922struct temperature_priv {
5923 int temperature;
5924};
5925
5926/**
5927 * hdd_get_temperature_cb() - "Get Temperature" callback function
5928 * @temperature: measured temperature
5929 * @context: callback context
5930 *
5931 * This function is passed to sme_get_temperature() as the callback
5932 * function to be invoked when the temperature measurement is
5933 * available.
5934 *
5935 * Return: None
5936 */
5937static void hdd_get_temperature_cb(int temperature, void *context)
5938{
5939 struct hdd_request *request;
5940 struct temperature_priv *priv;
5941
5942 hdd_enter();
5943
5944 request = hdd_request_get(context);
5945 if (!request) {
5946 hdd_err("Obsolete request");
5947 return;
5948 }
5949
5950 priv = hdd_request_priv(request);
5951 priv->temperature = temperature;
5952 hdd_request_complete(request);
5953 hdd_request_put(request);
5954 hdd_exit();
5955}
5956
5957int wlan_hdd_get_temperature(struct hdd_adapter *adapter, int *temperature)
5958{
5959 QDF_STATUS status;
5960 int ret;
5961 void *cookie;
5962 struct hdd_request *request;
5963 struct temperature_priv *priv;
5964 static const struct hdd_request_params params = {
5965 .priv_size = sizeof(*priv),
5966 .timeout_ms = WLAN_WAIT_TIME_STATS,
5967 };
5968
5969 hdd_enter();
5970 if (NULL == adapter) {
5971 hdd_err("adapter is NULL");
5972 return -EPERM;
5973 }
5974
5975 request = hdd_request_alloc(&params);
5976 if (!request) {
5977 hdd_err("Request allocation failure");
5978 return -ENOMEM;
5979 }
5980 cookie = hdd_request_cookie(request);
5981 status = sme_get_temperature(WLAN_HDD_GET_HAL_CTX(adapter),
5982 cookie, hdd_get_temperature_cb);
5983 if (QDF_STATUS_SUCCESS != status) {
5984 hdd_err("Unable to retrieve temperature");
5985 } else {
5986 ret = hdd_request_wait_for_response(request);
5987 if (ret) {
5988 hdd_err("SME timed out while retrieving temperature");
5989 } else {
5990 /* update the adapter with the fresh results */
5991 priv = hdd_request_priv(request);
5992 if (priv->temperature)
5993 adapter->temperature = priv->temperature;
5994 }
5995 }
5996
5997 /*
5998 * either we never sent a request, we sent a request and
5999 * received a response or we sent a request and timed out.
6000 * regardless we are done with the request.
6001 */
6002 hdd_request_put(request);
6003
6004 *temperature = adapter->temperature;
6005 hdd_exit();
6006 return 0;
6007}