blob: 618cc3d4201f6eb3594968ab5ba4693f198d1109 [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 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/**
23 * DOC : wlan_hdd_stats.c
24 *
25 * WLAN Host Device Driver statistics related implementation
26 *
27 */
28
29#include "wlan_hdd_stats.h"
30#include "sme_api.h"
31#include "cds_sched.h"
32#include "wlan_hdd_trace.h"
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070033#include "wlan_hdd_lpass.h"
Nirav Shahbf1b0332016-05-25 14:27:39 +053034#include "hif.h"
Sandeep Puligillafdd201e2017-02-02 18:43:46 -080035#include <qca_vendor.h>
Zhang Qian4ead8f02017-03-27 14:21:47 +080036#include "wma_api.h"
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +053037#include "wlan_hdd_hostapd.h"
38#include "wlan_hdd_request_manager.h"
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -080039#include "wlan_hdd_debugfs_llstat.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080040
41/* 11B, 11G Rate table include Basic rate and Extended rate
42 * The IDX field is the rate index
43 * The HI field is the rate when RSSI is strong or being ignored
44 * (in this case we report actual rate)
45 * The MID field is the rate when RSSI is moderate
46 * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
47 * The LO field is the rate when RSSI is low
48 * (in this case we don't report rates, actual current rate used)
49 */
Will Huang496b36c2017-07-11 16:38:50 +080050static const struct index_data_rate_type supported_data_rate[] = {
51 /* IDX HI HM LM LO (RSSI-based index */
52 {2, { 10, 10, 10, 0} },
53 {4, { 20, 20, 10, 0} },
54 {11, { 55, 20, 10, 0} },
55 {12, { 60, 55, 20, 0} },
56 {18, { 90, 55, 20, 0} },
57 {22, {110, 55, 20, 0} },
58 {24, {120, 90, 60, 0} },
59 {36, {180, 120, 60, 0} },
60 {44, {220, 180, 60, 0} },
61 {48, {240, 180, 90, 0} },
62 {66, {330, 180, 90, 0} },
63 {72, {360, 240, 90, 0} },
64 {96, {480, 240, 120, 0} },
65 {108, {540, 240, 120, 0} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080066};
67/* MCS Based rate table HT MCS parameters with Nss = 1 */
68static struct index_data_rate_type supported_mcs_rate_nss1[] = {
69/* MCS L20 L40 S20 S40 */
70 {0, {65, 135, 72, 150} },
71 {1, {130, 270, 144, 300} },
72 {2, {195, 405, 217, 450} },
73 {3, {260, 540, 289, 600} },
74 {4, {390, 810, 433, 900} },
75 {5, {520, 1080, 578, 1200} },
76 {6, {585, 1215, 650, 1350} },
77 {7, {650, 1350, 722, 1500} }
78};
79
80/* HT MCS parameters with Nss = 2 */
81static struct index_data_rate_type supported_mcs_rate_nss2[] = {
82/* MCS L20 L40 S20 S40 */
83 {0, {130, 270, 144, 300} },
84 {1, {260, 540, 289, 600} },
85 {2, {390, 810, 433, 900} },
86 {3, {520, 1080, 578, 1200} },
87 {4, {780, 1620, 867, 1800} },
88 {5, {1040, 2160, 1156, 2400} },
89 {6, {1170, 2430, 1300, 2700} },
90 {7, {1300, 2700, 1444, 3000} }
91};
92
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080093/* MCS Based VHT rate table MCS parameters with Nss = 1*/
94static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
95/* MCS L80 S80 L40 S40 L20 S40*/
96 {0, {293, 325}, {135, 150}, {65, 72} },
97 {1, {585, 650}, {270, 300}, {130, 144} },
98 {2, {878, 975}, {405, 450}, {195, 217} },
99 {3, {1170, 1300}, {540, 600}, {260, 289} },
100 {4, {1755, 1950}, {810, 900}, {390, 433} },
101 {5, {2340, 2600}, {1080, 1200}, {520, 578} },
102 {6, {2633, 2925}, {1215, 1350}, {585, 650} },
103 {7, {2925, 3250}, {1350, 1500}, {650, 722} },
104 {8, {3510, 3900}, {1620, 1800}, {780, 867} },
105 {9, {3900, 4333}, {1800, 2000}, {780, 867} }
106};
107
108/*MCS parameters with Nss = 2*/
109static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
110/* MCS L80 S80 L40 S40 L20 S40*/
111 {0, {585, 650}, {270, 300}, {130, 144} },
112 {1, {1170, 1300}, {540, 600}, {260, 289} },
113 {2, {1755, 1950}, {810, 900}, {390, 433} },
114 {3, {2340, 2600}, {1080, 1200}, {520, 578} },
115 {4, {3510, 3900}, {1620, 1800}, {780, 867} },
116 {5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
117 {6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
118 {7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
119 {8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
120 {9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
121};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800122
123/*array index ponints to MCS and array value points respective rssi*/
124static int rssi_mcs_tbl[][10] = {
125/*MCS 0 1 2 3 4 5 6 7 8 9*/
126 {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */
127 {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */
128 {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */
129};
130
131
132#ifdef WLAN_FEATURE_LINK_LAYER_STATS
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800133static struct hdd_ll_stats_context ll_stats_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800134
135/**
136 * put_wifi_rate_stat() - put wifi rate stats
137 * @stats: Pointer to stats context
138 * @vendor_event: Pointer to vendor event
139 *
140 * Return: bool
141 */
142static bool put_wifi_rate_stat(tpSirWifiRateStat stats,
143 struct sk_buff *vendor_event)
144{
145 if (nla_put_u8(vendor_event,
146 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
147 stats->rate.preamble) ||
148 nla_put_u8(vendor_event,
149 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
150 stats->rate.nss) ||
151 nla_put_u8(vendor_event,
152 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
153 stats->rate.bw) ||
154 nla_put_u8(vendor_event,
155 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
156 stats->rate.rateMcsIdx) ||
157 nla_put_u32(vendor_event,
158 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
159 stats->rate.bitrate) ||
160 nla_put_u32(vendor_event,
161 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
162 stats->txMpdu) ||
163 nla_put_u32(vendor_event,
164 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
165 stats->rxMpdu) ||
166 nla_put_u32(vendor_event,
167 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
168 stats->mpduLost) ||
169 nla_put_u32(vendor_event,
170 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
171 stats->retries) ||
172 nla_put_u32(vendor_event,
173 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
174 stats->retriesShort) ||
175 nla_put_u32(vendor_event,
176 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
177 stats->retriesLong)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700178 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800179 return false;
180 }
181
182 return true;
183}
184
185/**
186 * put_wifi_peer_info() - put wifi peer info
187 * @stats: Pointer to stats context
188 * @vendor_event: Pointer to vendor event
189 *
190 * Return: bool
191 */
192static bool put_wifi_peer_info(tpSirWifiPeerInfo stats,
193 struct sk_buff *vendor_event)
194{
195 u32 i = 0;
196 tpSirWifiRateStat pRateStats;
197
198 if (nla_put_u32
199 (vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
Dustin Brown877a5a92016-11-17 13:56:52 -0800200 wmi_to_sir_peer_type(stats->type)) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800201 nla_put(vendor_event,
202 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530203 QDF_MAC_ADDR_SIZE, &stats->peerMacAddress.bytes[0]) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800204 nla_put_u32(vendor_event,
205 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
206 stats->capabilities) ||
207 nla_put_u32(vendor_event,
208 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
209 stats->numRate)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700210 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211 goto error;
212 }
213
214 if (stats->numRate) {
215 struct nlattr *rateInfo;
216 struct nlattr *rates;
217
218 rateInfo = nla_nest_start(vendor_event,
219 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO);
220 if (rateInfo == NULL)
221 goto error;
222
223 for (i = 0; i < stats->numRate; i++) {
224 pRateStats = (tpSirWifiRateStat) ((uint8_t *)
225 stats->rateStats +
226 (i *
227 sizeof
228 (tSirWifiRateStat)));
229 rates = nla_nest_start(vendor_event, i);
230 if (rates == NULL)
231 goto error;
232
233 if (false ==
234 put_wifi_rate_stat(pRateStats, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700235 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800236 return false;
237 }
238 nla_nest_end(vendor_event, rates);
239 }
240 nla_nest_end(vendor_event, rateInfo);
241 }
242
243 return true;
244error:
245 return false;
246}
247
248/**
249 * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
250 * @stats: Pointer to stats context
251 * @vendor_event: Pointer to vendor event
252 *
253 * Return: bool
254 */
255static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats,
256 struct sk_buff *vendor_event)
257{
258 if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
259 stats->ac) ||
260 nla_put_u32(vendor_event,
261 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
262 stats->txMpdu) ||
263 nla_put_u32(vendor_event,
264 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
265 stats->rxMpdu) ||
266 nla_put_u32(vendor_event,
267 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
268 stats->txMcast) ||
269 nla_put_u32(vendor_event,
270 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
271 stats->rxMcast) ||
272 nla_put_u32(vendor_event,
273 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
274 stats->rxAmpdu) ||
275 nla_put_u32(vendor_event,
276 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
277 stats->txAmpdu) ||
278 nla_put_u32(vendor_event,
279 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
280 stats->mpduLost) ||
281 nla_put_u32(vendor_event,
282 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
283 stats->retries) ||
284 nla_put_u32(vendor_event,
285 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
286 stats->retriesShort) ||
287 nla_put_u32(vendor_event,
288 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
289 stats->retriesLong) ||
290 nla_put_u32(vendor_event,
291 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
292 stats->contentionTimeMin) ||
293 nla_put_u32(vendor_event,
294 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
295 stats->contentionTimeMax) ||
296 nla_put_u32(vendor_event,
297 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
298 stats->contentionTimeAvg) ||
299 nla_put_u32(vendor_event,
300 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
301 stats->contentionNumSamples)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700302 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800303 return false;
304 }
305
306 return true;
307}
308
309/**
310 * put_wifi_interface_info() - put wifi interface info
311 * @stats: Pointer to stats context
312 * @vendor_event: Pointer to vendor event
313 *
314 * Return: bool
315 */
316static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats,
317 struct sk_buff *vendor_event)
318{
319 if (nla_put_u32(vendor_event,
320 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
321 stats->mode) ||
322 nla_put(vendor_event,
323 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530324 QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800325 nla_put_u32(vendor_event,
326 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
327 stats->state) ||
328 nla_put_u32(vendor_event,
329 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
330 stats->roaming) ||
331 nla_put_u32(vendor_event,
332 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
333 stats->capabilities) ||
334 nla_put(vendor_event,
335 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
336 strlen(stats->ssid), stats->ssid) ||
337 nla_put(vendor_event,
338 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530339 QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800340 nla_put(vendor_event,
341 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
342 WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) ||
343 nla_put(vendor_event,
344 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
345 WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700346 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800347 return false;
348 }
349
350 return true;
351}
352
353/**
354 * put_wifi_iface_stats() - put wifi interface stats
355 * @pWifiIfaceStat: Pointer to interface stats context
356 * @num_peer: Number of peers
357 * @vendor_event: Pointer to vendor event
358 *
359 * Return: bool
360 */
361static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
362 u32 num_peers, struct sk_buff *vendor_event)
363{
364 int i = 0;
365 struct nlattr *wmmInfo;
366 struct nlattr *wmmStats;
367 u64 average_tsf_offset;
368
369 if (false == put_wifi_interface_info(&pWifiIfaceStat->info,
370 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700371 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800372 return false;
373
374 }
375
376 average_tsf_offset = pWifiIfaceStat->avg_bcn_spread_offset_high;
377 average_tsf_offset = (average_tsf_offset << 32) |
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700378 pWifiIfaceStat->avg_bcn_spread_offset_low;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800379
380 if (nla_put_u32(vendor_event,
381 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
382 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) ||
383 nla_put_u32(vendor_event,
384 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
385 num_peers) ||
386 nla_put_u32(vendor_event,
387 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
388 pWifiIfaceStat->beaconRx) ||
389 nla_put_u32(vendor_event,
390 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
391 pWifiIfaceStat->mgmtRx) ||
392 nla_put_u32(vendor_event,
393 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
394 pWifiIfaceStat->mgmtActionRx) ||
395 nla_put_u32(vendor_event,
396 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
397 pWifiIfaceStat->mgmtActionTx) ||
398 nla_put_u32(vendor_event,
399 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
400 pWifiIfaceStat->rssiMgmt) ||
401 nla_put_u32(vendor_event,
402 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
403 pWifiIfaceStat->rssiData) ||
404 nla_put_u32(vendor_event,
405 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
406 pWifiIfaceStat->rssiAck) ||
407 nla_put_u32(vendor_event,
408 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
409 pWifiIfaceStat->is_leaky_ap) ||
410 nla_put_u32(vendor_event,
411 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
412 pWifiIfaceStat->avg_rx_frms_leaked) ||
413 nla_put_u32(vendor_event,
414 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
415 pWifiIfaceStat->rx_leak_window) ||
Dustin Brownbb7e2f52016-10-17 12:16:35 -0700416 hdd_wlan_nla_put_u64(vendor_event,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800417 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
gaolezb432ed92017-03-16 18:40:04 +0800418 average_tsf_offset) ||
419 nla_put_u32(vendor_event,
420 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT,
421 pWifiIfaceStat->rts_succ_cnt) ||
422 nla_put_u32(vendor_event,
423 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT,
424 pWifiIfaceStat->rts_fail_cnt) ||
425 nla_put_u32(vendor_event,
426 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT,
427 pWifiIfaceStat->ppdu_succ_cnt) ||
428 nla_put_u32(vendor_event,
429 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT,
430 pWifiIfaceStat->ppdu_fail_cnt)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700431 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800432 return false;
433 }
434
435 wmmInfo = nla_nest_start(vendor_event,
436 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
437 if (wmmInfo == NULL)
438 return false;
439
440 for (i = 0; i < WIFI_AC_MAX; i++) {
441 wmmStats = nla_nest_start(vendor_event, i);
442 if (wmmStats == NULL)
443 return false;
444
445 if (false ==
446 put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i],
447 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700448 hdd_err("put_wifi_wmm_ac_stat Fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800449 return false;
450 }
451
452 nla_nest_end(vendor_event, wmmStats);
453 }
454 nla_nest_end(vendor_event, wmmInfo);
455 return true;
456}
457
458/**
459 * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
460 * @deviceMode: Device mode
461 *
462 * Return: interface mode
463 */
464static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode)
465{
466 switch (deviceMode) {
Krunal Sonif07bb382016-03-10 13:02:11 -0800467 case QDF_STA_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800468 return WIFI_INTERFACE_STA;
Krunal Sonif07bb382016-03-10 13:02:11 -0800469 case QDF_SAP_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800470 return WIFI_INTERFACE_SOFTAP;
Krunal Sonif07bb382016-03-10 13:02:11 -0800471 case QDF_P2P_CLIENT_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800472 return WIFI_INTERFACE_P2P_CLIENT;
Krunal Sonif07bb382016-03-10 13:02:11 -0800473 case QDF_P2P_GO_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474 return WIFI_INTERFACE_P2P_GO;
Krunal Sonif07bb382016-03-10 13:02:11 -0800475 case QDF_IBSS_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 return WIFI_INTERFACE_IBSS;
477 default:
478 /* Return Interface Mode as STA for all the unsupported modes */
479 return WIFI_INTERFACE_STA;
480 }
481}
482
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700483bool hdd_get_interface_info(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800484 tpSirWifiInterfaceInfo pInfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800485{
486 uint8_t *staMac = NULL;
Jeff Johnsond377dce2017-10-04 10:32:42 -0700487 struct hdd_station_ctx *sta_ctx;
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700488 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800489 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
490
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700491 pInfo->mode = hdd_map_device_to_ll_iface_mode(adapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800492
Jeff Johnson1e851a12017-10-28 14:36:12 -0700493 qdf_copy_macaddr(&pInfo->macAddr, &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800494
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700495 if (((QDF_STA_MODE == adapter->device_mode) ||
496 (QDF_P2P_CLIENT_MODE == adapter->device_mode) ||
497 (QDF_P2P_DEVICE_MODE == adapter->device_mode))) {
Jeff Johnsond377dce2017-10-04 10:32:42 -0700498 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800499 if (eConnectionState_NotConnected ==
Jeff Johnsond377dce2017-10-04 10:32:42 -0700500 sta_ctx->conn_info.connState) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501 pInfo->state = WIFI_DISCONNECTED;
502 }
503 if (eConnectionState_Connecting ==
Jeff Johnsond377dce2017-10-04 10:32:42 -0700504 sta_ctx->conn_info.connState) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700505 hdd_err("Session ID %d, Connection is in progress",
Jeff Johnson1b780e42017-10-31 14:11:45 -0700506 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507 pInfo->state = WIFI_ASSOCIATING;
508 }
509 if ((eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -0700510 sta_ctx->conn_info.connState)
511 && (false == sta_ctx->conn_info.uIsAuthenticated)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800512 staMac =
Jeff Johnson1e851a12017-10-28 14:36:12 -0700513 (uint8_t *) &(adapter->mac_addr.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800514 bytes[0]);
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700515 hdd_err("client " MAC_ADDRESS_STR
516 " is in the middle of WPS/EAPOL exchange.",
517 MAC_ADDR_ARRAY(staMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800518 pInfo->state = WIFI_AUTHENTICATING;
519 }
520 if (eConnectionState_Associated ==
Jeff Johnsond377dce2017-10-04 10:32:42 -0700521 sta_ctx->conn_info.connState) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800522 pInfo->state = WIFI_ASSOCIATED;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530523 qdf_copy_macaddr(&pInfo->bssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -0700524 &sta_ctx->conn_info.bssId);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530525 qdf_mem_copy(pInfo->ssid,
Jeff Johnsond377dce2017-10-04 10:32:42 -0700526 sta_ctx->conn_info.SSID.SSID.ssId,
527 sta_ctx->conn_info.SSID.SSID.length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800528 /*
529 * NULL Terminate the string
530 */
Jeff Johnsond377dce2017-10-04 10:32:42 -0700531 pInfo->ssid[sta_ctx->conn_info.SSID.SSID.length] = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800532 }
533 }
534
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530535 qdf_mem_copy(pInfo->countryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800536 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
537
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530538 qdf_mem_copy(pInfo->apCountryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800539 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
540
541 return true;
542}
543
544/**
545 * hdd_link_layer_process_peer_stats() - This function is called after
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700546 * @adapter: Pointer to device adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800547 * @more_data: More data
548 * @pData: Pointer to stats data
549 *
550 * Receiving Link Layer Peer statistics from FW.This function converts
551 * the firmware data to the NL data and sends the same to the kernel/upper
552 * layers.
553 *
554 * Return: None
555 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700556static void hdd_link_layer_process_peer_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800557 u32 more_data,
558 tpSirWifiPeerStat pData)
559{
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700560 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800561 tpSirWifiPeerStat pWifiPeerStat;
562 tpSirWifiPeerInfo pWifiPeerInfo;
563 struct sk_buff *vendor_event;
Sushant Kaushik7a535882015-11-02 13:31:21 +0530564 int status, i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800565 struct nlattr *peers;
566 int numRate;
567
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530568 ENTER();
569
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800570 pWifiPeerStat = pData;
571
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700572 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530573 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800574 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800575
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800576 hdd_debug("LL_STATS_PEER_ALL : numPeers %u, more data = %u",
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700577 pWifiPeerStat->numPeers, more_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800578
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800579 /*
580 * Allocate a size of 4096 for the peer stats comprising
581 * each of size = sizeof (tSirWifiPeerInfo) + numRate *
582 * sizeof (tSirWifiRateStat).Each field is put with an
583 * NL attribute.The size of 4096 is considered assuming
584 * that number of rates shall not exceed beyond 50 with
585 * the sizeof (tSirWifiRateStat) being 32.
586 */
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700587 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800588 LL_STATS_EVENT_BUF_SIZE);
589
590 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700591 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800592 return;
593 }
594
595 if (nla_put_u32(vendor_event,
596 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
597 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
598 nla_put_u32(vendor_event,
599 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
600 more_data) ||
601 nla_put_u32(vendor_event,
602 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
603 pWifiPeerStat->numPeers)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700604 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800605
606 kfree_skb(vendor_event);
607 return;
608 }
609
610 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
611 pWifiPeerStat->peerInfo);
612
613 if (pWifiPeerStat->numPeers) {
614 struct nlattr *peerInfo;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700615
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800616 peerInfo = nla_nest_start(vendor_event,
617 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO);
618 if (peerInfo == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700619 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800620 kfree_skb(vendor_event);
621 return;
622 }
623
624 for (i = 1; i <= pWifiPeerStat->numPeers; i++) {
625 peers = nla_nest_start(vendor_event, i);
626 if (peers == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700627 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800628 kfree_skb(vendor_event);
629 return;
630 }
631
632 numRate = pWifiPeerInfo->numRate;
633
634 if (false ==
635 put_wifi_peer_info(pWifiPeerInfo, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700636 hdd_err("put_wifi_peer_info fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800637 kfree_skb(vendor_event);
638 return;
639 }
640
641 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
642 pWifiPeerStat->
643 peerInfo +
644 (i *
645 sizeof
646 (tSirWifiPeerInfo))
647 +
648 (numRate *
649 sizeof
650 (tSirWifiRateStat)));
651 nla_nest_end(vendor_event, peers);
652 }
653 nla_nest_end(vendor_event, peerInfo);
654 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700655
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800656 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530657 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800658}
659
660/**
661 * hdd_link_layer_process_iface_stats() - This function is called after
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700662 * @adapter: Pointer to device adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800663 * @pData: Pointer to stats data
664 * @num_peers: Number of peers
665 *
666 * Receiving Link Layer Interface statistics from FW.This function converts
667 * the firmware data to the NL data and sends the same to the kernel/upper
668 * layers.
669 *
670 * Return: None
671 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700672static void hdd_link_layer_process_iface_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800673 tpSirWifiIfaceStat pData,
674 u32 num_peers)
675{
676 tpSirWifiIfaceStat pWifiIfaceStat;
677 struct sk_buff *vendor_event;
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700678 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800679 int status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800680
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530681 ENTER();
682
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800683 pWifiIfaceStat = pData;
684
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700685 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530686 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800687 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800688
689 /*
690 * Allocate a size of 4096 for the interface stats comprising
691 * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered
692 * assuming that all these fit with in the limit.Please take
693 * a call on the limit based on the data requirements on
694 * interface statistics.
695 */
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700696 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800697 LL_STATS_EVENT_BUF_SIZE);
698
699 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700700 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800701 return;
702 }
703
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800704 hdd_debug("WMI_LINK_STATS_IFACE Data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800705
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700706 if (false == hdd_get_interface_info(adapter, &pWifiIfaceStat->info)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700707 hdd_err("hdd_get_interface_info get fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708 kfree_skb(vendor_event);
709 return;
710 }
711
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800712 if (false ==
713 put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700714 hdd_err("put_wifi_iface_stats fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800715 kfree_skb(vendor_event);
716 return;
717 }
718
719 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530720 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800721}
722
723/**
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700724 * hdd_llstats_radio_fill_channels() - radio stats fill channels
725 * @adapter: Pointer to device adapter
726 * @radiostat: Pointer to stats data
727 * @vendor_event: vendor event
728 *
729 * Return: 0 on success; errno on failure
730 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700731static int hdd_llstats_radio_fill_channels(struct hdd_adapter *adapter,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700732 tSirWifiRadioStat *radiostat,
733 struct sk_buff *vendor_event)
734{
735 tSirWifiChannelStats *channel_stats;
736 struct nlattr *chlist;
737 struct nlattr *chinfo;
738 int i;
739
740 chlist = nla_nest_start(vendor_event,
741 QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
742 if (chlist == NULL) {
743 hdd_err("nla_nest_start failed");
744 return -EINVAL;
745 }
746
747 for (i = 0; i < radiostat->numChannels; i++) {
748 channel_stats = (tSirWifiChannelStats *) ((uint8_t *)
749 radiostat->channels +
750 (i * sizeof(tSirWifiChannelStats)));
751
752 chinfo = nla_nest_start(vendor_event, i);
753 if (chinfo == NULL) {
754 hdd_err("nla_nest_start failed");
755 return -EINVAL;
756 }
757
758 if (nla_put_u32(vendor_event,
759 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
760 channel_stats->channel.width) ||
761 nla_put_u32(vendor_event,
762 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
763 channel_stats->channel.centerFreq) ||
764 nla_put_u32(vendor_event,
765 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
766 channel_stats->channel.centerFreq0) ||
767 nla_put_u32(vendor_event,
768 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
769 channel_stats->channel.centerFreq1) ||
770 nla_put_u32(vendor_event,
771 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
772 channel_stats->onTime) ||
773 nla_put_u32(vendor_event,
774 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
775 channel_stats->ccaBusyTime)) {
776 hdd_err("nla_put failed");
777 return -EINVAL;
778 }
779 nla_nest_end(vendor_event, chinfo);
780 }
781 nla_nest_end(vendor_event, chlist);
782
783 return 0;
784}
785
786/**
787 * hdd_llstats_post_radio_stats() - post radio stats
788 * @adapter: Pointer to device adapter
789 * @more_data: More data
790 * @radiostat: Pointer to stats data
791 * @num_radio: Number of radios
792 *
793 * Return: 0 on success; errno on failure
794 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700795static int hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700796 u32 more_data,
797 tSirWifiRadioStat *radiostat,
798 u32 num_radio)
799{
800 struct sk_buff *vendor_event;
Jeff Johnson5eb1e682017-08-28 11:42:15 -0700801 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700802 int ret;
803
804 /*
805 * Allocate a size of 4096 for the Radio stats comprising
806 * sizeof (tSirWifiRadioStat) + numChannels * sizeof
807 * (tSirWifiChannelStats).Each channel data is put with an
808 * NL attribute.The size of 4096 is considered assuming that
809 * number of channels shall not exceed beyond 60 with the
810 * sizeof (tSirWifiChannelStats) being 24 bytes.
811 */
812
813 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(
814 hdd_ctx->wiphy,
815 LL_STATS_EVENT_BUF_SIZE);
816
817 if (!vendor_event) {
818 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
819 return -ENOMEM;
820 }
821
822 if (nla_put_u32(vendor_event,
823 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
824 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
825 nla_put_u32(vendor_event,
826 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
827 more_data) ||
828 nla_put_u32(vendor_event,
829 QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
830 num_radio) ||
831 nla_put_u32(vendor_event,
832 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
833 radiostat->radio) ||
834 nla_put_u32(vendor_event,
835 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
836 radiostat->onTime) ||
837 nla_put_u32(vendor_event,
838 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
839 radiostat->txTime) ||
840 nla_put_u32(vendor_event,
841 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
842 radiostat->rxTime) ||
843 nla_put_u32(vendor_event,
844 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
845 radiostat->onTimeScan) ||
846 nla_put_u32(vendor_event,
847 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
848 radiostat->onTimeNbd) ||
849 nla_put_u32(vendor_event,
850 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
851 radiostat->onTimeGscan) ||
852 nla_put_u32(vendor_event,
853 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
854 radiostat->onTimeRoamScan) ||
855 nla_put_u32(vendor_event,
856 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
857 radiostat->onTimePnoScan) ||
858 nla_put_u32(vendor_event,
859 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
860 radiostat->onTimeHs20) ||
861 nla_put_u32(vendor_event,
862 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
863 radiostat->total_num_tx_power_levels) ||
864 nla_put_u32(vendor_event,
865 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
866 radiostat->numChannels)) {
867 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
868 goto failure;
869 }
870
871 if (radiostat->total_num_tx_power_levels) {
872 if (nla_put(vendor_event,
873 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
874 sizeof(u32) *
875 radiostat->total_num_tx_power_levels,
876 radiostat->tx_time_per_power_level)) {
877 hdd_err("nla_put fail");
878 goto failure;
879 }
880 }
881
882 if (radiostat->numChannels) {
883 ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
884 vendor_event);
885 if (ret)
886 goto failure;
887 }
888
889 cfg80211_vendor_cmd_reply(vendor_event);
890 return 0;
891
892failure:
893 kfree_skb(vendor_event);
894 return -EINVAL;
895}
896
897/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898 * hdd_link_layer_process_radio_stats() - This function is called after
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700899 * @adapter: Pointer to device adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800900 * @more_data: More data
901 * @pData: Pointer to stats data
902 * @num_radios: Number of radios
903 *
904 * Receiving Link Layer Radio statistics from FW.This function converts
905 * the firmware data to the NL data and sends the same to the kernel/upper
906 * layers.
907 *
908 * Return: None
909 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700910static void hdd_link_layer_process_radio_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800911 u32 more_data,
912 tpSirWifiRadioStat pData,
913 u32 num_radio)
914{
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700915 int status, i, nr, ret;
916 tSirWifiRadioStat *pWifiRadioStat = pData;
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700917 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800918
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530919 ENTER();
920
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700921 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530922 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800923 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800925 hdd_debug("LL_STATS_RADIO: number of radios: %u", num_radio);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800926
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700927 for (i = 0; i < num_radio; i++) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800928 hdd_debug("LL_STATS_RADIO"
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700929 " radio: %u onTime: %u txTime: %u rxTime: %u"
930 " onTimeScan: %u onTimeNbd: %u"
931 " onTimeGscan: %u onTimeRoamScan: %u"
932 " onTimePnoScan: %u onTimeHs20: %u"
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -0800933 " numChannels: %u total_num_tx_pwr_levels: %u"
934 " on_time_host_scan: %u, on_time_lpi_scan: %u",
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700935 pWifiRadioStat->radio, pWifiRadioStat->onTime,
936 pWifiRadioStat->txTime, pWifiRadioStat->rxTime,
937 pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd,
938 pWifiRadioStat->onTimeGscan,
939 pWifiRadioStat->onTimeRoamScan,
940 pWifiRadioStat->onTimePnoScan,
941 pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels,
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -0800942 pWifiRadioStat->total_num_tx_power_levels,
943 pWifiRadioStat->on_time_host_scan,
944 pWifiRadioStat->on_time_lpi_scan);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700945 pWifiRadioStat++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800946 }
947
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700948 pWifiRadioStat = pData;
949 for (nr = 0; nr < num_radio; nr++) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700950 ret = hdd_llstats_post_radio_stats(adapter, more_data,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700951 pWifiRadioStat, num_radio);
952 if (ret)
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700953 return;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700954
955 pWifiRadioStat++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700956 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700957
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530958 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800959}
960
961/**
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800962 * hdd_ll_process_radio_stats() - Wrapper function for cfg80211/debugfs
963 * @adapter: Pointer to device adapter
964 * @more_data: More data
965 * @data: Pointer to stats data
966 * @num_radios: Number of radios
967 * @resp_id: Response ID from FW
968 *
969 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
970 * function which calls cfg80211/debugfs functions based on the response ID.
971 *
972 * Return: None
973 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700974static void hdd_ll_process_radio_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800975 uint32_t more_data, void *data, uint32_t num_radio,
976 uint32_t resp_id)
977{
978 if (DEBUGFS_LLSTATS_REQID == resp_id)
979 hdd_debugfs_process_radio_stats(adapter, more_data,
980 (tpSirWifiRadioStat)data, num_radio);
981 else
982 hdd_link_layer_process_radio_stats(adapter, more_data,
983 (tpSirWifiRadioStat)data, num_radio);
984}
985
986/**
987 * hdd_ll_process_iface_stats() - Wrapper function for cfg80211/debugfs
988 * @adapter: Pointer to device adapter
989 * @data: Pointer to stats data
990 * @num_peers: Number of peers
991 * @resp_id: Response ID from FW
992 *
993 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
994 * function which calls cfg80211/debugfs functions based on the response ID.
995 *
996 * Return: None
997 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700998static void hdd_ll_process_iface_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800999 void *data, uint32_t num_peers, uint32_t resp_id)
1000{
1001 if (DEBUGFS_LLSTATS_REQID == resp_id)
1002 hdd_debugfs_process_iface_stats(adapter,
1003 (tpSirWifiIfaceStat) data, num_peers);
1004 else
1005 hdd_link_layer_process_iface_stats(adapter,
1006 (tpSirWifiIfaceStat) data, num_peers);
1007}
1008
1009/**
1010 * hdd_ll_process_peer_stats() - Wrapper function for cfg80211/debugfs
1011 * @adapter: Pointer to device adapter
1012 * @more_data: More data
1013 * @data: Pointer to stats data
1014 * @resp_id: Response ID from FW
1015 *
1016 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1017 * function which calls cfg80211/debugfs functions based on the response ID.
1018 *
1019 * Return: None
1020 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001021static void hdd_ll_process_peer_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001022 uint32_t more_data, void *data, uint32_t resp_id)
1023{
1024 if (DEBUGFS_LLSTATS_REQID == resp_id)
1025 hdd_debugfs_process_peer_stats(adapter, data);
1026 else
1027 hdd_link_layer_process_peer_stats(adapter, more_data,
1028 (tpSirWifiPeerStat) data);
1029}
1030
1031/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032 * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called
1033 * @ctx: Pointer to hdd context
1034 * @indType: Indication type
1035 * @pRsp: Pointer to response
1036 *
1037 * After receiving Link Layer indications from FW.This callback converts the
1038 * firmware data to the NL data and send the same to the kernel/upper layers.
1039 *
1040 * Return: None
1041 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301042void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043 int indType, void *pRsp)
1044{
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001045 struct hdd_context *hdd_ctx = (struct hdd_context *) ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046 struct hdd_ll_stats_context *context;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001047 struct hdd_adapter *adapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001048 tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp;
1049 int status;
1050
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001051 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301052 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001053 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001055 adapter = hdd_get_adapter_by_vdev(hdd_ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001056 linkLayerStatsResults->ifaceId);
1057
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001058 if (NULL == adapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001059 hdd_err("vdev_id %d does not exist with host",
1060 linkLayerStatsResults->ifaceId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001061 return;
1062 }
1063
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001064 hdd_debug("Link Layer Indication indType: %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065
1066 switch (indType) {
1067 case SIR_HAL_LL_STATS_RESULTS_RSP:
1068 {
Jeff Johnson36e74c42017-09-18 08:15:42 -07001069 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 +05301070 linkLayerStatsResults->paramId,
1071 linkLayerStatsResults->ifaceId,
1072 linkLayerStatsResults->rspId,
1073 linkLayerStatsResults->moreResultToFollow,
1074 linkLayerStatsResults->num_radio,
1075 linkLayerStatsResults->results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076
1077 context = &ll_stats_context;
1078 spin_lock(&context->context_lock);
1079 /* validate response received from target */
1080 if ((context->request_id != linkLayerStatsResults->rspId) ||
1081 !(context->request_bitmap & linkLayerStatsResults->paramId)) {
1082 spin_unlock(&context->context_lock);
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001083 hdd_err("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 context->request_id, linkLayerStatsResults->rspId,
1085 context->request_bitmap, linkLayerStatsResults->paramId);
1086 return;
1087 }
1088 spin_unlock(&context->context_lock);
1089
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001090 if (linkLayerStatsResults->paramId & WMI_LINK_STATS_RADIO) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001091 hdd_ll_process_radio_stats(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001092 linkLayerStatsResults->moreResultToFollow,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001093 linkLayerStatsResults->results,
1094 linkLayerStatsResults->num_radio,
1095 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096
1097 spin_lock(&context->context_lock);
1098 if (!linkLayerStatsResults->moreResultToFollow)
1099 context->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
1100 spin_unlock(&context->context_lock);
1101
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001102 } else if (linkLayerStatsResults->paramId &
1103 WMI_LINK_STATS_IFACE) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001104 hdd_ll_process_iface_stats(adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001105 linkLayerStatsResults->results,
1106 linkLayerStatsResults->num_peers,
1107 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108
1109 spin_lock(&context->context_lock);
Srinivas Dasari6946a792015-09-28 15:01:49 +05301110 /* Firmware doesn't send peerstats event if no peers are
1111 * connected. HDD should not wait for any peerstats in
1112 * this case and return the status to middleware after
1113 * receiving iface stats
1114 */
1115 if (!linkLayerStatsResults->num_peers)
1116 context->request_bitmap &=
1117 ~(WMI_LINK_STATS_ALL_PEER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118 context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
1119 spin_unlock(&context->context_lock);
1120
1121 } else if (linkLayerStatsResults->
1122 paramId & WMI_LINK_STATS_ALL_PEER) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001123 hdd_ll_process_peer_stats(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001124 linkLayerStatsResults->moreResultToFollow,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001125 linkLayerStatsResults->results,
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_ALL_PEER);
1131 spin_unlock(&context->context_lock);
1132
1133 } else {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001134 hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001135 }
1136
1137 spin_lock(&context->context_lock);
1138 /* complete response event if all requests are completed */
1139 if (0 == context->request_bitmap)
1140 complete(&context->response_event);
1141 spin_unlock(&context->context_lock);
1142
1143 break;
1144 }
1145 default:
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001146 hdd_warn("invalid event type %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001147 break;
1148 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001149}
1150
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301151void hdd_lost_link_info_cb(void *context,
1152 struct sir_lost_link_info *lost_link_info)
1153{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001154 struct hdd_context *hdd_ctx = (struct hdd_context *)context;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301155 int status;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001156 struct hdd_adapter *adapter;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301157
1158 status = wlan_hdd_validate_context(hdd_ctx);
1159 if (0 != status)
1160 return;
1161
1162 if (NULL == lost_link_info) {
1163 hdd_err("lost_link_info is NULL");
1164 return;
1165 }
1166
1167 adapter = hdd_get_adapter_by_vdev(hdd_ctx, lost_link_info->vdev_id);
1168 if (NULL == adapter) {
1169 hdd_err("invalid adapter");
1170 return;
1171 }
1172
1173 adapter->rssi_on_disconnect = lost_link_info->rssi;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001174 hdd_debug("rssi on disconnect %d", adapter->rssi_on_disconnect);
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301175}
1176
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001177const struct
1178nla_policy
1179 qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1180 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1181 .type = NLA_U32},
1182 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1183 .type = NLA_U32},
1184};
1185
1186/**
1187 * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1188 * @wiphy: Pointer to wiphy
1189 * @wdev: Pointer to wdev
1190 * @data: Pointer to data
1191 * @data_len: Data length
1192 *
1193 * Return: int
1194 */
1195static int
1196__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1197 struct wireless_dev *wdev,
1198 const void *data,
1199 int data_len)
1200{
1201 int status;
1202 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
1203 tSirLLStatsSetReq LinkLayerStatsSetReq;
1204 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001205 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001206 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001207
Jeff Johnson1f61b612016-02-12 16:28:33 -08001208 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301209
Anurag Chouhan6d760662016-02-20 16:05:43 +05301210 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001211 hdd_err("Command not allowed in FTM mode");
1212 return -EPERM;
1213 }
1214
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001215 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301216 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001218
Dustin Brown4ea21db2018-01-05 14:13:17 -08001219 if (wlan_cfg80211_nla_parse(tb_vendor,
1220 QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1221 (struct nlattr *)data, data_len,
1222 qca_wlan_vendor_ll_set_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001223 hdd_err("maximum attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001224 return -EINVAL;
1225 }
1226
1227 if (!tb_vendor
1228 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001229 hdd_err("MPDU size Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230 return -EINVAL;
1231 }
1232
1233 if (!tb_vendor
1234 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001235 hdd_err("Stats Gathering Not Present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 return -EINVAL;
1237 }
1238
1239 /* Shall take the request Id if the Upper layers pass. 1 For now. */
1240 LinkLayerStatsSetReq.reqId = 1;
1241
1242 LinkLayerStatsSetReq.mpduSizeThreshold =
1243 nla_get_u32(tb_vendor
1244 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1245
1246 LinkLayerStatsSetReq.aggressiveStatisticsGathering =
1247 nla_get_u32(tb_vendor
1248 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1249
Jeff Johnson1b780e42017-10-31 14:11:45 -07001250 LinkLayerStatsSetReq.staId = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001251
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001252 hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301253 LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId,
1254 LinkLayerStatsSetReq.mpduSizeThreshold,
1255 LinkLayerStatsSetReq.aggressiveStatisticsGathering);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001256
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001257 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(hdd_ctx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001258 &LinkLayerStatsSetReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001259 hdd_err("sme_ll_stats_set_req Failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001260 return -EINVAL;
1261 }
1262
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001263 adapter->is_link_layer_stats_set = true;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301264 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265 return 0;
1266}
1267
1268/**
1269 * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1270 * @wiphy: Pointer to wiphy
1271 * @wdev: Pointer to wdev
1272 * @data: Pointer to data
1273 * @data_len: Data length
1274 *
1275 * Return: 0 if success, non-zero for failure
1276 */
1277int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1278 struct wireless_dev *wdev,
1279 const void *data,
1280 int data_len)
1281{
1282 int ret = 0;
1283
1284 cds_ssr_protect(__func__);
1285 ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
1286 cds_ssr_unprotect(__func__);
1287
1288 return ret;
1289}
1290
1291const struct
1292nla_policy
1293 qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1294 /* Unsigned 32bit value provided by the caller issuing the GET stats
1295 * command. When reporting
1296 * the stats results, the driver uses the same value to indicate
1297 * which GET request the results
1298 * correspond to.
1299 */
1300 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1301
1302 /* Unsigned 32bit value . bit mask to identify what statistics are
Jeff Johnson8bb78c32017-01-12 08:42:50 -08001303 * requested for retrieval
1304 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1306};
1307
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001308static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001309 tSirLLStatsGetReq *req)
1310{
1311 unsigned long rc;
1312 struct hdd_ll_stats_context *context;
1313
1314 context = &ll_stats_context;
1315 spin_lock(&context->context_lock);
1316 context->request_id = req->reqId;
1317 context->request_bitmap = req->paramIdMask;
1318 INIT_COMPLETION(context->response_event);
1319 spin_unlock(&context->context_lock);
1320
1321 if (QDF_STATUS_SUCCESS !=
1322 sme_ll_stats_get_req(hdd_ctx->hHal, req)) {
1323 hdd_err("sme_ll_stats_get_req Failed");
1324 return -EINVAL;
1325 }
1326
1327 rc = wait_for_completion_timeout(&context->response_event,
1328 msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
1329 if (!rc) {
1330 hdd_err("Target response timed out request id %d request bitmap 0x%x",
1331 context->request_id, context->request_bitmap);
1332 return -ETIMEDOUT;
1333 }
1334
1335 return 0;
1336}
1337
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001338int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001339 uint32_t req_mask)
1340{
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001341 int ret;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001342 tSirLLStatsGetReq get_req;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001343 struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001344 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001345
1346 ENTER();
1347
1348 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1349 hdd_warn("Command not allowed in FTM mode");
1350 return -EPERM;
1351 }
1352
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001353 ret = wlan_hdd_validate_context(hdd_ctx);
1354 if (0 != ret)
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001355 return -EINVAL;
1356
Jeff Johnson690fe952017-10-25 11:48:39 -07001357 if (hddstactx->hdd_reassoc_scenario) {
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001358 hdd_err("Roaming in progress, cannot process the request");
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001359 return -EBUSY;
1360 }
1361
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001362 if (!adapter->is_link_layer_stats_set)
1363 hdd_info("is_link_layer_stats_set: %d; STATs will be all zero",
1364 adapter->is_link_layer_stats_set);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001365
1366 get_req.reqId = req_id;
1367 get_req.paramIdMask = req_mask;
Jeff Johnson1b780e42017-10-31 14:11:45 -07001368 get_req.staId = adapter->session_id;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001369
1370 rtnl_lock();
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001371 ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001372 rtnl_unlock();
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001373 if (0 != ret)
1374 hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
Jeff Johnson1b780e42017-10-31 14:11:45 -07001375 req_id, req_mask, adapter->session_id);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001376
1377 EXIT();
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001378 return ret;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001379
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001380}
1381
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001382/**
1383 * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1384 * @wiphy: Pointer to wiphy
1385 * @wdev: Pointer to wdev
1386 * @data: Pointer to data
1387 * @data_len: Data length
1388 *
1389 * Return: int
1390 */
1391static int
1392__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1393 struct wireless_dev *wdev,
1394 const void *data,
1395 int data_len)
1396{
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001397 int ret;
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001398 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001399 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1400 tSirLLStatsGetReq LinkLayerStatsGetReq;
1401 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001402 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1403 struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001404
Kapil Guptabf4943c2016-10-13 12:15:39 +05301405 /* ENTER() intentionally not used in a frequently invoked API */
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301406
Anurag Chouhan6d760662016-02-20 16:05:43 +05301407 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001408 hdd_err("Command not allowed in FTM mode");
1409 return -EPERM;
1410 }
1411
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001412 ret = wlan_hdd_validate_context(hdd_ctx);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001413 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001414 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001416 if (!adapter->is_link_layer_stats_set) {
1417 hdd_warn("is_link_layer_stats_set: %d",
1418 adapter->is_link_layer_stats_set);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001419 return -EINVAL;
1420 }
1421
Jeff Johnson690fe952017-10-25 11:48:39 -07001422 if (hddstactx->hdd_reassoc_scenario) {
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001423 hdd_err("Roaming in progress, cannot process the request");
Anurag Chouhan22520002016-09-03 16:20:32 +05301424 return -EBUSY;
1425 }
1426
Dustin Brown4ea21db2018-01-05 14:13:17 -08001427 if (wlan_cfg80211_nla_parse(tb_vendor,
1428 QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1429 (struct nlattr *)data, data_len,
1430 qca_wlan_vendor_ll_get_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001431 hdd_err("max attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001432 return -EINVAL;
1433 }
1434
1435 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001436 hdd_err("Request Id Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001437 return -EINVAL;
1438 }
1439
1440 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001441 hdd_err("Req Mask Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001442 return -EINVAL;
1443 }
1444
1445 LinkLayerStatsGetReq.reqId =
1446 nla_get_u32(tb_vendor
1447 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1448 LinkLayerStatsGetReq.paramIdMask =
1449 nla_get_u32(tb_vendor
1450 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1451
Jeff Johnson1b780e42017-10-31 14:11:45 -07001452 LinkLayerStatsGetReq.staId = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453
Jeff Johnson1b780e42017-10-31 14:11:45 -07001454 if (wlan_hdd_validate_session_id(adapter->session_id)) {
1455 hdd_err("invalid session id: %d", adapter->session_id);
yeshwanth sriram guntuka08e995b2017-04-26 12:32:12 +05301456 return -EINVAL;
1457 }
1458
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001459 ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &LinkLayerStatsGetReq);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001460 if (0 != ret) {
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001461 hdd_err("Failed to send LL stats request (id:%u)",
1462 LinkLayerStatsGetReq.reqId);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001463 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 }
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001465
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301466 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001467 return 0;
1468}
1469
1470/**
1471 * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1472 * @wiphy: Pointer to wiphy
1473 * @wdev: Pointer to wdev
1474 * @data: Pointer to data
1475 * @data_len: Data length
1476 *
1477 * Return: 0 if success, non-zero for failure
1478 */
1479int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1480 struct wireless_dev *wdev,
1481 const void *data,
1482 int data_len)
1483{
1484 int ret = 0;
1485
1486 cds_ssr_protect(__func__);
1487 ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1488 cds_ssr_unprotect(__func__);
1489
1490 return ret;
1491}
1492
1493const struct
1494nla_policy
1495 qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1496 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1497 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1498 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1499 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1500};
1501
1502/**
1503 * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1504 * @wiphy: Pointer to wiphy
1505 * @wdev: Pointer to wdev
1506 * @data: Pointer to data
1507 * @data_len: Data length
1508 *
1509 * Return: int
1510 */
1511static int
1512__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1513 struct wireless_dev *wdev,
1514 const void *data,
1515 int data_len)
1516{
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001517 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001518 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1519 tSirLLStatsClearReq LinkLayerStatsClearReq;
1520 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001521 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001522 u32 statsClearReqMask;
1523 u8 stopReq;
1524 int status;
1525 struct sk_buff *temp_skbuff;
1526
Jeff Johnson1f61b612016-02-12 16:28:33 -08001527 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301528
Anurag Chouhan6d760662016-02-20 16:05:43 +05301529 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001530 hdd_err("Command not allowed in FTM mode");
1531 return -EPERM;
1532 }
1533
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001534 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301535 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001536 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001537
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001538 if (!adapter->is_link_layer_stats_set) {
1539 hdd_warn("is_link_layer_stats_set : %d",
1540 adapter->is_link_layer_stats_set);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001541 return -EINVAL;
1542 }
1543
Dustin Brown4ea21db2018-01-05 14:13:17 -08001544 if (wlan_cfg80211_nla_parse(tb_vendor,
1545 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1546 (struct nlattr *)data, data_len,
1547 qca_wlan_vendor_ll_clr_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001548 hdd_err("STATS_CLR_MAX is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549 return -EINVAL;
1550 }
1551
1552 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1553 !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001554 hdd_err("Error in LL_STATS CLR CONFIG PARA");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555 return -EINVAL;
1556 }
1557
1558 statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1559 nla_get_u32(tb_vendor
1560 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1561
1562 stopReq = LinkLayerStatsClearReq.stopReq =
1563 nla_get_u8(tb_vendor
1564 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1565
1566 /*
1567 * Shall take the request Id if the Upper layers pass. 1 For now.
1568 */
1569 LinkLayerStatsClearReq.reqId = 1;
1570
Jeff Johnson1b780e42017-10-31 14:11:45 -07001571 LinkLayerStatsClearReq.staId = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001573 hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301574 LinkLayerStatsClearReq.reqId,
1575 LinkLayerStatsClearReq.staId,
1576 LinkLayerStatsClearReq.statsClearReqMask,
1577 LinkLayerStatsClearReq.stopReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001578
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001579 if (QDF_STATUS_SUCCESS == sme_ll_stats_clear_req(hdd_ctx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580 &LinkLayerStatsClearReq)) {
1581 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1582 2 *
1583 sizeof(u32) +
1584 2 *
1585 NLMSG_HDRLEN);
1586 if (temp_skbuff != NULL) {
1587 if (nla_put_u32(temp_skbuff,
1588 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1589 statsClearReqMask) ||
1590 nla_put_u32(temp_skbuff,
1591 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1592 stopReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001593 hdd_err("LL_STATS_CLR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001594 kfree_skb(temp_skbuff);
1595 return -EINVAL;
1596 }
1597
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001598 /* If the ask is to stop the stats collection
1599 * as part of clear (stopReq = 1), ensure
1600 * that no further requests of get go to the
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001601 * firmware by having is_link_layer_stats_set set
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001602 * to 0. However it the stopReq as part of
1603 * the clear request is 0, the request to get
1604 * the statistics are honoured as in this case
1605 * the firmware is just asked to clear the
1606 * statistics.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001607 */
1608 if (stopReq == 1)
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001609 adapter->is_link_layer_stats_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001610
1611 return cfg80211_vendor_cmd_reply(temp_skbuff);
1612 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301613 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614 return -ENOMEM;
1615 }
1616
1617 return -EINVAL;
1618}
1619
1620/**
1621 * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1622 * @wiphy: Pointer to wiphy
1623 * @wdev: Pointer to wdev
1624 * @data: Pointer to data
1625 * @data_len: Data length
1626 *
1627 * Return: 0 if success, non-zero for failure
1628 */
1629int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1630 struct wireless_dev *wdev,
1631 const void *data,
1632 int data_len)
1633{
1634 int ret = 0;
1635
1636 cds_ssr_protect(__func__);
1637 ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
1638 cds_ssr_unprotect(__func__);
1639
1640 return ret;
1641}
1642
Zhang Qianca38fb12016-12-23 11:10:48 +08001643/**
1644 * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
1645 * @wifi_peer_info: peer information
1646 * @vendor_event: buffer for vendor event
1647 *
1648 * Return: 0 success
1649 */
1650static inline int
1651hdd_populate_per_peer_ps_info(tSirWifiPeerInfo *wifi_peer_info,
1652 struct sk_buff *vendor_event)
1653{
1654 if (!wifi_peer_info) {
1655 hdd_err("Invalid pointer to peer info.");
1656 return -EINVAL;
1657 }
1658
1659 if (nla_put_u32(vendor_event,
1660 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
1661 wifi_peer_info->power_saving) ||
1662 nla_put(vendor_event,
1663 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
1664 QDF_MAC_ADDR_SIZE, &wifi_peer_info->peerMacAddress)) {
1665 hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
1666 return -EINVAL;
1667 }
1668 return 0;
1669}
1670
1671/**
1672 * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
1673 * @data: stats for peer STA
1674 * @vendor_event: buffer for vendor event
1675 *
1676 * Return: 0 success
1677 */
1678static int hdd_populate_wifi_peer_ps_info(tSirWifiPeerStat *data,
1679 struct sk_buff *vendor_event)
1680{
1681 uint32_t peer_num, i;
1682 tSirWifiPeerInfo *wifi_peer_info;
1683 struct nlattr *peer_info, *peers;
1684
1685 if (!data) {
1686 hdd_err("Invalid pointer to Wifi peer stat.");
1687 return -EINVAL;
1688 }
1689
1690 peer_num = data->numPeers;
1691 if (peer_num == 0) {
1692 hdd_err("Peer number is zero.");
1693 return -EINVAL;
1694 }
1695
1696 if (nla_put_u32(vendor_event,
1697 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
1698 peer_num)) {
1699 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1700 return -EINVAL;
1701 }
1702
1703 peer_info = nla_nest_start(vendor_event,
1704 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
1705 if (peer_info == NULL) {
1706 hdd_err("nla_nest_start failed");
1707 return -EINVAL;
1708 }
1709
1710 for (i = 0; i < peer_num; i++) {
1711 wifi_peer_info = &data->peerInfo[i];
1712 peers = nla_nest_start(vendor_event, i);
1713
1714 if (peers == NULL) {
1715 hdd_err("nla_nest_start failed");
1716 return -EINVAL;
1717 }
1718
1719 if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
1720 return -EINVAL;
1721
1722 nla_nest_end(vendor_event, peers);
1723 }
1724 nla_nest_end(vendor_event, peer_info);
1725
1726 return 0;
1727}
1728
1729/**
1730 * hdd_populate_tx_failure_info() - populate TX failure info
1731 * @tx_fail: TX failure info
1732 * @skb: buffer for vendor event
1733 *
1734 * Return: 0 Success
1735 */
1736static inline int
1737hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
1738 struct sk_buff *skb)
1739{
1740 int status = 0;
1741
1742 if (tx_fail == NULL || skb == NULL)
1743 return -EINVAL;
1744
1745 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
1746 tx_fail->tid) ||
1747 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
1748 tx_fail->msdu_num) ||
1749 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
1750 tx_fail->status)) {
1751 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1752 status = -EINVAL;
1753 }
1754
1755 return status;
1756}
1757
1758/**
Zhang Qian4ead8f02017-03-27 14:21:47 +08001759 * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event
1760 * @info: cca info array for all channels
1761 * @vendor_event: vendor event buffer
1762 *
1763 * Return: 0 Success, EINVAL failure
1764 */
1765static int
1766hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca,
1767 struct sk_buff *vendor_event)
1768{
1769 /* There might be no CCA info for a channel */
1770 if (!cca)
1771 return 0;
1772
1773 if (nla_put_u32(vendor_event,
1774 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
1775 cca->idle_time) ||
1776 nla_put_u32(vendor_event,
1777 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
1778 cca->tx_time) ||
1779 nla_put_u32(vendor_event,
1780 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
1781 cca->rx_in_bss_time) ||
1782 nla_put_u32(vendor_event,
1783 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
1784 cca->rx_out_bss_time) ||
1785 nla_put_u32(vendor_event,
1786 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
1787 cca->rx_busy_time) ||
1788 nla_put_u32(vendor_event,
1789 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
1790 cca->rx_in_bad_cond_time) ||
1791 nla_put_u32(vendor_event,
1792 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
1793 cca->tx_in_bad_cond_time) ||
1794 nla_put_u32(vendor_event,
1795 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
1796 cca->wlan_not_avail_time) ||
1797 nla_put_u32(vendor_event,
1798 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
1799 cca->vdev_id)) {
1800 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1801 return -EINVAL;
1802 }
1803 return 0;
1804}
1805
1806/**
1807 * hdd_populate_wifi_signal_info - put chain signal info
1808 * @info: RF chain signal info
1809 * @skb: vendor event buffer
1810 *
1811 * Return: 0 Success, EINVAL failure
1812 */
1813static int
1814hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal,
1815 struct sk_buff *skb)
1816{
Zhang Qian303ebe92017-05-18 13:59:07 +08001817 uint32_t i, chain_count;
Zhang Qian4ead8f02017-03-27 14:21:47 +08001818 struct nlattr *chains, *att;
1819
1820 /* There might be no signal info for a peer */
1821 if (!peer_signal)
1822 return 0;
1823
Zhang Qian303ebe92017-05-18 13:59:07 +08001824 chain_count = peer_signal->num_chain < WIFI_MAX_CHAINS ?
1825 peer_signal->num_chain : WIFI_MAX_CHAINS;
Zhang Qian4ead8f02017-03-27 14:21:47 +08001826 if (nla_put_u32(skb,
1827 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
Zhang Qian303ebe92017-05-18 13:59:07 +08001828 chain_count)) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001829 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1830 return -EINVAL;
1831 }
1832
1833 att = nla_nest_start(skb,
1834 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL);
1835 if (!att) {
1836 hdd_err("nla_nest_start failed");
1837 return -EINVAL;
1838 }
1839
Zhang Qian303ebe92017-05-18 13:59:07 +08001840 for (i = 0; i < chain_count; i++) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001841 chains = nla_nest_start(skb, i);
1842
1843 if (!chains) {
1844 hdd_err("nla_nest_start failed");
1845 return -EINVAL;
1846 }
1847
Zhang Qian303ebe92017-05-18 13:59:07 +08001848 hdd_debug("SNR=%d, NF=%d, Rx=%d, Tx=%d",
1849 peer_signal->per_ant_snr[i],
1850 peer_signal->nf[i],
1851 peer_signal->per_ant_rx_mpdus[i],
1852 peer_signal->per_ant_tx_mpdus[i]);
Zhang Qian4ead8f02017-03-27 14:21:47 +08001853 if (nla_put_u32(skb,
1854 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
1855 peer_signal->per_ant_snr[i]) ||
1856 nla_put_u32(skb,
1857 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
Zhang Qian303ebe92017-05-18 13:59:07 +08001858 peer_signal->nf[i]) ||
1859 nla_put_u32(skb,
1860 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
1861 peer_signal->per_ant_rx_mpdus[i]) ||
1862 nla_put_u32(skb,
1863 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1864 peer_signal->per_ant_tx_mpdus[i])) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001865 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1866 return -EINVAL;
1867 }
1868 nla_nest_end(skb, chains);
1869 }
1870 nla_nest_end(skb, att);
1871
1872 return 0;
1873}
1874
1875/**
1876 * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info
1877 * @info: tx info
1878 * @skb: vendor event buffer
1879 *
1880 * Return: 0 Success, EINVAL failure
1881 */
1882static int
1883hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats,
1884 struct sk_buff *skb)
1885{
1886 uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay;
1887
1888 /* There might be no TX info for a peer */
1889 if (!tx_stats)
1890 return 0;
1891
1892 agg_size = tx_stats->mpdu_aggr_size;
1893 succ_mcs = tx_stats->success_mcs;
1894 fail_mcs = tx_stats->fail_mcs;
1895 delay = tx_stats->delay;
1896
1897 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
1898 tx_stats->msdus) ||
1899 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1900 tx_stats->mpdus) ||
1901 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
1902 tx_stats->ppdus) ||
1903 nla_put_u32(skb,
1904 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
1905 tx_stats->bytes) ||
1906 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
1907 tx_stats->drops) ||
1908 nla_put_u32(skb,
1909 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
1910 tx_stats->drop_bytes) ||
1911 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
1912 tx_stats->retries) ||
1913 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
1914 tx_stats->failed) ||
1915 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
1916 tx_stats->aggr_len) ||
1917 nla_put_u32(skb,
1918 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
1919 tx_stats->success_mcs_len) ||
1920 nla_put_u32(skb,
1921 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
1922 tx_stats->fail_mcs_len) ||
1923 nla_put_u32(skb,
1924 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
1925 tx_stats->delay_len))
1926 goto put_attr_fail;
1927
1928 if (agg_size) {
1929 if (nla_put(skb,
1930 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
1931 tx_stats->aggr_len, agg_size))
1932 goto put_attr_fail;
1933 }
1934
1935 if (succ_mcs) {
1936 if (nla_put(skb,
1937 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
1938 tx_stats->success_mcs_len, succ_mcs))
1939 goto put_attr_fail;
1940 }
1941
1942 if (fail_mcs) {
1943 if (nla_put(skb,
1944 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
1945 tx_stats->fail_mcs_len, fail_mcs))
1946 goto put_attr_fail;
1947 }
1948
1949 if (delay) {
1950 if (nla_put(skb,
1951 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
1952 tx_stats->delay_len, delay))
1953 goto put_attr_fail;
1954 }
1955 return 0;
1956
1957put_attr_fail:
1958 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1959 return -EINVAL;
1960}
1961
1962/**
1963 * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info
1964 * @info: rx info
1965 * @skb: vendor event buffer
1966 *
1967 * Return: 0 Success, EINVAL failure
1968 */
1969static int
1970hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats,
1971 struct sk_buff *skb)
1972{
1973 uint32_t *mcs, *aggr;
1974
1975 /* There might be no RX info for a peer */
1976 if (!rx_stats)
1977 return 0;
1978
1979 aggr = rx_stats->mpdu_aggr;
1980 mcs = rx_stats->mcs;
1981
1982 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
1983 rx_stats->mpdus) ||
1984 nla_put_u32(skb,
1985 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
1986 rx_stats->bytes) ||
1987 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
1988 rx_stats->ppdus) ||
1989 nla_put_u32(skb,
1990 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
1991 rx_stats->ppdu_bytes) ||
1992 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
1993 rx_stats->mpdu_lost) ||
1994 nla_put_u32(skb,
1995 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
1996 rx_stats->mpdu_retry) ||
1997 nla_put_u32(skb,
1998 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
1999 rx_stats->mpdu_dup) ||
2000 nla_put_u32(skb,
2001 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
2002 rx_stats->mpdu_discard) ||
2003 nla_put_u32(skb,
2004 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
2005 rx_stats->aggr_len) ||
2006 nla_put_u32(skb,
2007 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
2008 rx_stats->mcs_len))
2009 goto put_attr_fail;
2010
2011 if (aggr) {
2012 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
2013 rx_stats->aggr_len, aggr))
2014 goto put_attr_fail;
2015 }
2016
2017 if (mcs) {
2018 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
2019 rx_stats->mcs_len, mcs))
2020 goto put_attr_fail;
2021 }
2022
2023 return 0;
2024
2025put_attr_fail:
2026 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2027 return -EINVAL;
2028}
2029
2030/**
2031 * hdd_populate_wifi_wmm_ac_info() - put WMM AC info
2032 * @info: per AC stats
2033 * @skb: vendor event buffer
2034 *
2035 * Return: 0 Success, EINVAL failure
2036 */
2037static int
2038hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats,
2039 struct sk_buff *skb)
2040{
2041 struct nlattr *wmm;
2042
2043 wmm = nla_nest_start(skb, ac_stats->type);
2044 if (!wmm)
2045 goto nest_start_fail;
2046
2047 if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) ||
2048 hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb))
2049 goto put_attr_fail;
2050
2051 nla_nest_end(skb, wmm);
2052 return 0;
2053
2054nest_start_fail:
2055 hdd_err("nla_nest_start failed");
2056 return -EINVAL;
2057
2058put_attr_fail:
2059 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2060 return -EINVAL;
2061}
2062
2063/**
2064 * hdd_populate_wifi_ll_ext_peer_info() - put per peer info
2065 * @info: peer stats
2066 * @skb: vendor event buffer
2067 *
2068 * Return: 0 Success, EINVAL failure
2069 */
2070static int
2071hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers,
2072 struct sk_buff *skb)
2073{
2074 uint32_t i;
2075 struct nlattr *wmm_ac;
2076
2077 if (nla_put_u32(skb,
2078 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
2079 peers->peer_id) ||
2080 nla_put_u32(skb,
2081 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
2082 peers->vdev_id) ||
2083 nla_put_u32(skb,
2084 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
2085 peers->sta_ps_inds) ||
2086 nla_put_u32(skb,
2087 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
2088 peers->sta_ps_durs) ||
2089 nla_put_u32(skb,
2090 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
2091 peers->rx_probe_reqs) ||
2092 nla_put_u32(skb,
2093 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
2094 peers->rx_oth_mgmts) ||
2095 nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
2096 QDF_MAC_ADDR_SIZE, peers->mac_address) ||
2097 hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) {
2098 hdd_err("put peer signal attr failed");
2099 return -EINVAL;
2100 }
2101
2102 wmm_ac = nla_nest_start(skb,
2103 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS);
2104 if (!wmm_ac) {
2105 hdd_err("nla_nest_start failed");
2106 return -EINVAL;
2107 }
2108
2109 for (i = 0; i < WLAN_MAX_AC; i++) {
2110 if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) {
2111 hdd_err("put WMM AC attr failed");
2112 return -EINVAL;
2113 }
2114 }
2115
2116 nla_nest_end(skb, wmm_ac);
2117 return 0;
2118}
2119
2120/**
2121 * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats
2122 * @info: link layer stats
2123 * @skb: vendor event buffer
2124 *
2125 * Return: 0 Success, EINVAL failure
2126 */
2127static int
2128hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats,
2129 struct sk_buff *skb)
2130{
2131 uint32_t i;
2132 struct nlattr *peer, *peer_info, *channels, *channel_info;
2133
2134 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
2135 stats->trigger_cond_id) ||
2136 nla_put_u32(skb,
2137 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
2138 stats->cca_chgd_bitmap) ||
2139 nla_put_u32(skb,
2140 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
2141 stats->sig_chgd_bitmap) ||
2142 nla_put_u32(skb,
2143 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
2144 stats->tx_chgd_bitmap) ||
2145 nla_put_u32(skb,
2146 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
2147 stats->rx_chgd_bitmap) ||
2148 nla_put_u32(skb,
2149 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
2150 stats->channel_num) ||
2151 nla_put_u32(skb,
2152 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
2153 stats->peer_num)) {
2154 goto put_attr_fail;
2155 }
2156
2157 channels = nla_nest_start(skb,
2158 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS);
2159 if (!channels) {
2160 hdd_err("nla_nest_start failed");
2161 return -EINVAL;
2162 }
2163
2164 for (i = 0; i < stats->channel_num; i++) {
2165 channel_info = nla_nest_start(skb, i);
2166 if (!channel_info) {
2167 hdd_err("nla_nest_start failed");
2168 return -EINVAL;
2169 }
2170
2171 if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb))
2172 goto put_attr_fail;
2173 nla_nest_end(skb, channel_info);
2174 }
2175 nla_nest_end(skb, channels);
2176
2177 peer_info = nla_nest_start(skb,
2178 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER);
2179 if (!peer_info) {
2180 hdd_err("nla_nest_start failed");
2181 return -EINVAL;
2182 }
2183
2184 for (i = 0; i < stats->peer_num; i++) {
2185 peer = nla_nest_start(skb, i);
2186 if (!peer) {
2187 hdd_err("nla_nest_start failed");
2188 return -EINVAL;
2189 }
2190
2191 if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i],
2192 skb))
2193 goto put_attr_fail;
2194 nla_nest_end(skb, peer);
2195 }
2196
2197 nla_nest_end(skb, peer_info);
2198 return 0;
2199
2200put_attr_fail:
2201 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2202 return -EINVAL;
2203}
2204
2205/**
Zhang Qianca38fb12016-12-23 11:10:48 +08002206 * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
2207 * @ctx: HDD context
2208 * @rsp: msg from FW
2209 *
2210 * This function is an extension of
2211 * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
2212 * monitoring parameters offloaded to NL data and send the same to the
2213 * kernel/upper layers.
2214 *
2215 * Return: None
2216 */
2217void wlan_hdd_cfg80211_link_layer_stats_ext_callback(tHddHandle ctx,
2218 tSirLLStatsResults *rsp)
2219{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002220 struct hdd_context *hdd_ctx;
Zhang Qianca38fb12016-12-23 11:10:48 +08002221 struct sk_buff *skb = NULL;
2222 uint32_t param_id, index;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07002223 struct hdd_adapter *adapter = NULL;
Zhang Qianca38fb12016-12-23 11:10:48 +08002224 tSirLLStatsResults *linkLayer_stats_results;
2225 tSirWifiPeerStat *peer_stats;
2226 uint8_t *results;
2227 int status;
2228
2229 ENTER();
2230
2231 if (!ctx) {
2232 hdd_err("Invalid HDD context.");
2233 return;
2234 }
2235
2236 if (!rsp) {
2237 hdd_err("Invalid result.");
2238 return;
2239 }
2240
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002241 hdd_ctx = (struct hdd_context *)ctx;
Zhang Qianca38fb12016-12-23 11:10:48 +08002242 linkLayer_stats_results = rsp;
2243
2244 status = wlan_hdd_validate_context(hdd_ctx);
2245 if (0 != status)
2246 return;
2247
2248 adapter = hdd_get_adapter_by_vdev(hdd_ctx,
2249 linkLayer_stats_results->ifaceId);
2250
Zhang Qian4ead8f02017-03-27 14:21:47 +08002251 if (!adapter) {
Zhang Qianca38fb12016-12-23 11:10:48 +08002252 hdd_err("vdev_id %d does not exist with host.",
2253 linkLayer_stats_results->ifaceId);
2254 return;
2255 }
2256
2257 index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
2258 skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2259 NULL, LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
2260 index, GFP_KERNEL);
2261 if (!skb) {
2262 hdd_err("cfg80211_vendor_event_alloc failed.");
2263 return;
2264 }
2265
2266 results = linkLayer_stats_results->results;
2267 param_id = linkLayer_stats_results->paramId;
Jeff Johnson36e74c42017-09-18 08:15:42 -07002268 hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %pK",
Zhang Qianca38fb12016-12-23 11:10:48 +08002269 linkLayer_stats_results->paramId,
2270 linkLayer_stats_results->ifaceId,
2271 linkLayer_stats_results->results);
2272 if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
2273 peer_stats = (tSirWifiPeerStat *)results;
2274 status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
2275 } else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
2276 struct sir_wifi_iface_tx_fail *tx_fail;
2277
2278 tx_fail = (struct sir_wifi_iface_tx_fail *)results;
2279 status = hdd_populate_tx_failure_info(tx_fail, skb);
2280 } else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
2281 hdd_info("MAC counters stats");
Zhang Qian4ead8f02017-03-27 14:21:47 +08002282 status = hdd_populate_wifi_ll_ext_stats(
2283 (struct sir_wifi_ll_ext_stats *)
2284 rsp->results, skb);
Zhang Qianca38fb12016-12-23 11:10:48 +08002285 } else {
2286 hdd_info("Unknown link layer stats");
2287 status = -EINVAL;
2288 }
2289
2290 if (status == 0)
2291 cfg80211_vendor_event(skb, GFP_KERNEL);
2292 else
2293 kfree_skb(skb);
2294 EXIT();
2295}
2296
Zhang Qian4ead8f02017-03-27 14:21:47 +08002297static const struct nla_policy
2298qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = {
2299 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = {
2300 .type = NLA_U32
2301 },
2302 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = {
2303 .type = NLA_U32
2304 },
2305 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = {
2306 .type = NLA_U32
2307 },
2308 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = {
2309 .type = NLA_U32
2310 },
2311 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = {
2312 .type = NLA_U32
2313 },
2314 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = {
2315 .type = NLA_U32
2316 },
2317 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = {
2318 .type = NLA_U32
2319 },
2320 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = {
2321 .type = NLA_U32
2322 },
2323 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = {
2324 .type = NLA_U32
2325 },
2326 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = {
2327 .type = NLA_U32
2328 },
2329 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = {
2330 .type = NLA_U32
2331 },
2332 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = {
2333 .type = NLA_U32
2334 },
2335 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = {
2336 .type = NLA_U32
2337 },
2338 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = {
2339 .type = NLA_U32
2340 },
2341 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = {
2342 .type = NLA_U32
2343 },
2344 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = {
2345 .type = NLA_U32
2346 },
2347 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = {
2348 .type = NLA_U32
2349 },
2350 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = {
2351 .type = NLA_U32
2352 },
2353 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = {
2354 .type = NLA_U32
2355 },
2356 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = {
2357 .type = NLA_U32
2358 },
2359 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = {
2360 .type = NLA_U32
2361 },
2362 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = {
2363 .type = NLA_U32
2364 },
2365 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = {
2366 .type = NLA_U32
2367 },
2368 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = {
2369 .type = NLA_U32
2370 },
2371 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = {
2372 .type = NLA_U32
2373 },
2374 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = {
2375 .type = NLA_U32
2376 },
2377 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = {
2378 .type = NLA_U32
2379 },
2380 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = {
2381 .type = NLA_U32
2382 },
2383 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = {
2384 .type = NLA_U32
2385 },
2386 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = {
2387 .type = NLA_U32
2388 },
2389 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = {
2390 .type = NLA_U32
2391 },
2392 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = {
2393 .type = NLA_U32
2394 },
2395 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = {
2396 .type = NLA_U32
2397 },
2398 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = {
2399 .type = NLA_U32
2400 },
2401 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = {
2402 .type = NLA_U32
2403 },
2404 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = {
2405 .type = NLA_U32
2406 },
2407 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = {
2408 .type = NLA_U32
2409 },
2410 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = {
2411 .type = NLA_U32
2412 },
2413 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = {
2414 .type = NLA_U32
2415 },
2416 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = {
2417 .type = NLA_U32
2418 },
2419 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = {
2420 .type = NLA_U32
2421 },
2422 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = {
2423 .type = NLA_U32
2424 },
2425 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = {
2426 .type = NLA_U32
2427 },
2428 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = {
2429 .type = NLA_U32
2430 },
2431};
2432
2433/**
2434 * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2435 * @wiphy: wiphy handle
2436 * @wdev: wdev handle
2437 * @data: user layer input
2438 * @data_len: length of user layer input
2439 *
2440 * this function is called in ssr protected environment.
2441 *
2442 * return: 0 success, none zero for failure
2443 */
2444static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2445 struct wireless_dev *wdev,
2446 const void *data,
2447 int data_len)
2448{
2449 int status;
2450 uint32_t period;
2451 struct net_device *dev = wdev->netdev;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07002452 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002453 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Zhang Qian4ead8f02017-03-27 14:21:47 +08002454 struct sir_ll_ext_stats_threshold thresh = {0,};
2455 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1];
2456
2457 ENTER_DEV(dev);
2458
2459 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2460 hdd_warn("command not allowed in ftm mode");
2461 return -EPERM;
2462 }
2463
2464 status = wlan_hdd_validate_context(hdd_ctx);
2465 if (0 != status)
2466 return -EPERM;
2467
Dustin Brown4ea21db2018-01-05 14:13:17 -08002468 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX,
2469 (struct nlattr *)data, data_len,
2470 qca_wlan_vendor_ll_ext_policy)) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08002471 hdd_err("maximum attribute not present");
2472 return -EPERM;
2473 }
2474
2475 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) {
2476 period = nla_get_u32(tb[
2477 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]);
2478
2479 if (period != 0 && period < LL_STATS_MIN_PERIOD)
2480 period = LL_STATS_MIN_PERIOD;
2481
2482 /*
2483 * Only enable/disbale counters.
2484 * Keep the last threshold settings.
2485 */
2486 goto set_period;
2487 }
2488
2489 /* global thresh is not enabled */
2490 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) {
2491 thresh.global = false;
2492 hdd_warn("global thresh is not set");
2493 } else {
2494 thresh.global_threshold = nla_get_u32(tb[
2495 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]);
2496 thresh.global = true;
2497 hdd_debug("globle thresh is %d", thresh.global_threshold);
2498 }
2499
2500 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) {
2501 thresh.global = false;
2502 hdd_warn("global thresh is not enabled");
2503 } else {
2504 thresh.global = nla_get_u32(tb[
2505 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]);
2506 hdd_debug("global is %d", thresh.global);
2507 }
2508
2509 thresh.enable_bitmap = false;
2510 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) {
2511 thresh.tx_bitmap = nla_get_u32(tb[
2512 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]);
2513 thresh.enable_bitmap = true;
2514 }
2515
2516 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) {
2517 thresh.rx_bitmap = nla_get_u32(tb[
2518 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]);
2519 thresh.enable_bitmap = true;
2520 }
2521
2522 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) {
2523 thresh.cca_bitmap = nla_get_u32(tb[
2524 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]);
2525 thresh.enable_bitmap = true;
2526 }
2527
2528 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) {
2529 thresh.signal_bitmap = nla_get_u32(tb[
2530 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]);
2531 thresh.enable_bitmap = true;
2532 }
2533
2534 if (!thresh.global && !thresh.enable_bitmap) {
2535 hdd_warn("threshold will be disabled.");
2536 thresh.enable = false;
2537
2538 /* Just disable threshold */
2539 goto set_thresh;
2540 } else {
2541 thresh.enable = true;
2542 }
2543
2544 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) {
2545 thresh.tx.msdu = nla_get_u32(tb[
2546 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]);
2547 }
2548
2549 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) {
2550 thresh.tx.mpdu = nla_get_u32(tb[
2551 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]);
2552 }
2553
2554 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) {
2555 thresh.tx.ppdu = nla_get_u32(tb[
2556 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]);
2557 }
2558
2559 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) {
2560 thresh.tx.bytes = nla_get_u32(tb[
2561 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]);
2562 }
2563
2564 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) {
2565 thresh.tx.msdu_drop = nla_get_u32(
2566 tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]);
2567 }
2568
2569 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) {
2570 thresh.tx.byte_drop = nla_get_u32(tb[
2571 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]);
2572 }
2573
2574 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) {
2575 thresh.tx.mpdu_retry = nla_get_u32(tb[
2576 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]);
2577 }
2578
2579 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) {
2580 thresh.tx.mpdu_fail = nla_get_u32(tb[
2581 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]);
2582 }
2583
2584 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) {
2585 thresh.tx.ppdu_fail = nla_get_u32(tb[
2586 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]);
2587 }
2588
2589 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) {
2590 thresh.tx.aggregation = nla_get_u32(tb[
2591 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]);
2592 }
2593
2594 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) {
2595 thresh.tx.succ_mcs = nla_get_u32(tb[
2596 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]);
2597 }
2598
2599 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) {
2600 thresh.tx.fail_mcs = nla_get_u32(tb[
2601 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]);
2602 }
2603
2604 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) {
2605 thresh.tx.delay = nla_get_u32(tb[
2606 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]);
2607 }
2608
2609 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) {
2610 thresh.rx.mpdu = nla_get_u32(tb[
2611 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]);
2612 }
2613
2614 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) {
2615 thresh.rx.bytes = nla_get_u32(tb[
2616 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]);
2617 }
2618
2619 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) {
2620 thresh.rx.ppdu = nla_get_u32(tb[
2621 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]);
2622 }
2623
2624 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) {
2625 thresh.rx.ppdu_bytes = nla_get_u32(tb[
2626 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]);
2627 }
2628
2629 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) {
2630 thresh.rx.mpdu_lost = nla_get_u32(tb[
2631 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]);
2632 }
2633
2634 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) {
2635 thresh.rx.mpdu_retry = nla_get_u32(tb[
2636 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]);
2637 }
2638
2639 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) {
2640 thresh.rx.mpdu_dup = nla_get_u32(tb[
2641 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]);
2642 }
2643
2644 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) {
2645 thresh.rx.mpdu_discard = nla_get_u32(tb[
2646 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]);
2647 }
2648
2649 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) {
2650 thresh.rx.aggregation = nla_get_u32(tb[
2651 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]);
2652 }
2653
2654 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) {
2655 thresh.rx.mcs = nla_get_u32(tb[
2656 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]);
2657 }
2658
2659 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) {
2660 thresh.rx.ps_inds = nla_get_u32(tb[
2661 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]);
2662 }
2663
2664 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) {
2665 thresh.rx.ps_durs = nla_get_u32(tb[
2666 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]);
2667 }
2668
2669 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) {
2670 thresh.rx.probe_reqs = nla_get_u32(tb[
2671 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]);
2672 }
2673
2674 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) {
2675 thresh.rx.other_mgmt = nla_get_u32(tb[
2676 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]);
2677 }
2678
2679 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) {
2680 thresh.cca.idle_time = nla_get_u32(tb[
2681 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]);
2682 }
2683
2684 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) {
2685 thresh.cca.tx_time = nla_get_u32(tb[
2686 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]);
2687 }
2688
2689 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) {
2690 thresh.cca.rx_in_bss_time = nla_get_u32(tb[
2691 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]);
2692 }
2693
2694 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) {
2695 thresh.cca.rx_out_bss_time = nla_get_u32(tb[
2696 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]);
2697 }
2698
2699 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) {
2700 thresh.cca.rx_busy_time = nla_get_u32(tb[
2701 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]);
2702 }
2703
2704 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) {
2705 thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[
2706 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]);
2707 }
2708
2709 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) {
2710 thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[
2711 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]);
2712 }
2713
2714 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) {
2715 thresh.cca.wlan_not_avail_time = nla_get_u32(tb[
2716 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]);
2717 }
2718
2719 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) {
2720 thresh.signal.snr = nla_get_u32(tb[
2721 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]);
2722 }
2723
2724 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) {
2725 thresh.signal.nf = nla_get_u32(tb[
2726 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]);
2727 }
2728
2729set_thresh:
2730 hdd_info("send thresh settings to target");
2731 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_thresh(hdd_ctx->hHal,
2732 &thresh)) {
2733 hdd_err("sme_ll_stats_set_thresh failed.");
2734 return -EINVAL;
2735 }
2736 return 0;
2737
2738set_period:
2739 hdd_info("send period to target");
Jeff Johnson1b780e42017-10-31 14:11:45 -07002740 status = wma_cli_set_command(adapter->session_id,
Zhang Qian4ead8f02017-03-27 14:21:47 +08002741 WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD,
2742 period, PDEV_CMD);
2743 if (status) {
2744 hdd_err("wma_cli_set_command set_period failed.");
2745 return -EINVAL;
2746 }
2747 return 0;
2748}
2749
2750/**
2751 * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2752 * @wiphy: wiphy handle
2753 * @wdev: wdev handle
2754 * @data: user layer input
2755 * @data_len: length of user layer input
2756 *
2757 * return: 0 success, einval failure
2758 */
2759int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2760 struct wireless_dev *wdev,
2761 const void *data,
2762 int data_len)
2763{
2764 int ret;
2765
2766 cds_ssr_protect(__func__);
2767 ret = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev,
2768 data, data_len);
2769 cds_ssr_unprotect(__func__);
2770
2771 return ret;
2772}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002773#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
2774
2775#ifdef WLAN_FEATURE_STATS_EXT
2776/**
2777 * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2778 * @wiphy: Pointer to wiphy
2779 * @wdev: Pointer to wdev
2780 * @data: Pointer to data
2781 * @data_len: Data length
2782 *
2783 * Return: int
2784 */
2785static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2786 struct wireless_dev *wdev,
2787 const void *data,
2788 int data_len)
2789{
2790 tStatsExtRequestReq stats_ext_req;
2791 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002792 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002793 int ret_val;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302794 QDF_STATUS status;
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002795 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002796
Jeff Johnson1f61b612016-02-12 16:28:33 -08002797 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002798
2799 ret_val = wlan_hdd_validate_context(hdd_ctx);
2800 if (ret_val)
2801 return ret_val;
2802
Anurag Chouhan6d760662016-02-20 16:05:43 +05302803 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002804 hdd_err("Command not allowed in FTM mode");
2805 return -EPERM;
2806 }
2807
2808 stats_ext_req.request_data_len = data_len;
2809 stats_ext_req.request_data = (void *)data;
2810
Jeff Johnson1b780e42017-10-31 14:11:45 -07002811 status = sme_stats_ext_request(adapter->session_id, &stats_ext_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002812
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302813 if (QDF_STATUS_SUCCESS != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002814 ret_val = -EINVAL;
2815
2816 return ret_val;
2817}
2818
2819/**
2820 * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2821 * @wiphy: Pointer to wiphy
2822 * @wdev: Pointer to wdev
2823 * @data: Pointer to data
2824 * @data_len: Data length
2825 *
2826 * Return: int
2827 */
2828int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2829 struct wireless_dev *wdev,
2830 const void *data,
2831 int data_len)
2832{
2833 int ret;
2834
2835 cds_ssr_protect(__func__);
2836 ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
2837 data, data_len);
2838 cds_ssr_unprotect(__func__);
2839
2840 return ret;
2841}
2842
2843/**
2844 * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback
2845 * @ctx: Pointer to HDD context
2846 * @msg: Message received
2847 *
2848 * Return: nothing
2849 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05302850void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002851 tStatsExtEvent *msg)
2852{
2853
Jeff Johnsonf645abf2017-09-03 09:07:46 -07002854 struct hdd_context *hdd_ctx = (struct hdd_context *) ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002855 struct sk_buff *vendor_event;
2856 int status;
2857 int ret_val;
2858 tStatsExtEvent *data = msg;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002859 struct hdd_adapter *adapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002860
Jeff Johnsonf645abf2017-09-03 09:07:46 -07002861 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302862 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002863 return;
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302864
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002865 adapter = hdd_get_adapter_by_vdev(hdd_ctx, data->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002866
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002867 if (NULL == adapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002868 hdd_err("vdev_id %d does not exist with host", data->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002869 return;
2870 }
2871
Jeff Johnsonf645abf2017-09-03 09:07:46 -07002872 vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002873 NULL,
2874 data->event_data_len +
2875 sizeof(uint32_t) +
2876 NLMSG_HDRLEN + NLMSG_HDRLEN,
2877 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2878 GFP_KERNEL);
2879
2880 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002881 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002882 return;
2883 }
2884
2885 ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002886 adapter->dev->ifindex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002887 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002888 hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002889 kfree_skb(vendor_event);
2890
2891 return;
2892 }
2893
2894 ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
2895 data->event_data_len, data->event_data);
2896
2897 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002898 hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002899 kfree_skb(vendor_event);
2900
2901 return;
2902 }
2903
2904 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2905
2906}
lifeng66831662017-05-19 16:01:35 +08002907
2908void wlan_hdd_cfg80211_stats_ext2_callback(void *ctx,
2909 struct sir_sme_rx_aggr_hole_ind *pmsg)
2910{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002911 struct hdd_context *hdd_ctx = (struct hdd_context *)ctx;
lifeng66831662017-05-19 16:01:35 +08002912 int status;
2913 uint32_t data_size, hole_info_size;
2914 struct sk_buff *vendor_event;
2915
2916 status = wlan_hdd_validate_context(hdd_ctx);
2917 if (0 != status)
2918 return;
2919
2920 if (NULL == pmsg) {
2921 hdd_err("msg received here is null");
2922 return;
2923 }
2924
2925 hole_info_size = (pmsg->hole_cnt)*sizeof(pmsg->hole_info_array[0]);
2926 data_size = sizeof(struct sir_sme_rx_aggr_hole_ind) + hole_info_size;
2927
2928 vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2929 NULL,
2930 data_size + NLMSG_HDRLEN + NLMSG_HDRLEN,
2931 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2932 GFP_KERNEL);
2933
2934 if (!vendor_event) {
2935 hdd_err("vendor_event_alloc failed for STATS_EXT2");
2936 return;
2937 }
2938
2939 if (nla_put_u32(vendor_event,
2940 QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM,
2941 pmsg->hole_cnt)) {
2942 hdd_err("%s put fail",
2943 "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM");
2944 kfree_skb(vendor_event);
2945 return;
2946 }
2947 if (nla_put(vendor_event,
2948 QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO,
2949 hole_info_size,
2950 (void *)(pmsg->hole_info_array))) {
2951 hdd_err("%s put fail",
2952 "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO");
2953 kfree_skb(vendor_event);
2954 return;
2955 }
2956
2957 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2958}
2959
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002960#endif /* End of WLAN_FEATURE_STATS_EXT */
2961
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05302962#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
2963static inline void wlan_hdd_fill_station_info_signal(struct station_info
2964 *sinfo)
2965{
2966 sinfo->filled |= STATION_INFO_SIGNAL;
2967}
2968#else
2969static inline void wlan_hdd_fill_station_info_signal(struct station_info
2970 *sinfo)
2971{
2972 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2973}
2974#endif
2975
Dustin Brown32cb4792017-06-15 15:33:42 -07002976#ifdef LINKSPEED_DEBUG_ENABLED
2977#define linkspeed_dbg(format, args...) pr_info(format, ## args)
2978#else
2979#define linkspeed_dbg(format, args...)
2980#endif /* LINKSPEED_DEBUG_ENABLED */
2981
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002982/**
Dustin Brown0e4479e2017-07-14 14:47:39 -07002983 * wlan_hdd_fill_summary_stats() - populate station_info summary stats
2984 * @stats: summary stats to use as a source
2985 * @info: kernel station_info struct to use as a destination
2986 *
2987 * Return: None
2988 */
2989static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
2990 struct station_info *info)
2991{
2992 int i;
2993
2994 info->rx_packets = stats->rx_frm_cnt;
2995 info->tx_packets = 0;
2996 info->tx_retries = 0;
2997 info->tx_failed = 0;
2998
2999 for (i = 0; i < WIFI_MAX_AC; ++i) {
3000 info->tx_packets += stats->tx_frm_cnt[i];
3001 info->tx_retries += stats->multiple_retry_cnt[i];
3002 info->tx_failed += stats->fail_cnt[i];
3003 }
3004
3005#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
3006 info->filled |= STATION_INFO_TX_PACKETS |
3007 STATION_INFO_TX_RETRIES |
3008 STATION_INFO_TX_FAILED |
3009 STATION_INFO_RX_PACKETS;
3010#else
3011 info->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
3012 BIT(NL80211_STA_INFO_TX_PACKETS) |
3013 BIT(NL80211_STA_INFO_TX_RETRIES) |
3014 BIT(NL80211_STA_INFO_TX_FAILED);
3015#endif
3016}
3017
3018/**
3019 * wlan_hdd_get_sap_stats() - get aggregate SAP stats
3020 * @adapter: sap adapter to get stats for
3021 * @info: kernel station_info struct to populate
3022 *
3023 * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to
3024 * support "station dump" and "station get" for SAP vdevs, even though they
3025 * aren't technically stations.
3026 *
3027 * Return: errno
3028 */
3029static int
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003030wlan_hdd_get_sap_stats(struct hdd_adapter *adapter, struct station_info *info)
Dustin Brown0e4479e2017-07-14 14:47:39 -07003031{
3032 QDF_STATUS status;
3033
3034 status = wlan_hdd_get_station_stats(adapter);
3035 if (QDF_IS_STATUS_ERROR(status)) {
3036 hdd_err("Failed to get SAP stats; status:%d", status);
3037 return qdf_status_to_os_return(status);
3038 }
3039
3040 wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, info);
3041
3042 return 0;
3043}
3044
3045/**
Will Huang496b36c2017-07-11 16:38:50 +08003046 * hdd_get_max_rate_legacy() - get max rate for legacy mode
3047 * @stainfo: stainfo pointer
3048 * @rssidx: rssi index
3049 *
3050 * This function will get max rate for legacy mode
3051 *
3052 * Return: max rate on success, otherwise 0
3053 */
Jeff Johnson82155922017-09-30 16:54:14 -07003054static uint32_t hdd_get_max_rate_legacy(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003055 uint8_t rssidx)
3056{
3057 uint32_t maxrate = 0;
3058 /*Minimum max rate, 6Mbps*/
3059 int maxidx = 12;
3060 int i;
3061
3062 /* check supported rates */
3063 if (stainfo->max_supp_idx != 0xff &&
3064 maxidx < stainfo->max_supp_idx)
3065 maxidx = stainfo->max_supp_idx;
3066
3067 /* check extended rates */
3068 if (stainfo->max_ext_idx != 0xff &&
3069 maxidx < stainfo->max_ext_idx)
3070 maxidx = stainfo->max_ext_idx;
3071
3072 for (i = 0; QDF_ARRAY_SIZE(supported_data_rate); i++) {
3073 if (supported_data_rate[i].beacon_rate_index == maxidx)
3074 maxrate =
3075 supported_data_rate[i].supported_rate[rssidx];
3076 }
3077
3078 hdd_debug("maxrate %d", maxrate);
3079
3080 return maxrate;
3081}
3082
3083/**
3084 * hdd_get_max_rate_ht() - get max rate for ht mode
3085 * @stainfo: stainfo pointer
3086 * @stats: fw txrx status pointer
3087 * @rate_flags: rate flags
3088 * @nss: number of streams
3089 * @maxrate: returned max rate buffer pointer
3090 * @max_mcs_idx: max mcs idx
3091 * @report_max: report max rate or actual rate
3092 *
3093 * This function will get max rate for ht mode
3094 *
3095 * Return: None
3096 */
Jeff Johnson82155922017-09-30 16:54:14 -07003097static void hdd_get_max_rate_ht(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003098 struct hdd_fw_txrx_stats *stats,
3099 uint32_t rate_flags,
3100 uint8_t nss,
3101 uint32_t *maxrate,
3102 uint8_t *max_mcs_idx,
3103 bool report_max)
3104{
3105 struct index_data_rate_type *supported_mcs_rate;
3106 uint32_t tmprate;
3107 uint8_t flag = 0, mcsidx;
3108 int8_t rssi = stats->rssi;
3109 int mode;
3110 int i;
3111
3112 if (rate_flags & eHAL_TX_RATE_HT40)
3113 mode = 1;
3114 else
3115 mode = 0;
3116
3117 if (rate_flags & eHAL_TX_RATE_HT40)
3118 flag |= 1;
3119 if (rate_flags & eHAL_TX_RATE_SGI)
3120 flag |= 2;
3121
3122 supported_mcs_rate = (struct index_data_rate_type *)
3123 ((nss == 1) ? &supported_mcs_rate_nss1 :
3124 &supported_mcs_rate_nss2);
3125
3126 if (stainfo->max_mcs_idx == 0xff) {
3127 hdd_err("invalid max_mcs_idx");
3128 /* report real mcs idx */
3129 mcsidx = stats->tx_rate.mcs;
3130 } else {
3131 mcsidx = stainfo->max_mcs_idx;
3132 }
3133
3134 if (!report_max) {
3135 for (i = 0; i < mcsidx; i++) {
3136 if (rssi <= rssi_mcs_tbl[mode][i]) {
3137 mcsidx = i;
3138 break;
3139 }
3140 }
3141 if (mcsidx < stats->tx_rate.mcs)
3142 mcsidx = stats->tx_rate.mcs;
3143 }
3144
3145 tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
3146
3147 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3148
3149 *maxrate = tmprate;
3150 *max_mcs_idx = mcsidx;
3151}
3152
3153/**
3154 * hdd_get_max_rate_vht() - get max rate for vht mode
3155 * @stainfo: stainfo pointer
3156 * @stats: fw txrx status pointer
3157 * @rate_flags: rate flags
3158 * @nss: number of streams
3159 * @maxrate: returned max rate buffer pointer
3160 * @max_mcs_idx: max mcs idx
3161 * @report_max: report max rate or actual rate
3162 *
3163 * This function will get max rate for vht mode
3164 *
3165 * Return: None
3166 */
Jeff Johnson82155922017-09-30 16:54:14 -07003167static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003168 struct hdd_fw_txrx_stats *stats,
3169 uint32_t rate_flags,
3170 uint8_t nss,
3171 uint32_t *maxrate,
3172 uint8_t *max_mcs_idx,
3173 bool report_max)
3174{
3175 struct index_vht_data_rate_type *supported_vht_mcs_rate;
3176 uint32_t tmprate = 0;
3177 uint32_t vht_max_mcs;
3178 uint8_t flag = 0, mcsidx = INVALID_MCS_IDX;
3179 int8_t rssi = stats->rssi;
3180 int mode;
3181 int i;
3182
3183 supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
3184 ((nss == 1) ?
3185 &supported_vht_mcs_rate_nss1 :
3186 &supported_vht_mcs_rate_nss2);
3187
3188 if (rate_flags & eHAL_TX_RATE_VHT80)
3189 mode = 2;
3190 else if (rate_flags & eHAL_TX_RATE_VHT40)
3191 mode = 1;
3192 else
3193 mode = 0;
3194
3195 if (rate_flags &
3196 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 | eHAL_TX_RATE_VHT80)) {
3197 vht_max_mcs =
3198 (enum data_rate_11ac_max_mcs)
3199 (stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK);
3200 if (rate_flags & eHAL_TX_RATE_SGI)
3201 flag |= 1;
3202
3203 if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) {
3204 mcsidx = 7;
3205 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) {
3206 mcsidx = 8;
3207 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) {
3208 /*
3209 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3210 * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6
3211 * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8
3212 */
3213 if ((rate_flags & eHAL_TX_RATE_VHT20) &&
3214 (nss != 3 && nss != 6))
3215 mcsidx = 8;
3216 else
3217 mcsidx = 9;
3218 } else {
3219 hdd_err("invalid vht_max_mcs");
3220 /* report real mcs idx */
3221 mcsidx = stats->tx_rate.mcs;
3222 }
3223
3224 if (!report_max) {
3225 for (i = 0; i <= mcsidx; i++) {
3226 if (rssi <= rssi_mcs_tbl[mode][i]) {
3227 mcsidx = i;
3228 break;
3229 }
3230 }
3231 if (mcsidx < stats->tx_rate.mcs)
3232 mcsidx = stats->tx_rate.mcs;
3233 }
3234
3235 if (rate_flags & eHAL_TX_RATE_VHT80)
3236 tmprate =
3237 supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag];
3238 else if (rate_flags & eHAL_TX_RATE_VHT40)
3239 tmprate =
3240 supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag];
3241 else if (rate_flags & eHAL_TX_RATE_VHT20)
3242 tmprate =
3243 supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag];
3244 }
3245
3246 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3247
3248 *maxrate = tmprate;
3249 *max_mcs_idx = mcsidx;
3250}
3251
3252#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
3253/**
3254 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3255 * @stainfo: stainfo pointer
3256 * @rate_flags: HDD rate flags
3257 * @mcsidx: mcs index
3258 * @nss: number of streams
3259 * @vht: vht mode or not
3260 *
3261 * This function will fill ch width and mcs flags
3262 *
3263 * Return: None
3264 */
3265static void hdd_fill_bw_mcs(struct station_info *sinfo,
3266 uint8_t rate_flags,
3267 uint8_t mcsidx,
3268 uint8_t nss,
3269 bool vht)
3270{
3271 if (vht) {
3272 sinfo->txrate.nss = nss;
3273 sinfo->txrate.mcs = mcsidx;
3274 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3275 if (rate_flags & eHAL_TX_RATE_VHT80)
3276 sinfo->txrate.bw = RATE_INFO_BW_80;
3277 else if (rate_flags & eHAL_TX_RATE_VHT40)
3278 sinfo->txrate.bw = RATE_INFO_BW_40;
3279 else if (rate_flags & eHAL_TX_RATE_VHT20)
3280 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3281 } else {
3282 sinfo->txrate.mcs = (nss - 1) << 3;
3283 sinfo->txrate.mcs |= mcsidx;
3284 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3285 if (rate_flags & eHAL_TX_RATE_HT40)
3286 sinfo->txrate.bw = RATE_INFO_BW_40;
3287 }
3288}
3289#else
3290/**
3291 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3292 * @stainfo: stainfo pointer
3293 * @rate_flags: HDD rate flags
3294 * @mcsidx: mcs index
3295 * @nss: number of streams
3296 * @vht: vht mode or not
3297 *
3298 * This function will fill ch width and mcs flags
3299 *
3300 * Return: None
3301 */
3302static void hdd_fill_bw_mcs(struct station_info *sinfo,
3303 uint8_t rate_flags,
3304 uint8_t mcsidx,
3305 uint8_t nss,
3306 bool vht)
3307{
3308 if (vht) {
3309 sinfo->txrate.nss = nss;
3310 sinfo->txrate.mcs = mcsidx;
3311 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3312 if (rate_flags & eHAL_TX_RATE_VHT80)
3313 sinfo->txrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
3314 else if (rate_flags & eHAL_TX_RATE_VHT40)
3315 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
3316 else if (rate_flags & eHAL_TX_RATE_VHT20)
3317 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3318 } else {
3319 sinfo->txrate.mcs = (nss - 1) << 3;
3320 sinfo->txrate.mcs |= mcsidx;
3321 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3322 if (rate_flags & eHAL_TX_RATE_HT40)
3323 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
3324 }
3325}
3326#endif
3327
3328/**
3329 * hdd_fill_bw_mcs_vht() - fill ch width and mcs flags for VHT mode
3330 * @stainfo: stainfo pointer
3331 * @rate_flags: HDD rate flags
3332 * @mcsidx: mcs index
3333 * @nss: number of streams
3334 *
3335 * This function will fill ch width and mcs flags for VHT mode
3336 *
3337 * Return: None
3338 */
3339static void hdd_fill_bw_mcs_vht(struct station_info *sinfo,
3340 uint8_t rate_flags,
3341 uint8_t mcsidx,
3342 uint8_t nss)
3343{
3344 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, true);
3345}
3346
3347/**
3348 * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
3349 * @sinfo: station_info struct pointer
3350 * @rate_flags: HDD rate flags
3351 * @mcsidx: mcs index
3352 * @nss: number of streams
3353 * @maxrate: data rate (kbps)
3354 *
3355 * This function will fill rate info of sinfo struct
3356 *
3357 * Return: None
3358 */
3359static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
3360 uint32_t rate_flags,
3361 uint8_t mcsidx,
3362 uint8_t nss,
3363 uint32_t maxrate)
3364{
3365 if (rate_flags & eHAL_TX_RATE_LEGACY) {
3366 /* provide to the UI in units of 100kbps */
3367 sinfo->txrate.legacy = maxrate;
3368 } else {
3369 /* must be MCS */
3370 if (rate_flags &
3371 (eHAL_TX_RATE_VHT80 |
3372 eHAL_TX_RATE_VHT40 |
3373 eHAL_TX_RATE_VHT20))
3374 hdd_fill_bw_mcs_vht(sinfo, rate_flags, mcsidx, nss);
3375
3376 if (rate_flags & (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40))
3377 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, false);
3378
3379 if (rate_flags & eHAL_TX_RATE_SGI) {
3380 if (!(sinfo->txrate.flags & RATE_INFO_FLAGS_VHT_MCS))
3381 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3382 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3383 }
3384 }
3385
3386 hdd_info("flag %x mcs %d legacy %d nss %d",
3387 sinfo->txrate.flags,
3388 sinfo->txrate.mcs,
3389 sinfo->txrate.legacy,
3390 sinfo->txrate.nss);
3391}
3392
3393/**
3394 * hdd_fill_station_info_flags() - fill flags of sinfo struct
3395 * @sinfo: station_info struct pointer
3396 *
3397 * This function will fill flags of sinfo struct
3398 *
3399 * Return: None
3400 */
3401static void hdd_fill_station_info_flags(struct station_info *sinfo)
3402{
3403 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) |
3404 BIT(NL80211_STA_INFO_TX_BYTES) |
3405 BIT(NL80211_STA_INFO_TX_BYTES64) |
3406 BIT(NL80211_STA_INFO_TX_BITRATE) |
3407 BIT(NL80211_STA_INFO_TX_PACKETS) |
3408 BIT(NL80211_STA_INFO_TX_RETRIES) |
3409 BIT(NL80211_STA_INFO_TX_FAILED) |
3410 BIT(NL80211_STA_INFO_RX_BYTES) |
3411 BIT(NL80211_STA_INFO_RX_BYTES64) |
3412 BIT(NL80211_STA_INFO_RX_PACKETS) |
3413 BIT(NL80211_STA_INFO_INACTIVE_TIME) |
3414 BIT(NL80211_STA_INFO_CONNECTED_TIME);
3415}
3416
3417/**
3418 * hdd_fill_rate_info() - fill rate info of sinfo
3419 * @sinfo: station_info struct pointer
3420 * @stainfo: stainfo pointer
3421 * @stats: fw txrx status pointer
3422 * @cfg: hdd config pointer
3423 *
3424 * This function will fill rate info of sinfo
3425 *
3426 * Return: None
3427 */
3428static void hdd_fill_rate_info(struct station_info *sinfo,
Jeff Johnson82155922017-09-30 16:54:14 -07003429 struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003430 struct hdd_fw_txrx_stats *stats,
3431 struct hdd_config *cfg)
3432{
3433 uint8_t rate_flags;
3434 uint8_t mcsidx = 0xff;
3435 uint32_t myrate, maxrate, tmprate;
3436 int rssidx;
3437 int nss = 1;
3438
3439 hdd_info("reportMaxLinkSpeed %d", cfg->reportMaxLinkSpeed);
3440
3441 /* convert to 100kbps expected in rate table */
3442 myrate = stats->tx_rate.rate / 100;
3443 rate_flags = stainfo->rate_flags;
3444 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3445 nss = stainfo->nss;
3446 if (eHDD_LINK_SPEED_REPORT_ACTUAL == cfg->reportMaxLinkSpeed) {
3447 /* Get current rate flags if report actual */
3448 if (stats->tx_rate.rate_flags)
3449 rate_flags =
3450 stats->tx_rate.rate_flags;
3451 nss = stats->tx_rate.nss;
3452 }
3453
3454 if (stats->tx_rate.mcs == INVALID_MCS_IDX)
3455 rate_flags = eHAL_TX_RATE_LEGACY;
3456 }
3457
3458 if (eHDD_LINK_SPEED_REPORT_ACTUAL != cfg->reportMaxLinkSpeed) {
3459 /* we do not want to necessarily report the current speed */
3460 if (eHDD_LINK_SPEED_REPORT_MAX == cfg->reportMaxLinkSpeed) {
3461 /* report the max possible speed */
3462 rssidx = 0;
3463 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
3464 cfg->reportMaxLinkSpeed) {
3465 /* report the max possible speed with RSSI scaling */
3466 if (stats->rssi >= cfg->linkSpeedRssiHigh) {
3467 /* report the max possible speed */
3468 rssidx = 0;
3469 } else if (stats->rssi >=
3470 cfg->linkSpeedRssiMid) {
3471 /* report middle speed */
3472 rssidx = 1;
3473 } else if (stats->rssi >=
3474 cfg->linkSpeedRssiLow) {
3475 /* report middle speed */
3476 rssidx = 2;
3477 } else {
3478 /* report actual speed */
3479 rssidx = 3;
3480 }
3481 } else {
3482 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
3483 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
3484 cfg->reportMaxLinkSpeed);
3485 rssidx = 0;
3486 }
3487
3488 maxrate = hdd_get_max_rate_legacy(stainfo, rssidx);
3489
3490 /*
3491 * Get MCS Rate Set --
3492 * Only if we are connected in non legacy mode and not
3493 * reporting actual speed
3494 */
3495 if ((rssidx != 3) &&
3496 !(rate_flags & eHAL_TX_RATE_LEGACY)) {
3497 hdd_get_max_rate_vht(stainfo,
3498 stats,
3499 rate_flags,
3500 nss,
3501 &tmprate,
3502 &mcsidx,
3503 rssidx == 0);
3504
3505 if (maxrate < tmprate &&
3506 mcsidx != INVALID_MCS_IDX)
3507 maxrate = tmprate;
3508
3509 if (mcsidx == INVALID_MCS_IDX)
3510 hdd_get_max_rate_ht(stainfo,
3511 stats,
3512 rate_flags,
3513 nss,
3514 &tmprate,
3515 &mcsidx,
3516 rssidx == 0);
3517
3518 if (maxrate < tmprate &&
3519 mcsidx != INVALID_MCS_IDX)
3520 maxrate = tmprate;
3521 } else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3522 maxrate = myrate;
3523 mcsidx = stats->tx_rate.mcs;
3524 }
3525
3526 /*
3527 * make sure we report a value at least as big as our
3528 * current rate
3529 */
3530 if ((maxrate < myrate) || (maxrate == 0)) {
3531 maxrate = myrate;
3532 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3533 mcsidx = stats->tx_rate.mcs;
3534 /*
3535 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3536 * - MCS9 is valid for VHT20 when Nss = 3 or
3537 * Nss = 6
3538 * - MCS9 is not valid for VHT20 when
3539 * Nss = 1,2,4,5,7,8
3540 */
3541 if ((rate_flags & eHAL_TX_RATE_VHT20) &&
3542 (mcsidx > 8) &&
3543 (nss != 3 && nss != 6))
3544 mcsidx = 8;
3545 }
3546 }
3547 } else {
3548 /* report current rate instead of max rate */
3549 maxrate = myrate;
3550 if (!(rate_flags & eHAL_TX_RATE_LEGACY))
3551 mcsidx = stats->tx_rate.mcs;
3552 }
3553
3554 hdd_fill_sinfo_rate_info(sinfo,
3555 rate_flags,
3556 mcsidx,
3557 nss,
3558 maxrate);
3559}
3560
3561/**
3562 * wlan_hdd_fill_station_info() - fill station_info struct
3563 * @sinfo: station_info struct pointer
3564 * @stainfo: stainfo pointer
3565 * @stats: fw txrx status pointer
3566 * @cfg: hdd config pointer
3567 *
3568 * This function will fill station_info struct
3569 *
3570 * Return: None
3571 */
3572static void wlan_hdd_fill_station_info(struct station_info *sinfo,
Jeff Johnson82155922017-09-30 16:54:14 -07003573 struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003574 struct hdd_fw_txrx_stats *stats,
3575 struct hdd_config *cfg)
3576{
3577 qdf_time_t curr_time, dur;
3578
3579 curr_time = qdf_system_ticks();
3580 dur = curr_time - stainfo->assoc_ts;
3581 sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000;
3582 dur = curr_time - stainfo->last_tx_rx_ts;
3583 sinfo->inactive_time = qdf_system_ticks_to_msecs(dur);
3584 sinfo->signal = stats->rssi;
3585 sinfo->tx_bytes = stats->tx_bytes;
3586 sinfo->tx_packets = stats->tx_packets;
3587 sinfo->rx_bytes = stats->rx_bytes;
3588 sinfo->rx_packets = stats->rx_packets;
3589 sinfo->tx_failed = stats->tx_failed;
3590 sinfo->tx_retries = stats->tx_retries;
3591
3592 /* tx rate info */
3593 hdd_fill_rate_info(sinfo, stainfo, stats, cfg);
3594
3595 hdd_fill_station_info_flags(sinfo);
3596
3597 /* dump sta info*/
3598 hdd_info("dump stainfo");
3599 hdd_info("con_time %d inact_time %d tx_pkts %d rx_pkts %d",
3600 sinfo->connected_time, sinfo->inactive_time,
3601 sinfo->tx_packets, sinfo->rx_packets);
3602 hdd_info("failed %d retries %d tx_bytes %lld rx_bytes %lld",
3603 sinfo->tx_failed, sinfo->tx_retries,
3604 sinfo->tx_bytes, sinfo->rx_bytes);
3605 hdd_info("rssi %d mcs %d legacy %d nss %d flags %x",
3606 sinfo->signal, sinfo->txrate.mcs,
3607 sinfo->txrate.legacy, sinfo->txrate.nss,
3608 sinfo->txrate.flags);
3609}
3610
3611/**
3612 * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs
3613 * @rate: Data rate (100 kbps)
3614 * @nss: Number of streams
3615 * @mcs: HT mcs index
3616 *
3617 * This function is used to construct HT rate flag with rate, nss and mcs
3618 *
3619 * Return: rate flags for success, 0 on failure.
3620 */
3621static uint8_t hdd_get_rate_flags_ht(uint32_t rate,
3622 uint8_t nss,
3623 uint8_t mcs)
3624{
3625 struct index_data_rate_type *mcs_rate;
3626 uint8_t flags = 0;
3627
3628 mcs_rate = (struct index_data_rate_type *)
3629 ((nss == 1) ? &supported_mcs_rate_nss1 :
3630 &supported_mcs_rate_nss2);
3631
3632 if (rate == mcs_rate[mcs].supported_rate[0]) {
3633 flags |= eHAL_TX_RATE_HT20;
3634 } else if (rate == mcs_rate[mcs].supported_rate[1]) {
3635 flags |= eHAL_TX_RATE_HT40;
3636 } else if (rate == mcs_rate[mcs].supported_rate[2]) {
3637 flags |= eHAL_TX_RATE_HT20;
3638 flags |= eHAL_TX_RATE_SGI;
3639 } else if (rate == mcs_rate[mcs].supported_rate[3]) {
3640 flags |= eHAL_TX_RATE_HT40;
3641 flags |= eHAL_TX_RATE_SGI;
3642 } else {
3643 hdd_err("invalid params rate %d nss %d mcs %d",
3644 rate, nss, mcs);
3645 }
3646
3647 return flags;
3648}
3649
3650/**
3651 * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs
3652 * @rate: Data rate (100 kbps)
3653 * @nss: Number of streams
3654 * @mcs: VHT mcs index
3655 *
3656 * This function is used to construct VHT rate flag with rate, nss and mcs
3657 *
3658 * Return: rate flags for success, 0 on failure.
3659 */
3660static uint8_t hdd_get_rate_flags_vht(uint32_t rate,
3661 uint8_t nss,
3662 uint8_t mcs)
3663{
3664 struct index_vht_data_rate_type *mcs_rate;
3665 uint8_t flags = 0;
3666
3667 mcs_rate = (struct index_vht_data_rate_type *)
3668 ((nss == 1) ?
3669 &supported_vht_mcs_rate_nss1 :
3670 &supported_vht_mcs_rate_nss2);
3671
3672 if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
3673 flags |= eHAL_TX_RATE_VHT80;
3674 } else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
3675 flags |= eHAL_TX_RATE_VHT80;
3676 flags |= eHAL_TX_RATE_SGI;
3677 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
3678 flags |= eHAL_TX_RATE_VHT40;
3679 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
3680 flags |= eHAL_TX_RATE_VHT40;
3681 flags |= eHAL_TX_RATE_SGI;
3682 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
3683 flags |= eHAL_TX_RATE_VHT20;
3684 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
3685 flags |= eHAL_TX_RATE_VHT20;
3686 flags |= eHAL_TX_RATE_SGI;
3687 } else {
3688 hdd_err("invalid params rate %d nss %d mcs %d",
3689 rate, nss, mcs);
3690 }
3691
3692 return flags;
3693}
3694
3695/**
3696 * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs
3697 * @rate: Data rate (100 kbps)
3698 * @mode: Tx/Rx mode
3699 * @nss: Number of streams
3700 * @mcs: Mcs index
3701 *
3702 * This function is used to construct rate flag with rate, nss and mcs
3703 *
3704 * Return: rate flags for success, 0 on failure.
3705 */
3706static uint8_t hdd_get_rate_flags(uint32_t rate,
3707 uint8_t mode,
3708 uint8_t nss,
3709 uint8_t mcs)
3710{
3711 uint8_t flags = 0;
3712
3713 if (mode == SIR_SME_PHY_MODE_HT)
3714 flags = hdd_get_rate_flags_ht(rate, nss, mcs);
3715 else if (mode == SIR_SME_PHY_MODE_VHT)
3716 flags = hdd_get_rate_flags_vht(rate, nss, mcs);
3717 else
3718 hdd_err("invalid mode param %d", mode);
3719
3720 return flags;
3721}
3722
3723/**
3724 * wlan_hdd_fill_rate_info() - fill HDD rate info from SIR peer info
3725 * @ap_ctx: AP Context
3726 * @peer_info: SIR peer info pointer
3727 *
3728 * This function is used to fill HDD rate info rom SIR peer info
3729 *
3730 * Return: None
3731 */
Jeff Johnson87251032017-08-29 13:31:11 -07003732static void wlan_hdd_fill_rate_info(struct hdd_ap_ctx *ap_ctx,
Will Huang496b36c2017-07-11 16:38:50 +08003733 struct sir_peer_info_ext *peer_info)
3734{
3735 uint8_t flags;
3736 uint32_t rate_code;
3737
3738 /* tx rate info */
3739 ap_ctx->txrx_stats.tx_rate.rate = peer_info->tx_rate;
3740 rate_code = peer_info->tx_rate_code;
3741
3742 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3743 WMI_RATE_PREAMBLE_HT)
3744 ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_HT;
3745 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3746 WMI_RATE_PREAMBLE_VHT)
3747 ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_VHT;
3748 else
3749 ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
3750
3751 ap_ctx->txrx_stats.tx_rate.nss =
3752 WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3753 ap_ctx->txrx_stats.tx_rate.mcs =
3754 WMI_GET_HW_RATECODE_RATE_V1(rate_code);
3755
3756 flags = hdd_get_rate_flags(ap_ctx->txrx_stats.tx_rate.rate / 100,
3757 ap_ctx->txrx_stats.tx_rate.mode,
3758 ap_ctx->txrx_stats.tx_rate.nss,
3759 ap_ctx->txrx_stats.tx_rate.mcs);
3760
3761 ap_ctx->txrx_stats.tx_rate.rate_flags = flags;
3762
3763 hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x",
3764 ap_ctx->txrx_stats.tx_rate.mode,
3765 ap_ctx->txrx_stats.tx_rate.nss,
3766 ap_ctx->txrx_stats.tx_rate.mcs,
3767 ap_ctx->txrx_stats.tx_rate.rate_flags,
3768 flags);
3769
3770 /* rx rate info */
3771 ap_ctx->txrx_stats.rx_rate.rate = peer_info->rx_rate;
3772 rate_code = peer_info->rx_rate_code;
3773
3774 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3775 WMI_RATE_PREAMBLE_HT)
3776 ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_HT;
3777 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3778 WMI_RATE_PREAMBLE_VHT)
3779 ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_VHT;
3780 else
3781 ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
3782
3783 ap_ctx->txrx_stats.rx_rate.nss =
3784 WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3785 ap_ctx->txrx_stats.rx_rate.mcs =
3786 WMI_GET_HW_RATECODE_RATE_V1(rate_code);
3787
3788 flags = hdd_get_rate_flags(ap_ctx->txrx_stats.rx_rate.rate / 100,
3789 ap_ctx->txrx_stats.rx_rate.mode,
3790 ap_ctx->txrx_stats.rx_rate.nss,
3791 ap_ctx->txrx_stats.rx_rate.mcs);
3792
3793 ap_ctx->txrx_stats.rx_rate.rate_flags = flags;
3794
3795 hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x",
3796 ap_ctx->txrx_stats.rx_rate.mode,
3797 ap_ctx->txrx_stats.rx_rate.nss,
3798 ap_ctx->txrx_stats.rx_rate.mcs,
3799 ap_ctx->txrx_stats.rx_rate.rate_flags,
3800 flags);
3801}
3802
3803int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3804 struct net_device *dev,
3805 const u8 *mac,
3806 struct station_info *sinfo);
3807
3808/**
3809 * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
3810 * @wiphy: pointer to wiphy
3811 * @dev: pointer to net_device structure
3812 * @mac: request peer mac address
3813 * @sinfo: pointer to station_info struct
3814 *
3815 * This function will get remote peer info from fw and fill sinfo struct
3816 *
3817 * Return: 0 on success, otherwise error value
3818 */
3819int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3820 struct net_device *dev,
3821 const u8 *mac,
3822 struct station_info *sinfo)
3823{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003824 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07003825 struct hdd_context *hddctx = wiphy_priv(wiphy);
Jeff Johnson87251032017-08-29 13:31:11 -07003826 struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
Jeff Johnson82155922017-09-30 16:54:14 -07003827 struct hdd_station_info *stainfo = NULL;
Will Huang496b36c2017-07-11 16:38:50 +08003828 struct hdd_config *cfg;
3829 struct qdf_mac_addr macaddr;
3830 struct sir_peer_info_ext peer_info;
3831 int status;
3832 int i;
3833
3834 status = wlan_hdd_validate_context(hddctx);
3835 if (status != 0)
3836 return status;
3837
3838 cfg = hddctx->config;
3839
3840 hdd_debug("get peer %pM info", mac);
3841
3842 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003843 if (!qdf_mem_cmp(adapter->sta_info[i].sta_mac.bytes,
Will Huang496b36c2017-07-11 16:38:50 +08003844 mac,
3845 QDF_MAC_ADDR_SIZE)) {
Jeff Johnsonbb8b56a2017-10-23 07:02:36 -07003846 stainfo = &adapter->sta_info[i];
Will Huang496b36c2017-07-11 16:38:50 +08003847 break;
3848 }
3849 }
3850
3851 if (!stainfo) {
3852 hdd_err("peer %pM not found", mac);
3853 return -EINVAL;
3854 }
3855
3856 qdf_mem_copy(macaddr.bytes, mac, QDF_MAC_ADDR_SIZE);
3857 status = wlan_hdd_get_peer_info(adapter, macaddr, &peer_info);
3858 if (status) {
3859 hdd_err("fail to get peer info from fw");
3860 return -EPERM;
3861 }
3862
3863 qdf_mem_zero(&ap_ctx->txrx_stats, sizeof(ap_ctx->txrx_stats));
3864 ap_ctx->txrx_stats.tx_packets = peer_info.tx_packets;
3865 ap_ctx->txrx_stats.tx_bytes = peer_info.tx_bytes;
3866 ap_ctx->txrx_stats.rx_packets = peer_info.rx_packets;
3867 ap_ctx->txrx_stats.rx_bytes = peer_info.rx_bytes;
3868 ap_ctx->txrx_stats.tx_retries = peer_info.tx_retries;
3869 ap_ctx->txrx_stats.tx_failed = peer_info.tx_failed;
3870 ap_ctx->txrx_stats.rssi =
3871 peer_info.rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM;
3872 wlan_hdd_fill_rate_info(ap_ctx, &peer_info);
3873
3874 wlan_hdd_fill_station_info(sinfo, stainfo, &ap_ctx->txrx_stats, cfg);
3875
3876 return status;
3877}
3878
3879/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003880 * __wlan_hdd_cfg80211_get_station() - get station statistics
3881 * @wiphy: Pointer to wiphy
3882 * @dev: Pointer to network device
3883 * @mac: Pointer to mac
3884 * @sinfo: Pointer to station info
3885 *
3886 * Return: 0 for success, non-zero for failure
3887 */
3888static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
3889 struct net_device *dev,
3890 const uint8_t *mac,
3891 struct station_info *sinfo)
3892{
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003893 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnsond377dce2017-10-04 10:32:42 -07003894 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
3895 int ssidlen = sta_ctx->conn_info.SSID.SSID.length;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003896 uint8_t rate_flags;
Dustin Brown905cdc72016-11-16 16:51:10 -08003897 uint8_t mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003898
Jeff Johnsonf645abf2017-09-03 09:07:46 -07003899 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
3900 struct hdd_config *pCfg = hdd_ctx->config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003901
3902 uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
3903 uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX;
3904 uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
3905 uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
3906 uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET];
3907 uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET;
3908 uint16_t maxRate = 0;
Anurag Chouhan5de8d172016-07-13 14:44:28 +05303909 int8_t snr = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003910 uint16_t myRate;
3911 uint16_t currentRate = 0;
3912 uint8_t maxSpeedMCS = 0;
3913 uint8_t maxMCSIdx = 0;
3914 uint8_t rateFlag = 1;
3915 uint8_t i, j, rssidx;
3916 uint8_t nss = 1;
3917 int status, mode = 0, maxHtIdx;
3918 struct index_vht_data_rate_type *supported_vht_mcs_rate;
3919 struct index_data_rate_type *supported_mcs_rate;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303920#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
3921 bool rssi_stats_valid = false;
3922#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003924 uint32_t vht_mcs_map;
Will Huang496b36c2017-07-11 16:38:50 +08003925 enum data_rate_11ac_max_mcs vht_max_mcs;
Rajeev Kumar Sirasanagandlab13b7772017-01-24 15:28:29 +05303926 int32_t rcpi_value;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003927
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003928 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003929
Anurag Chouhan6d760662016-02-20 16:05:43 +05303930 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003931 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003932 return -EINVAL;
3933 }
3934
Jeff Johnsonf645abf2017-09-03 09:07:46 -07003935 status = wlan_hdd_validate_context(hdd_ctx);
Dustin Brown0e4479e2017-07-14 14:47:39 -07003936 if (status)
3937 return status;
3938
Jeff Johnson1b780e42017-10-31 14:11:45 -07003939 if (wlan_hdd_validate_session_id(adapter->session_id)) {
3940 hdd_err("invalid session id: %d", adapter->session_id);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05303941 return -EINVAL;
3942 }
3943
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003944 if (adapter->device_mode == QDF_SAP_MODE)
3945 return wlan_hdd_get_sap_stats(adapter, sinfo);
Dustin Brown0e4479e2017-07-14 14:47:39 -07003946
Jeff Johnsond377dce2017-10-04 10:32:42 -07003947 if ((eConnectionState_Associated != sta_ctx->conn_info.connState) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003948 (0 == ssidlen)) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003949 hdd_debug("Not associated or Invalid ssidlen, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003950 ssidlen);
3951 /*To keep GUI happy */
3952 return 0;
3953 }
3954
Jeff Johnson690fe952017-10-25 11:48:39 -07003955 if (sta_ctx->hdd_reassoc_scenario) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003956 hdd_debug("Roaming is in progress, cannot continue with this request");
Sachin Ahujafeedeba2016-09-13 21:54:16 +05303957 /*
3958 * supplicant reports very low rssi to upper layer
3959 * and handover happens to cellular.
3960 * send the cached rssi when get_station
3961 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003962 sinfo->signal = adapter->rssi;
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05303963 wlan_hdd_fill_station_info_signal(sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003964 return 0;
3965 }
3966
Rajeev Kumar Sirasanagandlab13b7772017-01-24 15:28:29 +05303967 if (hdd_ctx->rcpi_enabled)
3968 wlan_hdd_get_rcpi(adapter, (uint8_t *)mac, &rcpi_value,
3969 RCPI_MEASUREMENT_TYPE_AVG_MGMT);
3970
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003971 wlan_hdd_get_station_stats(adapter);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05303972
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003973 if (adapter->hdd_stats.summary_stat.rssi)
3974 adapter->rssi = adapter->hdd_stats.summary_stat.rssi;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05303975
3976 /* for new connection there might be no valid previous RSSI */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003977 if (!adapter->rssi) {
3978 hdd_get_rssi_snr_by_bssid(adapter,
Jeff Johnsond377dce2017-10-04 10:32:42 -07003979 sta_ctx->conn_info.bssId.bytes,
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003980 &adapter->rssi, NULL);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05303981 }
3982
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003983 sinfo->signal = adapter->rssi;
3984 snr = adapter->hdd_stats.summary_stat.snr;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003985 hdd_debug("snr: %d, rssi: %d",
Jeff Johnsona86e78e2017-10-02 13:23:05 -07003986 adapter->hdd_stats.summary_stat.snr,
3987 adapter->hdd_stats.summary_stat.rssi);
Jeff Johnsond377dce2017-10-04 10:32:42 -07003988 sta_ctx->conn_info.signal = sinfo->signal;
3989 sta_ctx->conn_info.noise =
3990 sta_ctx->conn_info.signal - snr;
Anurag Chouhan5de8d172016-07-13 14:44:28 +05303991
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05303992 wlan_hdd_fill_station_info_signal(sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003993
Jeff Johnson71396692016-09-23 15:41:52 -07003994 /*
3995 * we notify connect to lpass here instead of during actual
3996 * connect processing because rssi info is not accurate during
3997 * actual connection. lpass will ensure the notification is
3998 * only processed once per association.
3999 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004000 hdd_lpass_notify_connect(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004001
Jeff Johnson861dd4f2017-10-24 10:10:40 -07004002 rate_flags = adapter->hdd_stats.class_a_stat.tx_rate_flags;
4003 mcs_index = adapter->hdd_stats.class_a_stat.mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004004
4005 /* convert to the UI units of 100kbps */
Jeff Johnson861dd4f2017-10-24 10:10:40 -07004006 myRate = adapter->hdd_stats.class_a_stat.tx_rate * 5;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004007 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
Jeff Johnson861dd4f2017-10-24 10:10:40 -07004008 nss = adapter->hdd_stats.class_a_stat.nss;
Liangwei Dong05475a72017-08-09 13:39:57 +09004009 if ((nss > 1) &&
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004010 policy_mgr_is_current_hwmode_dbs(hdd_ctx->hdd_psoc) &&
4011 !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->hdd_psoc)) {
Liangwei Dong05475a72017-08-09 13:39:57 +09004012 hdd_debug("Hw mode is DBS, Reduce nss(%d) to 1", nss);
Agrawal Ashish569ad262017-05-01 14:06:36 +05304013 nss--;
4014 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004015
4016 if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) {
4017 /* Get current rate flags if report actual */
Hanumanth Reddy Pothula063cbe92017-08-08 23:22:01 +05304018 /* WMA fails to find mcs_index for legacy tx rates */
4019 if (mcs_index == INVALID_MCS_IDX && myRate)
4020 rate_flags = eHAL_TX_RATE_LEGACY;
4021 else
4022 rate_flags =
Jeff Johnson861dd4f2017-10-24 10:10:40 -07004023 adapter->hdd_stats.class_a_stat.mcs_rate_flags;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004024 }
4025
Dustin Brown905cdc72016-11-16 16:51:10 -08004026 if (mcs_index == INVALID_MCS_IDX)
4027 mcs_index = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004029
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004030 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 -08004031 sinfo->signal, pCfg->reportMaxLinkSpeed, myRate,
4032 (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid,
Dustin Brown905cdc72016-11-16 16:51:10 -08004033 (int)pCfg->linkSpeedRssiLow, (int)rate_flags, (int)mcs_index);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004034
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07004035 /* assume basic BW. anything else will override this later */
Dustin Brown32cb4792017-06-15 15:33:42 -07004036 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_20);
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07004037
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004038 if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) {
4039 /* we do not want to necessarily report the current speed */
4040 if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) {
4041 /* report the max possible speed */
4042 rssidx = 0;
4043 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
4044 pCfg->reportMaxLinkSpeed) {
4045 /* report the max possible speed with RSSI scaling */
4046 if (sinfo->signal >= pCfg->linkSpeedRssiHigh) {
4047 /* report the max possible speed */
4048 rssidx = 0;
4049 } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) {
4050 /* report middle speed */
4051 rssidx = 1;
4052 } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) {
4053 /* report middle speed */
4054 rssidx = 2;
4055 } else {
4056 /* report actual speed */
4057 rssidx = 3;
4058 }
4059 } else {
4060 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004061 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004062 pCfg->reportMaxLinkSpeed);
4063 rssidx = 0;
4064 }
4065
4066 maxRate = 0;
4067
4068 /* Get Basic Rate Set */
4069 if (0 !=
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004070 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(adapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071 WNI_CFG_OPERATIONAL_RATE_SET,
4072 OperationalRates,
4073 &ORLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004074 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004075 /*To keep GUI happy */
4076 return 0;
4077 }
4078
4079 for (i = 0; i < ORLeng; i++) {
4080 for (j = 0;
4081 j < ARRAY_SIZE(supported_data_rate); j++) {
4082 /* Validate Rate Set */
4083 if (supported_data_rate[j].beacon_rate_index ==
4084 (OperationalRates[i] & 0x7F)) {
4085 currentRate =
4086 supported_data_rate[j].
4087 supported_rate[rssidx];
4088 break;
4089 }
4090 }
4091 /* Update MAX rate */
4092 maxRate =
4093 (currentRate > maxRate) ? currentRate : maxRate;
4094 }
4095
4096 /* Get Extended Rate Set */
4097 if (0 !=
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004098 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(adapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004099 WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
4100 ExtendedRates, &ERLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004101 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004102 /*To keep GUI happy */
4103 return 0;
4104 }
4105
4106 for (i = 0; i < ERLeng; i++) {
4107 for (j = 0;
4108 j < ARRAY_SIZE(supported_data_rate); j++) {
4109 if (supported_data_rate[j].beacon_rate_index ==
4110 (ExtendedRates[i] & 0x7F)) {
4111 currentRate =
4112 supported_data_rate[j].
4113 supported_rate[rssidx];
4114 break;
4115 }
4116 }
4117 /* Update MAX rate */
4118 maxRate =
4119 (currentRate > maxRate) ? currentRate : maxRate;
4120 }
Jeff Johnson8bb78c32017-01-12 08:42:50 -08004121 /*
4122 * Get MCS Rate Set --
4123 * Only if we are connected in non legacy mode and not
4124 * reporting actual speed
4125 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004126 if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) {
4127 if (0 !=
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004128 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(adapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004129 WNI_CFG_CURRENT_MCS_SET, MCSRates,
4130 &MCSLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004131 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004132 /*To keep GUI happy */
4133 return 0;
4134 }
4135 rateFlag = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004136 supported_vht_mcs_rate =
4137 (struct index_vht_data_rate_type *)
4138 ((nss ==
4139 1) ? &supported_vht_mcs_rate_nss1 :
4140 &supported_vht_mcs_rate_nss2);
4141
4142 if (rate_flags & eHAL_TX_RATE_VHT80)
4143 mode = 2;
4144 else if ((rate_flags & eHAL_TX_RATE_VHT40) ||
4145 (rate_flags & eHAL_TX_RATE_HT40))
4146 mode = 1;
4147 else
4148 mode = 0;
4149
4150 /* VHT80 rate has seperate rate table */
4151 if (rate_flags &
4152 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
4153 eHAL_TX_RATE_VHT80)) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004154 sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(adapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004155 WNI_CFG_VHT_TX_MCS_MAP,
4156 &vht_mcs_map);
Will Huang496b36c2017-07-11 16:38:50 +08004157 vht_max_mcs = (enum data_rate_11ac_max_mcs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004158 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
4159 if (rate_flags & eHAL_TX_RATE_SGI)
4160 rateFlag |= 1;
Dustin Brown32cb4792017-06-15 15:33:42 -07004161
Will Huang496b36c2017-07-11 16:38:50 +08004162 if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004163 maxMCSIdx = 7;
Will Huang496b36c2017-07-11 16:38:50 +08004164 else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004165 maxMCSIdx = 8;
Will Huang496b36c2017-07-11 16:38:50 +08004166 else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs)
Dustin Brown32cb4792017-06-15 15:33:42 -07004167 maxMCSIdx = 9;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004168
4169 if (rssidx != 0) {
4170 for (i = 0; i <= maxMCSIdx; i++) {
4171 if (sinfo->signal <=
4172 rssi_mcs_tbl[mode][i]) {
4173 maxMCSIdx = i;
4174 break;
4175 }
4176 }
4177 }
4178
4179 if (rate_flags & eHAL_TX_RATE_VHT80) {
4180 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08004181 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004182 supported_VHT80_rate[rateFlag];
4183 maxRate =
4184 supported_vht_mcs_rate[maxMCSIdx].
4185 supported_VHT80_rate[rateFlag];
4186 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
4187 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08004188 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004189 supported_VHT40_rate[rateFlag];
4190 maxRate =
4191 supported_vht_mcs_rate[maxMCSIdx].
4192 supported_VHT40_rate[rateFlag];
4193 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
4194 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08004195 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004196 supported_VHT20_rate[rateFlag];
4197 maxRate =
4198 supported_vht_mcs_rate[maxMCSIdx].
4199 supported_VHT20_rate[rateFlag];
4200 }
4201
4202 maxSpeedMCS = 1;
4203 if (currentRate > maxRate)
4204 maxRate = currentRate;
4205
Kiran Kumar Lokere9a733a72016-02-17 19:01:15 -08004206 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004207 if (rate_flags & eHAL_TX_RATE_HT40)
4208 rateFlag |= 1;
4209 if (rate_flags & eHAL_TX_RATE_SGI)
4210 rateFlag |= 2;
4211
4212 supported_mcs_rate =
4213 (struct index_data_rate_type *)
4214 ((nss ==
4215 1) ? &supported_mcs_rate_nss1 :
4216 &supported_mcs_rate_nss2);
4217
4218 maxHtIdx = MAX_HT_MCS_IDX;
4219 if (rssidx != 0) {
4220 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
4221 if (sinfo->signal <=
4222 rssi_mcs_tbl[mode][i]) {
4223 maxHtIdx = i + 1;
4224 break;
4225 }
4226 }
4227 }
4228
4229 for (i = 0; i < MCSLeng; i++) {
4230 for (j = 0; j < maxHtIdx; j++) {
4231 if (supported_mcs_rate[j].
4232 beacon_rate_index ==
4233 MCSRates[i]) {
4234 currentRate =
4235 supported_mcs_rate[j].
4236 supported_rate
4237 [rateFlag];
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05304238 maxMCSIdx =
4239 supported_mcs_rate[j].
4240 beacon_rate_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004241 break;
4242 }
4243 }
4244
4245 if ((j < MAX_HT_MCS_IDX)
4246 && (currentRate > maxRate)) {
4247 maxRate = currentRate;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004248 }
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05304249 maxSpeedMCS = 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004250 }
Yeshwanth Sriram Guntukad18c7a22018-02-02 15:22:30 +05304251 if (nss == 2)
4252 maxMCSIdx += MAX_HT_MCS_IDX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004253 }
4254 }
4255
4256 else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
4257 maxRate = myRate;
4258 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08004259 maxMCSIdx = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004260 }
4261 /* report a value at least as big as current rate */
4262 if ((maxRate < myRate) || (0 == maxRate)) {
4263 maxRate = myRate;
4264 if (rate_flags & eHAL_TX_RATE_LEGACY) {
4265 maxSpeedMCS = 0;
4266 } else {
4267 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08004268 maxMCSIdx = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004269 }
4270 }
4271
4272 if (rate_flags & eHAL_TX_RATE_LEGACY) {
4273 sinfo->txrate.legacy = maxRate;
Dustin Brown32cb4792017-06-15 15:33:42 -07004274 linkspeed_dbg("Reporting legacy rate %d\n",
4275 sinfo->txrate.legacy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004276 } else {
4277 sinfo->txrate.mcs = maxMCSIdx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004278 sinfo->txrate.nss = nss;
Dustin Brown32cb4792017-06-15 15:33:42 -07004279
4280 if (rate_flags & eHAL_TX_RATE_VHT80)
4281 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_80);
4282 else if (rate_flags & eHAL_TX_RATE_VHT40)
4283 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_40);
4284
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004285 if (rate_flags &
4286 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
4287 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Dustin Brown32cb4792017-06-15 15:33:42 -07004288 if (rate_flags & eHAL_TX_RATE_HT40)
4289 hdd_set_rate_bw(&sinfo->txrate,
4290 HDD_RATE_BW_40);
Yeshwanth Sriram Guntukad18c7a22018-02-02 15:22:30 +05304291 } else {
4292 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004294
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004295 if (rate_flags & eHAL_TX_RATE_SGI) {
4296 if (!
4297 (sinfo->txrate.
4298 flags & RATE_INFO_FLAGS_VHT_MCS))
4299 sinfo->txrate.flags |=
4300 RATE_INFO_FLAGS_MCS;
4301 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
4302 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004303 linkspeed_dbg("Reporting MCS rate %d flags %x\n",
4304 sinfo->txrate.mcs, sinfo->txrate.flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004305 }
4306 } else {
4307 /* report current rate instead of max rate */
4308
4309 if (rate_flags & eHAL_TX_RATE_LEGACY) {
4310 /* provide to the UI in units of 100kbps */
4311 sinfo->txrate.legacy = myRate;
Dustin Brown32cb4792017-06-15 15:33:42 -07004312 linkspeed_dbg("Reporting actual legacy rate %d\n",
4313 sinfo->txrate.legacy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004314 } else {
4315 /* must be MCS */
Dustin Brown905cdc72016-11-16 16:51:10 -08004316 sinfo->txrate.mcs = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004317 sinfo->txrate.nss = nss;
Dustin Brown32cb4792017-06-15 15:33:42 -07004318
4319 if (rate_flags & eHAL_TX_RATE_VHT80)
4320 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_80);
4321 else if (rate_flags & eHAL_TX_RATE_VHT40)
4322 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_40);
4323
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004324 if (rate_flags &
4325 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
4326 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Dustin Brown32cb4792017-06-15 15:33:42 -07004327 if (rate_flags & eHAL_TX_RATE_HT40)
4328 hdd_set_rate_bw(&sinfo->txrate,
4329 HDD_RATE_BW_40);
Yeshwanth Sriram Guntukad18c7a22018-02-02 15:22:30 +05304330 } else {
4331 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004332 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004333
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004334 if (rate_flags & eHAL_TX_RATE_SGI) {
4335 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
4336 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
4337 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004338
4339 linkspeed_dbg("Reporting actual MCS rate %d flags %x\n",
4340 sinfo->txrate.mcs, sinfo->txrate.flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004341 }
4342 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004343
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004344 wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, sinfo);
4345 sinfo->tx_bytes = adapter->stats.tx_bytes;
4346 sinfo->rx_bytes = adapter->stats.rx_bytes;
4347 sinfo->rx_packets = adapter->stats.rx_packets;
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004348
Jeff Johnsond377dce2017-10-04 10:32:42 -07004349 qdf_mem_copy(&sta_ctx->conn_info.txrate,
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304350 &sinfo->txrate, sizeof(sinfo->txrate));
4351
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004352#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
4353 sinfo->filled |= STATION_INFO_TX_BITRATE |
4354 STATION_INFO_TX_BYTES |
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004355 STATION_INFO_RX_BYTES |
4356 STATION_INFO_RX_PACKETS;
4357#else
Dustin Brown0e4479e2017-07-14 14:47:39 -07004358 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE) |
4359 BIT(NL80211_STA_INFO_TX_BYTES) |
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004360 BIT(NL80211_STA_INFO_RX_BYTES) |
4361 BIT(NL80211_STA_INFO_RX_PACKETS);
4362#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004363
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304364 if (rate_flags & eHAL_TX_RATE_LEGACY)
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004365 hdd_debug("Reporting legacy rate %d pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304366 sinfo->txrate.legacy, sinfo->tx_packets,
4367 sinfo->rx_packets);
4368 else
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004369 hdd_debug("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304370 sinfo->txrate.mcs, sinfo->txrate.flags,
4371 sinfo->tx_packets, sinfo->rx_packets);
4372
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304373#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
4374 sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
4375 for (i = 0; i < NUM_CHAINS_MAX; i++) {
4376 sinfo->chain_signal_avg[i] =
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004377 adapter->hdd_stats.per_chain_rssi_stats.rssi[i];
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304378 sinfo->chains |= 1 << i;
4379 if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
4380 sinfo->chain_signal_avg[i] != 0)
4381 sinfo->signal_avg = sinfo->chain_signal_avg[i];
4382
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004383 hdd_debug("RSSI for chain %d, vdev_id %d is %d",
Jeff Johnson1b780e42017-10-31 14:11:45 -07004384 i, adapter->session_id, sinfo->chain_signal_avg[i]);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304385
4386 if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
4387 rssi_stats_valid = true;
4388 }
4389
4390 if (rssi_stats_valid) {
4391#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
4392 sinfo->filled |= STATION_INFO_CHAIN_SIGNAL_AVG;
4393 sinfo->filled |= STATION_INFO_SIGNAL_AVG;
4394#else
4395 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
4396 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
4397#endif
4398 }
4399#endif
4400
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304401 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004402 TRACE_CODE_HDD_CFG80211_GET_STA,
Jeff Johnson1b780e42017-10-31 14:11:45 -07004403 adapter->session_id, maxRate));
Dustin Brown32cb4792017-06-15 15:33:42 -07004404
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004405 EXIT();
Dustin Brown32cb4792017-06-15 15:33:42 -07004406
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004407 return 0;
4408}
4409
4410/**
4411 * wlan_hdd_cfg80211_get_station() - get station statistics
4412 * @wiphy: Pointer to wiphy
4413 * @dev: Pointer to network device
4414 * @mac: Pointer to mac
4415 * @sinfo: Pointer to station info
4416 *
4417 * Return: 0 for success, non-zero for failure
4418 */
4419#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
4420int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4421 struct net_device *dev, const uint8_t *mac,
4422 struct station_info *sinfo)
4423#else
4424int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4425 struct net_device *dev, uint8_t *mac,
4426 struct station_info *sinfo)
4427#endif
4428{
4429 int ret;
4430
4431 cds_ssr_protect(__func__);
4432 ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4433 cds_ssr_unprotect(__func__);
4434
4435 return ret;
4436}
4437
4438/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304439 * __wlan_hdd_cfg80211_dump_station() - dump station statistics
4440 * @wiphy: Pointer to wiphy
4441 * @dev: Pointer to network device
4442 * @idx: variable to determine whether to get stats or not
4443 * @mac: Pointer to mac
4444 * @sinfo: Pointer to station info
4445 *
4446 * Return: 0 for success, non-zero for failure
4447 */
4448static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4449 struct net_device *dev,
4450 int idx, u8 *mac,
4451 struct station_info *sinfo)
4452{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07004453 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304454
4455 hdd_debug("%s: idx %d", __func__, idx);
4456 if (idx != 0)
4457 return -ENOENT;
4458 qdf_mem_copy(mac, hdd_ctx->config->intfMacAddr[0].bytes,
4459 QDF_MAC_ADDR_SIZE);
4460 return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4461}
4462
4463/**
4464 * wlan_hdd_cfg80211_dump_station() - dump station statistics
4465 * @wiphy: Pointer to wiphy
4466 * @dev: Pointer to network device
4467 * @idx: variable to determine whether to get stats or not
4468 * @mac: Pointer to mac
4469 * @sinfo: Pointer to station info
4470 *
4471 * Return: 0 for success, non-zero for failure
4472 */
4473int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4474 struct net_device *dev,
4475 int idx, u8 *mac,
4476 struct station_info *sinfo)
4477{
4478 int ret;
4479
4480 cds_ssr_protect(__func__);
4481 ret = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
4482 cds_ssr_unprotect(__func__);
4483 return ret;
4484}
4485
4486/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004487 * hdd_get_stats() - Function to retrieve interface statistics
4488 * @dev: pointer to network device
4489 *
4490 * This function is the ndo_get_stats method for all netdevs
4491 * registered with the kernel
4492 *
4493 * Return: pointer to net_device_stats structure
4494 */
4495struct net_device_stats *hdd_get_stats(struct net_device *dev)
4496{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07004497 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004498
Jeff Johnson3c3994a2016-02-11 08:12:30 -08004499 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004500 return &adapter->stats;
4501}
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304502
4503
4504/*
4505 * time = cycle_count * cycle
4506 * cycle = 1 / clock_freq
4507 * Since the unit of clock_freq reported from
4508 * FW is MHZ, and we want to calculate time in
4509 * ms level, the result is
4510 * time = cycle / (clock_freq * 1000)
4511 */
4512#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
4513static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4514 struct scan_chan_info *chan_info,
4515 struct ieee80211_channel *channels)
4516{
4517 uint64_t clock_freq = chan_info->clock_freq * 1000;
4518
4519 if (channels->center_freq != (uint16_t)chan_info->freq)
4520 return false;
4521
4522 survey->channel = channels;
4523 survey->noise = chan_info->noise_floor;
4524 survey->filled = SURVEY_INFO_NOISE_DBM;
4525
4526 if (opfreq == chan_info->freq)
4527 survey->filled |= SURVEY_INFO_IN_USE;
4528
4529 if (clock_freq == 0)
4530 return true;
4531
4532 survey->time = chan_info->cycle_count / clock_freq;
4533 survey->time_busy = chan_info->rx_clear_count / clock_freq;
4534 survey->time_tx = chan_info->tx_frame_count / clock_freq;
4535
4536 survey->filled |= SURVEY_INFO_TIME |
4537 SURVEY_INFO_TIME_BUSY |
4538 SURVEY_INFO_TIME_TX;
4539 return true;
4540}
4541#else
4542static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4543 struct scan_chan_info *chan_info,
4544 struct ieee80211_channel *channels)
4545{
4546 uint64_t clock_freq = chan_info->clock_freq * 1000;
4547
4548 if (channels->center_freq != (uint16_t)chan_info->freq)
4549 return false;
4550
4551 survey->channel = channels;
4552 survey->noise = chan_info->noise_floor;
4553 survey->filled = SURVEY_INFO_NOISE_DBM;
4554
4555 if (opfreq == chan_info->freq)
4556 survey->filled |= SURVEY_INFO_IN_USE;
4557
4558 if (clock_freq == 0)
4559 return true;
4560
4561 survey->channel_time = chan_info->cycle_count / clock_freq;
4562 survey->channel_time_busy = chan_info->rx_clear_count / clock_freq;
4563 survey->channel_time_tx = chan_info->tx_frame_count / clock_freq;
4564
4565 survey->filled |= SURVEY_INFO_CHANNEL_TIME |
4566 SURVEY_INFO_CHANNEL_TIME_BUSY |
4567 SURVEY_INFO_CHANNEL_TIME_TX;
4568 return true;
4569}
4570#endif
4571
4572static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004573 struct hdd_adapter *adapter, struct survey_info *survey, int idx)
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304574{
4575 bool filled = false;
4576 int i, j = 0;
4577 uint32_t channel = 0, opfreq; /* Initialization Required */
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004578 struct hdd_context *hdd_ctx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304579
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004580 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson1b780e42017-10-31 14:11:45 -07004581 sme_get_operation_channel(hdd_ctx->hHal, &channel, adapter->session_id);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304582 hdd_wlan_get_freq(channel, &opfreq);
4583
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004584 mutex_lock(&hdd_ctx->chan_info_lock);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304585
Srinivas Girigowda5da651b2017-08-04 11:22:54 -07004586 for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) {
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304587 if (wiphy->bands[i] == NULL)
4588 continue;
4589
4590 for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
4591 struct ieee80211_supported_band *band = wiphy->bands[i];
Jeff Johnson4f7f7c62017-10-05 08:53:41 -07004592
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304593 filled = wlan_fill_survey_result(survey, opfreq,
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004594 &hdd_ctx->chan_info[idx],
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304595 &band->channels[j]);
4596 }
4597 }
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004598 mutex_unlock(&hdd_ctx->chan_info_lock);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304599
4600 return filled;
4601}
4602
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004603/**
4604 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
4605 * @wiphy: Pointer to wiphy
4606 * @dev: Pointer to network device
4607 * @idx: Index
4608 * @survey: Pointer to survey info
4609 *
4610 * Return: 0 for success, non-zero for failure
4611 */
4612static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4613 struct net_device *dev,
4614 int idx, struct survey_info *survey)
4615{
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004616 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004617 struct hdd_context *hdd_ctx;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004618 struct hdd_station_ctx *sta_ctx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304619 int status;
4620 bool filled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004621
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004622 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004623
Srinivas Girigowda6598eea2017-07-06 19:26:19 -07004624 hdd_debug("dump survey index: %d", idx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304625 if (idx > QDF_MAX_NUM_CHAN - 1)
4626 return -EINVAL;
4627
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004628 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004629 status = wlan_hdd_validate_context(hdd_ctx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304630 if (0 != status)
4631 return status;
4632
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004633 if (hdd_ctx->chan_info == NULL) {
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304634 hdd_err("chan_info is NULL");
4635 return -EINVAL;
4636 }
4637
4638 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004639 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004640 return -EINVAL;
4641 }
4642
Jeff Johnsond377dce2017-10-04 10:32:42 -07004643 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004645 if (hdd_ctx->config->fEnableSNRMonitoring == 0)
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304646 return -ENONET;
4647
Jeff Johnson690fe952017-10-25 11:48:39 -07004648 if (sta_ctx->hdd_reassoc_scenario) {
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304649 hdd_info("Roaming in progress, hence return");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004650 return -ENONET;
4651 }
4652
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004653 filled = wlan_hdd_update_survey_info(wiphy, adapter, survey, idx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304654
4655 if (!filled)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004656 return -ENONET;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304657 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658 return 0;
4659}
4660
4661/**
4662 * wlan_hdd_cfg80211_dump_survey() - get survey related info
4663 * @wiphy: Pointer to wiphy
4664 * @dev: Pointer to network device
4665 * @idx: Index
4666 * @survey: Pointer to survey info
4667 *
4668 * Return: 0 for success, non-zero for failure
4669 */
4670int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4671 struct net_device *dev,
4672 int idx, struct survey_info *survey)
4673{
4674 int ret;
4675
4676 cds_ssr_protect(__func__);
4677 ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
4678 cds_ssr_unprotect(__func__);
4679
4680 return ret;
4681}
4682/**
4683 * hdd_init_ll_stats_ctx() - initialize link layer stats context
4684 *
4685 * Return: none
4686 */
4687inline void hdd_init_ll_stats_ctx(void)
4688{
4689 spin_lock_init(&ll_stats_context.context_lock);
4690 init_completion(&ll_stats_context.response_event);
4691 ll_stats_context.request_bitmap = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004692}
Nirav Shahbf1b0332016-05-25 14:27:39 +05304693
4694/**
4695 * hdd_display_hif_stats() - display hif stats
4696 *
4697 * Return: none
4698 *
4699 */
4700void hdd_display_hif_stats(void)
4701{
4702 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
4703
4704 if (!hif_ctx)
4705 return;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -07004706
Nirav Shahbf1b0332016-05-25 14:27:39 +05304707 hif_display_stats(hif_ctx);
4708}
4709
4710/**
4711 * hdd_clear_hif_stats() - clear hif stats
4712 *
4713 * Return: none
4714 */
4715void hdd_clear_hif_stats(void)
4716{
4717 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
4718
4719 if (!hif_ctx)
4720 return;
4721 hif_clear_stats(hif_ctx);
4722}
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05304723
4724/**
4725 * hdd_is_rcpi_applicable() - validates RCPI request
4726 * @adapter: adapter upon which the measurement is requested
4727 * @mac_addr: peer addr for which measurement is requested
4728 * @rcpi_value: pointer to where the RCPI should be returned
4729 * @reassoc: used to return cached RCPI during reassoc
4730 *
4731 * Return: true for success, false for failure
4732 */
4733
4734static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter,
4735 struct qdf_mac_addr *mac_addr,
4736 int32_t *rcpi_value,
4737 bool *reassoc)
4738{
4739 struct hdd_station_ctx *hdd_sta_ctx;
4740
4741 if (adapter->device_mode == QDF_STA_MODE ||
4742 adapter->device_mode == QDF_P2P_CLIENT_MODE) {
4743 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4744 if (hdd_sta_ctx->conn_info.connState !=
4745 eConnectionState_Associated)
4746 return false;
4747
4748 if (hdd_sta_ctx->hdd_reassoc_scenario) {
4749 /* return the cached rcpi, if mac addr matches */
4750 hdd_debug("Roaming in progress, return cached RCPI");
4751 if (!qdf_mem_cmp(&adapter->rcpi.mac_addr,
4752 mac_addr, sizeof(*mac_addr))) {
4753 *rcpi_value = adapter->rcpi.rcpi;
4754 *reassoc = true;
4755 return true;
4756 }
4757 return false;
4758 }
4759
4760 if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssId,
4761 sizeof(*mac_addr))) {
4762 hdd_err("mac addr is different from bssid connected");
4763 return false;
4764 }
4765 } else if (adapter->device_mode == QDF_SAP_MODE ||
4766 adapter->device_mode == QDF_P2P_GO_MODE) {
4767 if (!test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) {
4768 hdd_err("Invalid rcpi request, softap not started");
4769 return false;
4770 }
4771
4772 /* check if peer mac addr is associated to softap */
4773 if (!hdd_is_peer_associated(adapter, mac_addr)) {
4774 hdd_err("invalid peer mac-addr: not associated");
4775 return false;
4776 }
4777 } else {
4778 hdd_err("Invalid rcpi request");
4779 return false;
4780 }
4781
4782 *reassoc = false;
4783 return true;
4784}
4785
4786/**
4787 * wlan_hdd_get_rcpi_cb() - callback function for rcpi response
4788 * @context: Pointer to rcpi context
4789 * @rcpi_req: Pointer to rcpi response
4790 *
4791 * Return: None
4792 */
4793static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr,
4794 int32_t rcpi, QDF_STATUS status)
4795{
4796 struct hdd_request *request;
4797 struct rcpi_info *priv;
4798
4799 if (!context) {
4800 hdd_err("No rcpi context");
4801 return;
4802 }
4803
4804 request = hdd_request_get(context);
4805 if (!request) {
4806 hdd_err("Obsolete RCPI request");
4807 return;
4808 }
4809
4810 priv = hdd_request_priv(request);
4811 priv->mac_addr = mac_addr;
4812
4813 if (!QDF_IS_STATUS_SUCCESS(status)) {
4814 priv->rcpi = 0;
4815 hdd_err("Error in computing RCPI");
4816 } else {
4817 priv->rcpi = rcpi;
4818 }
4819
4820 hdd_request_complete(request);
4821 hdd_request_put(request);
4822}
4823
4824/**
4825 * __wlan_hdd_get_rcpi() - local function to get RCPI
4826 * @adapter: adapter upon which the measurement is requested
4827 * @mac: peer addr for which measurement is requested
4828 * @rcpi_value: pointer to where the RCPI should be returned
4829 * @measurement_type: type of rcpi measurement
4830 *
4831 * Return: 0 for success, non-zero for failure
4832 */
4833static int __wlan_hdd_get_rcpi(struct hdd_adapter *adapter,
4834 uint8_t *mac,
4835 int32_t *rcpi_value,
4836 enum rcpi_measurement_type measurement_type)
4837{
4838 struct hdd_context *hdd_ctx;
4839 int status = 0, ret = 0;
4840 struct qdf_mac_addr mac_addr;
4841 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
4842 struct sme_rcpi_req *rcpi_req;
4843 void *cookie;
4844 struct rcpi_info *priv;
4845 struct hdd_request *request;
4846 static const struct hdd_request_params params = {
4847 .priv_size = sizeof(*priv),
4848 .timeout_ms = WLAN_WAIT_TIME_RCPI,
4849 };
4850 bool reassoc;
4851
4852 ENTER();
4853
4854 /* initialize the rcpi value to zero, useful in error cases */
4855 *rcpi_value = 0;
4856
4857 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
4858 hdd_err("Command not allowed in FTM mode");
4859 return -EINVAL;
4860 }
4861
4862 if (!adapter) {
4863 hdd_warn("adapter context is NULL");
4864 return -EINVAL;
4865 }
4866
4867 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
4868 status = wlan_hdd_validate_context(hdd_ctx);
4869 if (status)
4870 return -EINVAL;
4871
4872 if (!hdd_ctx->rcpi_enabled) {
4873 hdd_debug("RCPI not supported");
4874 return -EINVAL;
4875 }
4876
4877 if (!mac) {
4878 hdd_warn("RCPI peer mac-addr is NULL");
4879 return -EINVAL;
4880 }
4881
4882 qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE);
4883
4884 if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc))
4885 return -EINVAL;
4886 if (reassoc)
4887 return 0;
4888
4889 rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
4890 if (!rcpi_req) {
4891 hdd_err("unable to allocate memory for RCPI req");
4892 return -EINVAL;
4893 }
4894
4895 request = hdd_request_alloc(&params);
4896 if (!request) {
4897 hdd_err("Request allocation failure");
4898 qdf_mem_free(rcpi_req);
4899 return -ENOMEM;
4900 }
4901 cookie = hdd_request_cookie(request);
4902
4903 rcpi_req->mac_addr = mac_addr;
Jeff Johnson1b780e42017-10-31 14:11:45 -07004904 rcpi_req->session_id = adapter->session_id;
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05304905 rcpi_req->measurement_type = measurement_type;
4906 rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb;
4907 rcpi_req->rcpi_context = cookie;
4908
4909 qdf_status = sme_get_rcpi(hdd_ctx->hHal, rcpi_req);
4910 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
4911 hdd_err("Unable to retrieve RCPI");
4912 status = qdf_status_to_os_return(qdf_status);
4913 goto out;
4914 }
4915
4916 /* request was sent -- wait for the response */
4917 ret = hdd_request_wait_for_response(request);
4918 if (ret) {
4919 hdd_err("SME timed out while retrieving RCPI");
4920 status = -EINVAL;
4921 goto out;
4922 }
4923
4924 /* update the adapter with the fresh results */
4925 priv = hdd_request_priv(request);
4926 adapter->rcpi.mac_addr = priv->mac_addr;
4927 adapter->rcpi.rcpi = priv->rcpi;
4928 if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) {
4929 hdd_err("mis match of mac addr from call-back");
4930 status = -EINVAL;
4931 goto out;
4932 }
4933
4934 *rcpi_value = adapter->rcpi.rcpi;
4935 hdd_debug("RCPI = %d", *rcpi_value);
4936out:
4937 qdf_mem_free(rcpi_req);
4938 hdd_request_put(request);
4939
4940 EXIT();
4941 return status;
4942}
4943
4944int wlan_hdd_get_rcpi(struct hdd_adapter *adapter, uint8_t *mac,
4945 int32_t *rcpi_value,
4946 enum rcpi_measurement_type measurement_type)
4947{
4948 int ret;
4949
4950 cds_ssr_protect(__func__);
4951 ret = __wlan_hdd_get_rcpi(adapter, mac, rcpi_value, measurement_type);
4952 cds_ssr_unprotect(__func__);
4953
4954 return ret;
4955}