xref: /wlan-dirver/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c (revision 0bec9a925953c0d92cb530c808dd67de56a0923e)
1 /*
2  * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
3  *
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"
33 #include "wlan_hdd_lpass.h"
34 #include "hif.h"
35 #include <qca_vendor.h>
36 #include "wma_api.h"
37 #include "wlan_hdd_debugfs_llstat.h"
38 
39 /* 11B, 11G Rate table include Basic rate and Extended rate
40  * The IDX field is the rate index
41  * The HI field is the rate when RSSI is strong or being ignored
42  *  (in this case we report actual rate)
43  * The MID field is the rate when RSSI is moderate
44  * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
45  * The LO field is the rate when RSSI is low
46  *  (in this case we don't report rates, actual current rate used)
47  */
48 static const struct index_data_rate_type supported_data_rate[] = {
49 	/* IDX     HI  HM  LM LO (RSSI-based index */
50 	{2,   { 10,  10, 10, 0} },
51 	{4,   { 20,  20, 10, 0} },
52 	{11,  { 55,  20, 10, 0} },
53 	{12,  { 60,  55, 20, 0} },
54 	{18,  { 90,  55, 20, 0} },
55 	{22,  {110,  55, 20, 0} },
56 	{24,  {120,  90, 60, 0} },
57 	{36,  {180, 120, 60, 0} },
58 	{44,  {220, 180, 60, 0} },
59 	{48,  {240, 180, 90, 0} },
60 	{66,  {330, 180, 90, 0} },
61 	{72,  {360, 240, 90, 0} },
62 	{96,  {480, 240, 120, 0} },
63 	{108, {540, 240, 120, 0} }
64 };
65 /* MCS Based rate table HT MCS parameters with Nss = 1 */
66 static struct index_data_rate_type supported_mcs_rate_nss1[] = {
67 /* MCS  L20   L40   S20  S40 */
68 	{0, {65, 135, 72, 150} },
69 	{1, {130, 270, 144, 300} },
70 	{2, {195, 405, 217, 450} },
71 	{3, {260, 540, 289, 600} },
72 	{4, {390, 810, 433, 900} },
73 	{5, {520, 1080, 578, 1200} },
74 	{6, {585, 1215, 650, 1350} },
75 	{7, {650, 1350, 722, 1500} }
76 };
77 
78 /* HT MCS parameters with Nss = 2 */
79 static struct index_data_rate_type supported_mcs_rate_nss2[] = {
80 /* MCS  L20    L40   S20   S40 */
81 	{0, {130, 270, 144, 300} },
82 	{1, {260, 540, 289, 600} },
83 	{2, {390, 810, 433, 900} },
84 	{3, {520, 1080, 578, 1200} },
85 	{4, {780, 1620, 867, 1800} },
86 	{5, {1040, 2160, 1156, 2400} },
87 	{6, {1170, 2430, 1300, 2700} },
88 	{7, {1300, 2700, 1444, 3000} }
89 };
90 
91 /* MCS Based VHT rate table MCS parameters with Nss = 1*/
92 static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
93 /* MCS  L80    S80     L40   S40    L20   S40*/
94 	{0, {293, 325}, {135, 150}, {65, 72} },
95 	{1, {585, 650}, {270, 300}, {130, 144} },
96 	{2, {878, 975}, {405, 450}, {195, 217} },
97 	{3, {1170, 1300}, {540, 600}, {260, 289} },
98 	{4, {1755, 1950}, {810, 900}, {390, 433} },
99 	{5, {2340, 2600}, {1080, 1200}, {520, 578} },
100 	{6, {2633, 2925}, {1215, 1350}, {585, 650} },
101 	{7, {2925, 3250}, {1350, 1500}, {650, 722} },
102 	{8, {3510, 3900}, {1620, 1800}, {780, 867} },
103 	{9, {3900, 4333}, {1800, 2000}, {780, 867} }
104 };
105 
106 /*MCS parameters with Nss = 2*/
107 static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
108 /* MCS  L80    S80     L40   S40    L20   S40*/
109 	{0, {585, 650}, {270, 300}, {130, 144} },
110 	{1, {1170, 1300}, {540, 600}, {260, 289} },
111 	{2, {1755, 1950}, {810, 900}, {390, 433} },
112 	{3, {2340, 2600}, {1080, 1200}, {520, 578} },
113 	{4, {3510, 3900}, {1620, 1800}, {780, 867} },
114 	{5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
115 	{6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
116 	{7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
117 	{8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
118 	{9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
119 };
120 
121 /*array index ponints to MCS and array value points respective rssi*/
122 static int rssi_mcs_tbl[][10] = {
123 /*MCS 0   1     2   3    4    5    6    7    8    9*/
124 	{-82, -79, -77, -74, -70, -66, -65, -64, -59, -57},     /* 20 */
125 	{-79, -76, -74, -71, -67, -63, -62, -61, -56, -54},     /* 40 */
126 	{-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */
127 };
128 
129 
130 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
131 static struct hdd_ll_stats_context ll_stats_context;
132 
133 /**
134  * put_wifi_rate_stat() - put wifi rate stats
135  * @stats: Pointer to stats context
136  * @vendor_event: Pointer to vendor event
137  *
138  * Return: bool
139  */
140 static bool put_wifi_rate_stat(tpSirWifiRateStat stats,
141 			       struct sk_buff *vendor_event)
142 {
143 	if (nla_put_u8(vendor_event,
144 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
145 		       stats->rate.preamble) ||
146 	    nla_put_u8(vendor_event,
147 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
148 		       stats->rate.nss) ||
149 	    nla_put_u8(vendor_event,
150 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
151 		       stats->rate.bw) ||
152 	    nla_put_u8(vendor_event,
153 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
154 		       stats->rate.rateMcsIdx) ||
155 	    nla_put_u32(vendor_event,
156 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
157 			stats->rate.bitrate) ||
158 	    nla_put_u32(vendor_event,
159 			   QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
160 			   stats->txMpdu) ||
161 	    nla_put_u32(vendor_event,
162 			   QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
163 			   stats->rxMpdu) ||
164 	    nla_put_u32(vendor_event,
165 			   QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
166 			   stats->mpduLost) ||
167 	    nla_put_u32(vendor_event,
168 			   QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
169 			   stats->retries) ||
170 	    nla_put_u32(vendor_event,
171 			   QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
172 			   stats->retriesShort) ||
173 	    nla_put_u32(vendor_event,
174 			   QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
175 			   stats->retriesLong)) {
176 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
177 		return false;
178 	}
179 
180 	return true;
181 }
182 
183 /**
184  * put_wifi_peer_info() - put wifi peer info
185  * @stats: Pointer to stats context
186  * @vendor_event: Pointer to vendor event
187  *
188  * Return: bool
189  */
190 static bool put_wifi_peer_info(tpSirWifiPeerInfo stats,
191 			       struct sk_buff *vendor_event)
192 {
193 	u32 i = 0;
194 	tpSirWifiRateStat pRateStats;
195 
196 	if (nla_put_u32
197 		    (vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
198 		    wmi_to_sir_peer_type(stats->type)) ||
199 	    nla_put(vendor_event,
200 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
201 		       QDF_MAC_ADDR_SIZE, &stats->peerMacAddress.bytes[0]) ||
202 	    nla_put_u32(vendor_event,
203 			   QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
204 			   stats->capabilities) ||
205 	    nla_put_u32(vendor_event,
206 			   QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
207 			   stats->numRate)) {
208 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
209 		goto error;
210 	}
211 
212 	if (stats->numRate) {
213 		struct nlattr *rateInfo;
214 		struct nlattr *rates;
215 
216 		rateInfo = nla_nest_start(vendor_event,
217 					  QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO);
218 		if (rateInfo == NULL)
219 			goto error;
220 
221 		for (i = 0; i < stats->numRate; i++) {
222 			pRateStats = (tpSirWifiRateStat) ((uint8_t *)
223 							  stats->rateStats +
224 							  (i *
225 							   sizeof
226 							   (tSirWifiRateStat)));
227 			rates = nla_nest_start(vendor_event, i);
228 			if (rates == NULL)
229 				goto error;
230 
231 			if (false ==
232 			    put_wifi_rate_stat(pRateStats, vendor_event)) {
233 				hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
234 				return false;
235 			}
236 			nla_nest_end(vendor_event, rates);
237 		}
238 		nla_nest_end(vendor_event, rateInfo);
239 	}
240 
241 	return true;
242 error:
243 	return false;
244 }
245 
246 /**
247  * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
248  * @stats: Pointer to stats context
249  * @vendor_event: Pointer to vendor event
250  *
251  * Return: bool
252  */
253 static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats,
254 				 struct sk_buff *vendor_event)
255 {
256 	if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
257 			stats->ac) ||
258 	    nla_put_u32(vendor_event,
259 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
260 			stats->txMpdu) ||
261 	    nla_put_u32(vendor_event,
262 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
263 			stats->rxMpdu) ||
264 	    nla_put_u32(vendor_event,
265 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
266 			stats->txMcast) ||
267 	    nla_put_u32(vendor_event,
268 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
269 			stats->rxMcast) ||
270 	    nla_put_u32(vendor_event,
271 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
272 			stats->rxAmpdu) ||
273 	    nla_put_u32(vendor_event,
274 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
275 			stats->txAmpdu) ||
276 	    nla_put_u32(vendor_event,
277 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
278 			stats->mpduLost) ||
279 	    nla_put_u32(vendor_event,
280 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
281 			stats->retries) ||
282 	    nla_put_u32(vendor_event,
283 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
284 			stats->retriesShort) ||
285 	    nla_put_u32(vendor_event,
286 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
287 			stats->retriesLong) ||
288 	    nla_put_u32(vendor_event,
289 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
290 			stats->contentionTimeMin) ||
291 	    nla_put_u32(vendor_event,
292 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
293 			stats->contentionTimeMax) ||
294 	    nla_put_u32(vendor_event,
295 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
296 			stats->contentionTimeAvg) ||
297 	    nla_put_u32(vendor_event,
298 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
299 			stats->contentionNumSamples)) {
300 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
301 		return false;
302 	}
303 
304 	return true;
305 }
306 
307 /**
308  * put_wifi_interface_info() - put wifi interface info
309  * @stats: Pointer to stats context
310  * @vendor_event: Pointer to vendor event
311  *
312  * Return: bool
313  */
314 static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats,
315 				    struct sk_buff *vendor_event)
316 {
317 	if (nla_put_u32(vendor_event,
318 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
319 			stats->mode) ||
320 	    nla_put(vendor_event,
321 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
322 		    QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
323 	    nla_put_u32(vendor_event,
324 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
325 			stats->state) ||
326 	    nla_put_u32(vendor_event,
327 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
328 			stats->roaming) ||
329 	    nla_put_u32(vendor_event,
330 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
331 			stats->capabilities) ||
332 	    nla_put(vendor_event,
333 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
334 		    strlen(stats->ssid), stats->ssid) ||
335 	    nla_put(vendor_event,
336 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
337 		    QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
338 	    nla_put(vendor_event,
339 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
340 		    WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) ||
341 	    nla_put(vendor_event,
342 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
343 		    WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) {
344 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
345 		return false;
346 	}
347 
348 	return true;
349 }
350 
351 /**
352  * put_wifi_iface_stats() - put wifi interface stats
353  * @pWifiIfaceStat: Pointer to interface stats context
354  * @num_peer: Number of peers
355  * @vendor_event: Pointer to vendor event
356  *
357  * Return: bool
358  */
359 static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
360 				 u32 num_peers, struct sk_buff *vendor_event)
361 {
362 	int i = 0;
363 	struct nlattr *wmmInfo;
364 	struct nlattr *wmmStats;
365 	u64 average_tsf_offset;
366 
367 	if (false == put_wifi_interface_info(&pWifiIfaceStat->info,
368 					     vendor_event)) {
369 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
370 		return false;
371 
372 	}
373 
374 	average_tsf_offset =  pWifiIfaceStat->avg_bcn_spread_offset_high;
375 	average_tsf_offset =  (average_tsf_offset << 32) |
376 		pWifiIfaceStat->avg_bcn_spread_offset_low;
377 
378 	if (nla_put_u32(vendor_event,
379 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
380 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) ||
381 	    nla_put_u32(vendor_event,
382 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
383 			num_peers) ||
384 	    nla_put_u32(vendor_event,
385 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
386 			pWifiIfaceStat->beaconRx) ||
387 	    nla_put_u32(vendor_event,
388 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
389 			pWifiIfaceStat->mgmtRx) ||
390 	    nla_put_u32(vendor_event,
391 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
392 			pWifiIfaceStat->mgmtActionRx) ||
393 	    nla_put_u32(vendor_event,
394 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
395 			pWifiIfaceStat->mgmtActionTx) ||
396 	    nla_put_u32(vendor_event,
397 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
398 			pWifiIfaceStat->rssiMgmt) ||
399 	    nla_put_u32(vendor_event,
400 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
401 			pWifiIfaceStat->rssiData) ||
402 	    nla_put_u32(vendor_event,
403 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
404 			pWifiIfaceStat->rssiAck) ||
405 	    nla_put_u32(vendor_event,
406 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
407 			pWifiIfaceStat->is_leaky_ap) ||
408 	    nla_put_u32(vendor_event,
409 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
410 			pWifiIfaceStat->avg_rx_frms_leaked) ||
411 	    nla_put_u32(vendor_event,
412 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
413 			pWifiIfaceStat->rx_leak_window) ||
414 	    hdd_wlan_nla_put_u64(vendor_event,
415 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
416 			average_tsf_offset) ||
417 	    nla_put_u32(vendor_event,
418 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT,
419 			pWifiIfaceStat->rts_succ_cnt) ||
420 	    nla_put_u32(vendor_event,
421 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT,
422 			pWifiIfaceStat->rts_fail_cnt) ||
423 	    nla_put_u32(vendor_event,
424 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT,
425 			pWifiIfaceStat->ppdu_succ_cnt) ||
426 	    nla_put_u32(vendor_event,
427 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT,
428 			pWifiIfaceStat->ppdu_fail_cnt)) {
429 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
430 		return false;
431 	}
432 
433 	wmmInfo = nla_nest_start(vendor_event,
434 				 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
435 	if (wmmInfo == NULL)
436 		return false;
437 
438 	for (i = 0; i < WIFI_AC_MAX; i++) {
439 		wmmStats = nla_nest_start(vendor_event, i);
440 		if (wmmStats == NULL)
441 			return false;
442 
443 		if (false ==
444 		    put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i],
445 					 vendor_event)) {
446 			hdd_err("put_wifi_wmm_ac_stat Fail");
447 			return false;
448 		}
449 
450 		nla_nest_end(vendor_event, wmmStats);
451 	}
452 	nla_nest_end(vendor_event, wmmInfo);
453 	return true;
454 }
455 
456 /**
457  * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
458  * @deviceMode: Device mode
459  *
460  * Return: interface mode
461  */
462 static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode)
463 {
464 	switch (deviceMode) {
465 	case QDF_STA_MODE:
466 		return WIFI_INTERFACE_STA;
467 	case QDF_SAP_MODE:
468 		return WIFI_INTERFACE_SOFTAP;
469 	case QDF_P2P_CLIENT_MODE:
470 		return WIFI_INTERFACE_P2P_CLIENT;
471 	case QDF_P2P_GO_MODE:
472 		return WIFI_INTERFACE_P2P_GO;
473 	case QDF_IBSS_MODE:
474 		return WIFI_INTERFACE_IBSS;
475 	default:
476 		/* Return Interface Mode as STA for all the unsupported modes */
477 		return WIFI_INTERFACE_STA;
478 	}
479 }
480 
481 bool hdd_get_interface_info(struct hdd_adapter *pAdapter,
482 			    tpSirWifiInterfaceInfo pInfo)
483 {
484 	uint8_t *staMac = NULL;
485 	struct hdd_station_ctx *pHddStaCtx;
486 	tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
487 	tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
488 
489 	pInfo->mode = hdd_map_device_to_ll_iface_mode(pAdapter->device_mode);
490 
491 	qdf_copy_macaddr(&pInfo->macAddr, &pAdapter->macAddressCurrent);
492 
493 	if (((QDF_STA_MODE == pAdapter->device_mode) ||
494 	     (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
495 	     (QDF_P2P_DEVICE_MODE == pAdapter->device_mode))) {
496 		pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
497 		if (eConnectionState_NotConnected ==
498 		    pHddStaCtx->conn_info.connState) {
499 			pInfo->state = WIFI_DISCONNECTED;
500 		}
501 		if (eConnectionState_Connecting ==
502 		    pHddStaCtx->conn_info.connState) {
503 			hdd_err("Session ID %d, Connection is in progress",
504 				pAdapter->sessionId);
505 			pInfo->state = WIFI_ASSOCIATING;
506 		}
507 		if ((eConnectionState_Associated ==
508 		     pHddStaCtx->conn_info.connState)
509 		    && (false == pHddStaCtx->conn_info.uIsAuthenticated)) {
510 			staMac =
511 				(uint8_t *) &(pAdapter->macAddressCurrent.
512 					      bytes[0]);
513 			hdd_err("client " MAC_ADDRESS_STR
514 				" is in the middle of WPS/EAPOL exchange.",
515 				MAC_ADDR_ARRAY(staMac));
516 			pInfo->state = WIFI_AUTHENTICATING;
517 		}
518 		if (eConnectionState_Associated ==
519 		    pHddStaCtx->conn_info.connState) {
520 			pInfo->state = WIFI_ASSOCIATED;
521 			qdf_copy_macaddr(&pInfo->bssid,
522 					 &pHddStaCtx->conn_info.bssId);
523 			qdf_mem_copy(pInfo->ssid,
524 				     pHddStaCtx->conn_info.SSID.SSID.ssId,
525 				     pHddStaCtx->conn_info.SSID.SSID.length);
526 			/*
527 			 * NULL Terminate the string
528 			 */
529 			pInfo->ssid[pHddStaCtx->conn_info.SSID.SSID.length] = 0;
530 		}
531 	}
532 
533 	qdf_mem_copy(pInfo->countryStr,
534 		     pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
535 
536 	qdf_mem_copy(pInfo->apCountryStr,
537 		     pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
538 
539 	return true;
540 }
541 
542 /**
543  * hdd_link_layer_process_peer_stats() - This function is called after
544  * @pAdapter: Pointer to device adapter
545  * @more_data: More data
546  * @pData: Pointer to stats data
547  *
548  * Receiving Link Layer Peer statistics from FW.This function converts
549  * the firmware data to the NL data and sends the same to the kernel/upper
550  * layers.
551  *
552  * Return: None
553  */
554 static void hdd_link_layer_process_peer_stats(struct hdd_adapter *pAdapter,
555 					      u32 more_data,
556 					      tpSirWifiPeerStat pData)
557 {
558 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
559 	tpSirWifiPeerStat pWifiPeerStat;
560 	tpSirWifiPeerInfo pWifiPeerInfo;
561 	struct sk_buff *vendor_event;
562 	int status, i;
563 	struct nlattr *peers;
564 	int numRate;
565 
566 	ENTER();
567 
568 	pWifiPeerStat = pData;
569 
570 	status = wlan_hdd_validate_context(hdd_ctx);
571 	if (0 != status)
572 		return;
573 
574 	hdd_debug("LL_STATS_PEER_ALL : numPeers %u, more data = %u",
575 		   pWifiPeerStat->numPeers, more_data);
576 
577 	/*
578 	 * Allocate a size of 4096 for the peer stats comprising
579 	 * each of size = sizeof (tSirWifiPeerInfo) + numRate *
580 	 * sizeof (tSirWifiRateStat).Each field is put with an
581 	 * NL attribute.The size of 4096 is considered assuming
582 	 * that number of rates shall not exceed beyond 50 with
583 	 * the sizeof (tSirWifiRateStat) being 32.
584 	 */
585 	vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
586 				LL_STATS_EVENT_BUF_SIZE);
587 
588 	if (!vendor_event) {
589 		hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
590 		return;
591 	}
592 
593 	if (nla_put_u32(vendor_event,
594 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
595 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
596 	    nla_put_u32(vendor_event,
597 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
598 			more_data) ||
599 	    nla_put_u32(vendor_event,
600 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
601 			pWifiPeerStat->numPeers)) {
602 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
603 
604 		kfree_skb(vendor_event);
605 		return;
606 	}
607 
608 	pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
609 					     pWifiPeerStat->peerInfo);
610 
611 	if (pWifiPeerStat->numPeers) {
612 		struct nlattr *peerInfo;
613 
614 		peerInfo = nla_nest_start(vendor_event,
615 					  QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO);
616 		if (peerInfo == NULL) {
617 			hdd_err("nla_nest_start failed");
618 			kfree_skb(vendor_event);
619 			return;
620 		}
621 
622 		for (i = 1; i <= pWifiPeerStat->numPeers; i++) {
623 			peers = nla_nest_start(vendor_event, i);
624 			if (peers == NULL) {
625 				hdd_err("nla_nest_start failed");
626 				kfree_skb(vendor_event);
627 				return;
628 			}
629 
630 			numRate = pWifiPeerInfo->numRate;
631 
632 			if (false ==
633 			    put_wifi_peer_info(pWifiPeerInfo, vendor_event)) {
634 				hdd_err("put_wifi_peer_info fail");
635 				kfree_skb(vendor_event);
636 				return;
637 			}
638 
639 			pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
640 							     pWifiPeerStat->
641 							     peerInfo +
642 							     (i *
643 							      sizeof
644 							      (tSirWifiPeerInfo))
645 							     +
646 							     (numRate *
647 							      sizeof
648 							      (tSirWifiRateStat)));
649 			nla_nest_end(vendor_event, peers);
650 		}
651 		nla_nest_end(vendor_event, peerInfo);
652 	}
653 
654 	cfg80211_vendor_cmd_reply(vendor_event);
655 	EXIT();
656 }
657 
658 /**
659  * hdd_link_layer_process_iface_stats() - This function is called after
660  * @pAdapter: Pointer to device adapter
661  * @pData: Pointer to stats data
662  * @num_peers: Number of peers
663  *
664  * Receiving Link Layer Interface statistics from FW.This function converts
665  * the firmware data to the NL data and sends the same to the kernel/upper
666  * layers.
667  *
668  * Return: None
669  */
670 static void hdd_link_layer_process_iface_stats(struct hdd_adapter *pAdapter,
671 					       tpSirWifiIfaceStat pData,
672 					       u32 num_peers)
673 {
674 	tpSirWifiIfaceStat pWifiIfaceStat;
675 	struct sk_buff *vendor_event;
676 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
677 	int status;
678 
679 	ENTER();
680 
681 	pWifiIfaceStat = pData;
682 
683 	status = wlan_hdd_validate_context(hdd_ctx);
684 	if (0 != status)
685 		return;
686 
687 	/*
688 	 * Allocate a size of 4096 for the interface stats comprising
689 	 * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered
690 	 * assuming that all these fit with in the limit.Please take
691 	 * a call on the limit based on the data requirements on
692 	 * interface statistics.
693 	 */
694 	vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
695 				LL_STATS_EVENT_BUF_SIZE);
696 
697 	if (!vendor_event) {
698 		hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
699 		return;
700 	}
701 
702 	hdd_debug("WMI_LINK_STATS_IFACE Data");
703 
704 	if (false == hdd_get_interface_info(pAdapter, &pWifiIfaceStat->info)) {
705 		hdd_err("hdd_get_interface_info get fail");
706 		kfree_skb(vendor_event);
707 		return;
708 	}
709 
710 	if (false ==
711 	    put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) {
712 		hdd_err("put_wifi_iface_stats fail");
713 		kfree_skb(vendor_event);
714 		return;
715 	}
716 
717 	cfg80211_vendor_cmd_reply(vendor_event);
718 	EXIT();
719 }
720 
721 /**
722  * hdd_llstats_radio_fill_channels() - radio stats fill channels
723  * @adapter: Pointer to device adapter
724  * @radiostat: Pointer to stats data
725  * @vendor_event: vendor event
726  *
727  * Return: 0 on success; errno on failure
728  */
729 static int hdd_llstats_radio_fill_channels(struct hdd_adapter *adapter,
730 					   tSirWifiRadioStat *radiostat,
731 					   struct sk_buff *vendor_event)
732 {
733 	tSirWifiChannelStats *channel_stats;
734 	struct nlattr *chlist;
735 	struct nlattr *chinfo;
736 	int i;
737 
738 	chlist = nla_nest_start(vendor_event,
739 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
740 	if (chlist == NULL) {
741 		hdd_err("nla_nest_start failed");
742 		return -EINVAL;
743 	}
744 
745 	for (i = 0; i < radiostat->numChannels; i++) {
746 		channel_stats = (tSirWifiChannelStats *) ((uint8_t *)
747 				     radiostat->channels +
748 				     (i * sizeof(tSirWifiChannelStats)));
749 
750 		chinfo = nla_nest_start(vendor_event, i);
751 		if (chinfo == NULL) {
752 			hdd_err("nla_nest_start failed");
753 			return -EINVAL;
754 		}
755 
756 		if (nla_put_u32(vendor_event,
757 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
758 				channel_stats->channel.width) ||
759 		    nla_put_u32(vendor_event,
760 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
761 				channel_stats->channel.centerFreq) ||
762 		    nla_put_u32(vendor_event,
763 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
764 				channel_stats->channel.centerFreq0) ||
765 		    nla_put_u32(vendor_event,
766 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
767 				channel_stats->channel.centerFreq1) ||
768 		    nla_put_u32(vendor_event,
769 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
770 				channel_stats->onTime) ||
771 		    nla_put_u32(vendor_event,
772 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
773 				channel_stats->ccaBusyTime)) {
774 			hdd_err("nla_put failed");
775 			return -EINVAL;
776 		}
777 		nla_nest_end(vendor_event, chinfo);
778 	}
779 	nla_nest_end(vendor_event, chlist);
780 
781 	return 0;
782 }
783 
784 /**
785  * hdd_llstats_post_radio_stats() - post radio stats
786  * @adapter: Pointer to device adapter
787  * @more_data: More data
788  * @radiostat: Pointer to stats data
789  * @num_radio: Number of radios
790  *
791  * Return: 0 on success; errno on failure
792  */
793 static int hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
794 					u32 more_data,
795 					tSirWifiRadioStat *radiostat,
796 					u32 num_radio)
797 {
798 	struct sk_buff *vendor_event;
799 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
800 	int ret;
801 
802 	/*
803 	 * Allocate a size of 4096 for the Radio stats comprising
804 	 * sizeof (tSirWifiRadioStat) + numChannels * sizeof
805 	 * (tSirWifiChannelStats).Each channel data is put with an
806 	 * NL attribute.The size of 4096 is considered assuming that
807 	 * number of channels shall not exceed beyond  60 with the
808 	 * sizeof (tSirWifiChannelStats) being 24 bytes.
809 	 */
810 
811 	vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(
812 					hdd_ctx->wiphy,
813 					LL_STATS_EVENT_BUF_SIZE);
814 
815 	if (!vendor_event) {
816 		hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
817 		return -ENOMEM;
818 	}
819 
820 	if (nla_put_u32(vendor_event,
821 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
822 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
823 	    nla_put_u32(vendor_event,
824 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
825 			more_data) ||
826 	    nla_put_u32(vendor_event,
827 			QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
828 			num_radio) ||
829 	    nla_put_u32(vendor_event,
830 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
831 			radiostat->radio) ||
832 	    nla_put_u32(vendor_event,
833 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
834 			radiostat->onTime) ||
835 	    nla_put_u32(vendor_event,
836 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
837 			radiostat->txTime) ||
838 	    nla_put_u32(vendor_event,
839 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
840 			radiostat->rxTime) ||
841 	    nla_put_u32(vendor_event,
842 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
843 			radiostat->onTimeScan) ||
844 	    nla_put_u32(vendor_event,
845 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
846 			radiostat->onTimeNbd) ||
847 	    nla_put_u32(vendor_event,
848 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
849 			radiostat->onTimeGscan) ||
850 	    nla_put_u32(vendor_event,
851 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
852 			radiostat->onTimeRoamScan) ||
853 	    nla_put_u32(vendor_event,
854 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
855 			radiostat->onTimePnoScan) ||
856 	    nla_put_u32(vendor_event,
857 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
858 			radiostat->onTimeHs20) ||
859 	    nla_put_u32(vendor_event,
860 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
861 			radiostat->total_num_tx_power_levels)    ||
862 	    nla_put_u32(vendor_event,
863 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
864 			radiostat->numChannels)) {
865 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
866 		goto failure;
867 	}
868 
869 	if (radiostat->total_num_tx_power_levels) {
870 		if (nla_put(vendor_event,
871 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
872 			    sizeof(u32) *
873 			    radiostat->total_num_tx_power_levels,
874 			    radiostat->tx_time_per_power_level)) {
875 			hdd_err("nla_put fail");
876 			goto failure;
877 		}
878 	}
879 
880 	if (radiostat->numChannels) {
881 		ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
882 						      vendor_event);
883 		if (ret)
884 			goto failure;
885 	}
886 
887 	cfg80211_vendor_cmd_reply(vendor_event);
888 	return 0;
889 
890 failure:
891 	kfree_skb(vendor_event);
892 	return -EINVAL;
893 }
894 
895 /**
896  * hdd_link_layer_process_radio_stats() - This function is called after
897  * @pAdapter: Pointer to device adapter
898  * @more_data: More data
899  * @pData: Pointer to stats data
900  * @num_radios: Number of radios
901  *
902  * Receiving Link Layer Radio statistics from FW.This function converts
903  * the firmware data to the NL data and sends the same to the kernel/upper
904  * layers.
905  *
906  * Return: None
907  */
908 static void hdd_link_layer_process_radio_stats(struct hdd_adapter *pAdapter,
909 					       u32 more_data,
910 					       tpSirWifiRadioStat pData,
911 					       u32 num_radio)
912 {
913 	int status, i, nr, ret;
914 	tSirWifiRadioStat *pWifiRadioStat = pData;
915 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
916 
917 	ENTER();
918 
919 	status = wlan_hdd_validate_context(hdd_ctx);
920 	if (0 != status)
921 		return;
922 
923 	hdd_debug("LL_STATS_RADIO: number of radios: %u", num_radio);
924 
925 	for (i = 0; i < num_radio; i++) {
926 		hdd_debug("LL_STATS_RADIO"
927 		       " radio: %u onTime: %u txTime: %u rxTime: %u"
928 		       " onTimeScan: %u onTimeNbd: %u"
929 		       " onTimeGscan: %u onTimeRoamScan: %u"
930 		       " onTimePnoScan: %u  onTimeHs20: %u"
931 		       " numChannels: %u total_num_tx_pwr_levels: %u"
932 		       " on_time_host_scan: %u, on_time_lpi_scan: %u",
933 		       pWifiRadioStat->radio, pWifiRadioStat->onTime,
934 		       pWifiRadioStat->txTime, pWifiRadioStat->rxTime,
935 		       pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd,
936 		       pWifiRadioStat->onTimeGscan,
937 		       pWifiRadioStat->onTimeRoamScan,
938 		       pWifiRadioStat->onTimePnoScan,
939 		       pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels,
940 		       pWifiRadioStat->total_num_tx_power_levels,
941 		       pWifiRadioStat->on_time_host_scan,
942 		       pWifiRadioStat->on_time_lpi_scan);
943 		pWifiRadioStat++;
944 	}
945 
946 	pWifiRadioStat = pData;
947 	for (nr = 0; nr < num_radio; nr++) {
948 		ret = hdd_llstats_post_radio_stats(pAdapter, more_data,
949 						   pWifiRadioStat, num_radio);
950 		if (ret)
951 			return;
952 
953 		pWifiRadioStat++;
954 	}
955 
956 	EXIT();
957 }
958 
959 /**
960  * hdd_ll_process_radio_stats() - Wrapper function for cfg80211/debugfs
961  * @adapter: Pointer to device adapter
962  * @more_data: More data
963  * @data: Pointer to stats data
964  * @num_radios: Number of radios
965  * @resp_id: Response ID from FW
966  *
967  * Receiving Link Layer Radio statistics from FW. This function is a wrapper
968  * function which calls cfg80211/debugfs functions based on the response ID.
969  *
970  * Return: None
971  */
972 static void hdd_ll_process_radio_stats(struct hdd_adapter *adapter,
973 		uint32_t more_data, void *data, uint32_t num_radio,
974 		uint32_t resp_id)
975 {
976 	if (DEBUGFS_LLSTATS_REQID == resp_id)
977 		hdd_debugfs_process_radio_stats(adapter, more_data,
978 			(tpSirWifiRadioStat)data, num_radio);
979 	else
980 		hdd_link_layer_process_radio_stats(adapter, more_data,
981 			(tpSirWifiRadioStat)data, num_radio);
982 }
983 
984 /**
985  * hdd_ll_process_iface_stats() - Wrapper function for cfg80211/debugfs
986  * @adapter: Pointer to device adapter
987  * @data: Pointer to stats data
988  * @num_peers: Number of peers
989  * @resp_id: Response ID from FW
990  *
991  * Receiving Link Layer Radio statistics from FW. This function is a wrapper
992  * function which calls cfg80211/debugfs functions based on the response ID.
993  *
994  * Return: None
995  */
996 static void hdd_ll_process_iface_stats(struct hdd_adapter *adapter,
997 			void *data, uint32_t num_peers, uint32_t resp_id)
998 {
999 	if (DEBUGFS_LLSTATS_REQID == resp_id)
1000 		hdd_debugfs_process_iface_stats(adapter,
1001 				(tpSirWifiIfaceStat) data, num_peers);
1002 	else
1003 		hdd_link_layer_process_iface_stats(adapter,
1004 				(tpSirWifiIfaceStat) data, num_peers);
1005 }
1006 
1007 /**
1008  * hdd_ll_process_peer_stats() - Wrapper function for cfg80211/debugfs
1009  * @adapter: Pointer to device adapter
1010  * @more_data: More data
1011  * @data: Pointer to stats data
1012  * @resp_id: Response ID from FW
1013  *
1014  * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1015  * function which calls cfg80211/debugfs functions based on the response ID.
1016  *
1017  * Return: None
1018  */
1019 static void hdd_ll_process_peer_stats(struct hdd_adapter *adapter,
1020 		uint32_t more_data, void *data, uint32_t resp_id)
1021 {
1022 	if (DEBUGFS_LLSTATS_REQID == resp_id)
1023 		hdd_debugfs_process_peer_stats(adapter, data);
1024 	else
1025 		hdd_link_layer_process_peer_stats(adapter, more_data,
1026 						  (tpSirWifiPeerStat) data);
1027 }
1028 
1029 /**
1030  * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called
1031  * @ctx: Pointer to hdd context
1032  * @indType: Indication type
1033  * @pRsp: Pointer to response
1034  *
1035  * After receiving Link Layer indications from FW.This callback converts the
1036  * firmware data to the NL data and send the same to the kernel/upper layers.
1037  *
1038  * Return: None
1039  */
1040 void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
1041 							int indType, void *pRsp)
1042 {
1043 	struct hdd_context *hdd_ctx = (struct hdd_context *) ctx;
1044 	struct hdd_ll_stats_context *context;
1045 	struct hdd_adapter *pAdapter = NULL;
1046 	tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp;
1047 	int status;
1048 
1049 	status = wlan_hdd_validate_context(hdd_ctx);
1050 	if (status)
1051 		return;
1052 
1053 	pAdapter = hdd_get_adapter_by_vdev(hdd_ctx,
1054 					   linkLayerStatsResults->ifaceId);
1055 
1056 	if (NULL == pAdapter) {
1057 		hdd_err("vdev_id %d does not exist with host",
1058 			linkLayerStatsResults->ifaceId);
1059 		return;
1060 	}
1061 
1062 	hdd_debug("Link Layer Indication indType: %d", indType);
1063 
1064 	switch (indType) {
1065 	case SIR_HAL_LL_STATS_RESULTS_RSP:
1066 	{
1067 		hdd_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %p",
1068 			linkLayerStatsResults->paramId,
1069 			linkLayerStatsResults->ifaceId,
1070 			linkLayerStatsResults->rspId,
1071 			linkLayerStatsResults->moreResultToFollow,
1072 			linkLayerStatsResults->num_radio,
1073 			linkLayerStatsResults->results);
1074 
1075 		context = &ll_stats_context;
1076 		spin_lock(&context->context_lock);
1077 		/* validate response received from target */
1078 		if ((context->request_id != linkLayerStatsResults->rspId) ||
1079 		  !(context->request_bitmap & linkLayerStatsResults->paramId)) {
1080 			spin_unlock(&context->context_lock);
1081 			hdd_err("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
1082 			context->request_id, linkLayerStatsResults->rspId,
1083 			context->request_bitmap, linkLayerStatsResults->paramId);
1084 			return;
1085 		}
1086 		spin_unlock(&context->context_lock);
1087 
1088 		if (linkLayerStatsResults->paramId & WMI_LINK_STATS_RADIO) {
1089 			hdd_ll_process_radio_stats(pAdapter,
1090 				linkLayerStatsResults->moreResultToFollow,
1091 				linkLayerStatsResults->results,
1092 				linkLayerStatsResults->num_radio,
1093 				linkLayerStatsResults->rspId);
1094 
1095 			spin_lock(&context->context_lock);
1096 			if (!linkLayerStatsResults->moreResultToFollow)
1097 				context->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
1098 			spin_unlock(&context->context_lock);
1099 
1100 		} else if (linkLayerStatsResults->paramId &
1101 				WMI_LINK_STATS_IFACE) {
1102 			hdd_ll_process_iface_stats(pAdapter,
1103 				linkLayerStatsResults->results,
1104 				linkLayerStatsResults->num_peers,
1105 				linkLayerStatsResults->rspId);
1106 
1107 			spin_lock(&context->context_lock);
1108 			/* Firmware doesn't send peerstats event if no peers are
1109 			 * connected. HDD should not wait for any peerstats in
1110 			 * this case and return the status to middleware after
1111 			 * receiving iface stats
1112 			 */
1113 			if (!linkLayerStatsResults->num_peers)
1114 				context->request_bitmap &=
1115 					~(WMI_LINK_STATS_ALL_PEER);
1116 			context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
1117 			spin_unlock(&context->context_lock);
1118 
1119 		} else if (linkLayerStatsResults->
1120 			   paramId & WMI_LINK_STATS_ALL_PEER) {
1121 			hdd_ll_process_peer_stats(pAdapter,
1122 				linkLayerStatsResults->moreResultToFollow,
1123 				linkLayerStatsResults->results,
1124 				linkLayerStatsResults->rspId);
1125 
1126 			spin_lock(&context->context_lock);
1127 			if (!linkLayerStatsResults->moreResultToFollow)
1128 				context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
1129 			spin_unlock(&context->context_lock);
1130 
1131 		} else {
1132 			hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
1133 		}
1134 
1135 		spin_lock(&context->context_lock);
1136 		/* complete response event if all requests are completed */
1137 		if (0 == context->request_bitmap)
1138 			complete(&context->response_event);
1139 		spin_unlock(&context->context_lock);
1140 
1141 		break;
1142 	}
1143 	default:
1144 		hdd_warn("invalid event type %d", indType);
1145 		break;
1146 	}
1147 }
1148 
1149 void hdd_lost_link_info_cb(void *context,
1150 				  struct sir_lost_link_info *lost_link_info)
1151 {
1152 	struct hdd_context *hdd_ctx = (struct hdd_context *)context;
1153 	int status;
1154 	struct hdd_adapter *adapter;
1155 
1156 	status = wlan_hdd_validate_context(hdd_ctx);
1157 	if (0 != status)
1158 		return;
1159 
1160 	if (NULL == lost_link_info) {
1161 		hdd_err("lost_link_info is NULL");
1162 		return;
1163 	}
1164 
1165 	adapter = hdd_get_adapter_by_vdev(hdd_ctx, lost_link_info->vdev_id);
1166 	if (NULL == adapter) {
1167 		hdd_err("invalid adapter");
1168 		return;
1169 	}
1170 
1171 	adapter->rssi_on_disconnect = lost_link_info->rssi;
1172 	hdd_debug("rssi on disconnect %d", adapter->rssi_on_disconnect);
1173 }
1174 
1175 const struct
1176 nla_policy
1177 	qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1178 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1179 						.type = NLA_U32},
1180 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1181 						.type = NLA_U32},
1182 };
1183 
1184 /**
1185  * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1186  * @wiphy: Pointer to wiphy
1187  * @wdev: Pointer to wdev
1188  * @data: Pointer to data
1189  * @data_len: Data length
1190  *
1191  * Return: int
1192  */
1193 static int
1194 __wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1195 				   struct wireless_dev *wdev,
1196 				   const void *data,
1197 				   int data_len)
1198 {
1199 	int status;
1200 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
1201 	tSirLLStatsSetReq LinkLayerStatsSetReq;
1202 	struct net_device *dev = wdev->netdev;
1203 	struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1204 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
1205 
1206 	ENTER_DEV(dev);
1207 
1208 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1209 		hdd_err("Command not allowed in FTM mode");
1210 		return -EPERM;
1211 	}
1212 
1213 	status = wlan_hdd_validate_context(hdd_ctx);
1214 	if (0 != status)
1215 		return -EINVAL;
1216 
1217 	if (hdd_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1218 			  (struct nlattr *)data, data_len,
1219 			  qca_wlan_vendor_ll_set_policy)) {
1220 		hdd_err("maximum attribute not present");
1221 		return -EINVAL;
1222 	}
1223 
1224 	if (!tb_vendor
1225 	    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
1226 		hdd_err("MPDU size Not present");
1227 		return -EINVAL;
1228 	}
1229 
1230 	if (!tb_vendor
1231 	    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
1232 		hdd_err("Stats Gathering Not Present");
1233 		return -EINVAL;
1234 	}
1235 
1236 	/* Shall take the request Id if the Upper layers pass. 1 For now. */
1237 	LinkLayerStatsSetReq.reqId = 1;
1238 
1239 	LinkLayerStatsSetReq.mpduSizeThreshold =
1240 		nla_get_u32(tb_vendor
1241 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1242 
1243 	LinkLayerStatsSetReq.aggressiveStatisticsGathering =
1244 		nla_get_u32(tb_vendor
1245 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1246 
1247 	LinkLayerStatsSetReq.staId = pAdapter->sessionId;
1248 
1249 	hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
1250 		LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId,
1251 		LinkLayerStatsSetReq.mpduSizeThreshold,
1252 		LinkLayerStatsSetReq.aggressiveStatisticsGathering);
1253 
1254 	if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(hdd_ctx->hHal,
1255 						       &LinkLayerStatsSetReq)) {
1256 		hdd_err("sme_ll_stats_set_req Failed");
1257 		return -EINVAL;
1258 	}
1259 
1260 	pAdapter->isLinkLayerStatsSet = 1;
1261 	EXIT();
1262 	return 0;
1263 }
1264 
1265 /**
1266  * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1267  * @wiphy: Pointer to wiphy
1268  * @wdev: Pointer to wdev
1269  * @data: Pointer to data
1270  * @data_len: Data length
1271  *
1272  * Return: 0 if success, non-zero for failure
1273  */
1274 int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1275 					struct wireless_dev *wdev,
1276 					const void *data,
1277 					int data_len)
1278 {
1279 	int ret = 0;
1280 
1281 	cds_ssr_protect(__func__);
1282 	ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
1283 	cds_ssr_unprotect(__func__);
1284 
1285 	return ret;
1286 }
1287 
1288 const struct
1289 nla_policy
1290 	qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1291 	/* Unsigned 32bit value provided by the caller issuing the GET stats
1292 	 * command. When reporting
1293 	 * the stats results, the driver uses the same value to indicate
1294 	 * which GET request the results
1295 	 * correspond to.
1296 	 */
1297 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1298 
1299 	/* Unsigned 32bit value . bit mask to identify what statistics are
1300 	 * requested for retrieval
1301 	 */
1302 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1303 };
1304 
1305 static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
1306 				      tSirLLStatsGetReq *req)
1307 {
1308 	unsigned long rc;
1309 	struct hdd_ll_stats_context *context;
1310 
1311 	context = &ll_stats_context;
1312 	spin_lock(&context->context_lock);
1313 	context->request_id = req->reqId;
1314 	context->request_bitmap = req->paramIdMask;
1315 	INIT_COMPLETION(context->response_event);
1316 	spin_unlock(&context->context_lock);
1317 
1318 	if (QDF_STATUS_SUCCESS !=
1319 			sme_ll_stats_get_req(hdd_ctx->hHal, req)) {
1320 		hdd_err("sme_ll_stats_get_req Failed");
1321 		return -EINVAL;
1322 	}
1323 
1324 	rc = wait_for_completion_timeout(&context->response_event,
1325 			msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
1326 	if (!rc) {
1327 		hdd_err("Target response timed out request id %d request bitmap 0x%x",
1328 			context->request_id, context->request_bitmap);
1329 		return -ETIMEDOUT;
1330 	}
1331 
1332 	return 0;
1333 }
1334 
1335 int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id,
1336 			  uint32_t req_mask)
1337 {
1338 	int ret;
1339 	tSirLLStatsGetReq get_req;
1340 	struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1341 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1342 
1343 	ENTER();
1344 
1345 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1346 		hdd_warn("Command not allowed in FTM mode");
1347 		return -EPERM;
1348 	}
1349 
1350 	ret = wlan_hdd_validate_context(hdd_ctx);
1351 	if (0 != ret)
1352 		return -EINVAL;
1353 
1354 	if (hddstactx->hdd_ReassocScenario) {
1355 		hdd_err("Roaming in progress, cannot process the request");
1356 		return -EBUSY;
1357 	}
1358 
1359 	if (!adapter->isLinkLayerStatsSet)
1360 		hdd_info("isLinkLayerStatsSet: %d; STATs will be all zero",
1361 			adapter->isLinkLayerStatsSet);
1362 
1363 	get_req.reqId = req_id;
1364 	get_req.paramIdMask = req_mask;
1365 	get_req.staId = adapter->sessionId;
1366 
1367 	rtnl_lock();
1368 	ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req);
1369 	rtnl_unlock();
1370 	if (0 != ret)
1371 		hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
1372 			req_id, req_mask, adapter->sessionId);
1373 
1374 	EXIT();
1375 	return ret;
1376 
1377 }
1378 
1379 /**
1380  * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1381  * @wiphy: Pointer to wiphy
1382  * @wdev: Pointer to wdev
1383  * @data: Pointer to data
1384  * @data_len: Data length
1385  *
1386  * Return: int
1387  */
1388 static int
1389 __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1390 				   struct wireless_dev *wdev,
1391 				   const void *data,
1392 				   int data_len)
1393 {
1394 	int ret;
1395 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
1396 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1397 	tSirLLStatsGetReq LinkLayerStatsGetReq;
1398 	struct net_device *dev = wdev->netdev;
1399 	struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1400 	struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
1401 
1402 	/* ENTER() intentionally not used in a frequently invoked API */
1403 
1404 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1405 		hdd_err("Command not allowed in FTM mode");
1406 		return -EPERM;
1407 	}
1408 
1409 	ret = wlan_hdd_validate_context(hdd_ctx);
1410 	if (0 != ret)
1411 		return -EINVAL;
1412 
1413 	if (!pAdapter->isLinkLayerStatsSet) {
1414 		hdd_warn("isLinkLayerStatsSet: %d",
1415 			 pAdapter->isLinkLayerStatsSet);
1416 		return -EINVAL;
1417 	}
1418 
1419 	if (hddstactx->hdd_ReassocScenario) {
1420 		hdd_err("Roaming in progress, cannot process the request");
1421 		return -EBUSY;
1422 	}
1423 
1424 	if (hdd_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1425 			  (struct nlattr *)data, data_len,
1426 			  qca_wlan_vendor_ll_get_policy)) {
1427 		hdd_err("max attribute not present");
1428 		return -EINVAL;
1429 	}
1430 
1431 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
1432 		hdd_err("Request Id Not present");
1433 		return -EINVAL;
1434 	}
1435 
1436 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
1437 		hdd_err("Req Mask Not present");
1438 		return -EINVAL;
1439 	}
1440 
1441 	LinkLayerStatsGetReq.reqId =
1442 		nla_get_u32(tb_vendor
1443 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1444 	LinkLayerStatsGetReq.paramIdMask =
1445 		nla_get_u32(tb_vendor
1446 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1447 
1448 	LinkLayerStatsGetReq.staId = pAdapter->sessionId;
1449 
1450 	if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1451 		hdd_err("invalid session id: %d", pAdapter->sessionId);
1452 		return -EINVAL;
1453 	}
1454 
1455 	ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &LinkLayerStatsGetReq);
1456 	if (0 != ret) {
1457 		hdd_err("Failed to send LL stats request (id:%u)",
1458 			LinkLayerStatsGetReq.reqId);
1459 		return ret;
1460 	}
1461 
1462 	EXIT();
1463 	return 0;
1464 }
1465 
1466 /**
1467  * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1468  * @wiphy: Pointer to wiphy
1469  * @wdev: Pointer to wdev
1470  * @data: Pointer to data
1471  * @data_len: Data length
1472  *
1473  * Return: 0 if success, non-zero for failure
1474  */
1475 int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1476 				struct wireless_dev *wdev,
1477 				const void *data,
1478 				int data_len)
1479 {
1480 	int ret = 0;
1481 
1482 	cds_ssr_protect(__func__);
1483 	ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1484 	cds_ssr_unprotect(__func__);
1485 
1486 	return ret;
1487 }
1488 
1489 const struct
1490 nla_policy
1491 	qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1492 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1493 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1494 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1495 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1496 };
1497 
1498 /**
1499  * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1500  * @wiphy: Pointer to wiphy
1501  * @wdev: Pointer to wdev
1502  * @data: Pointer to data
1503  * @data_len: Data length
1504  *
1505  * Return: int
1506  */
1507 static int
1508 __wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1509 				    struct wireless_dev *wdev,
1510 				    const void *data,
1511 				    int data_len)
1512 {
1513 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
1514 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1515 	tSirLLStatsClearReq LinkLayerStatsClearReq;
1516 	struct net_device *dev = wdev->netdev;
1517 	struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1518 	u32 statsClearReqMask;
1519 	u8 stopReq;
1520 	int status;
1521 	struct sk_buff *temp_skbuff;
1522 
1523 	ENTER_DEV(dev);
1524 
1525 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1526 		hdd_err("Command not allowed in FTM mode");
1527 		return -EPERM;
1528 	}
1529 
1530 	status = wlan_hdd_validate_context(hdd_ctx);
1531 	if (0 != status)
1532 		return -EINVAL;
1533 
1534 	if (!pAdapter->isLinkLayerStatsSet) {
1535 		hdd_warn("isLinkLayerStatsSet : %d",
1536 			  pAdapter->isLinkLayerStatsSet);
1537 		return -EINVAL;
1538 	}
1539 
1540 	if (hdd_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1541 			  (struct nlattr *)data, data_len,
1542 			  qca_wlan_vendor_ll_clr_policy)) {
1543 		hdd_err("STATS_CLR_MAX is not present");
1544 		return -EINVAL;
1545 	}
1546 
1547 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1548 	    !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
1549 		hdd_err("Error in LL_STATS CLR CONFIG PARA");
1550 		return -EINVAL;
1551 	}
1552 
1553 	statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1554 				    nla_get_u32(tb_vendor
1555 						[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1556 
1557 	stopReq = LinkLayerStatsClearReq.stopReq =
1558 			  nla_get_u8(tb_vendor
1559 				     [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1560 
1561 	/*
1562 	 * Shall take the request Id if the Upper layers pass. 1 For now.
1563 	 */
1564 	LinkLayerStatsClearReq.reqId = 1;
1565 
1566 	LinkLayerStatsClearReq.staId = pAdapter->sessionId;
1567 
1568 	hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
1569 		LinkLayerStatsClearReq.reqId,
1570 		LinkLayerStatsClearReq.staId,
1571 		LinkLayerStatsClearReq.statsClearReqMask,
1572 		LinkLayerStatsClearReq.stopReq);
1573 
1574 	if (QDF_STATUS_SUCCESS == sme_ll_stats_clear_req(hdd_ctx->hHal,
1575 					&LinkLayerStatsClearReq)) {
1576 		temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1577 								  2 *
1578 								  sizeof(u32) +
1579 								  2 *
1580 								  NLMSG_HDRLEN);
1581 		if (temp_skbuff != NULL) {
1582 			if (nla_put_u32(temp_skbuff,
1583 					QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1584 					statsClearReqMask) ||
1585 			    nla_put_u32(temp_skbuff,
1586 					QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1587 					stopReq)) {
1588 				hdd_err("LL_STATS_CLR put fail");
1589 				kfree_skb(temp_skbuff);
1590 				return -EINVAL;
1591 			}
1592 
1593 			/* If the ask is to stop the stats collection
1594 			 * as part of clear (stopReq = 1), ensure
1595 			 * that no further requests of get go to the
1596 			 * firmware by having isLinkLayerStatsSet set
1597 			 * to 0.  However it the stopReq as part of
1598 			 * the clear request is 0, the request to get
1599 			 * the statistics are honoured as in this case
1600 			 * the firmware is just asked to clear the
1601 			 * statistics.
1602 			 */
1603 			if (stopReq == 1)
1604 				pAdapter->isLinkLayerStatsSet = 0;
1605 
1606 			return cfg80211_vendor_cmd_reply(temp_skbuff);
1607 		}
1608 		EXIT();
1609 		return -ENOMEM;
1610 	}
1611 
1612 	return -EINVAL;
1613 }
1614 
1615 /**
1616  * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1617  * @wiphy: Pointer to wiphy
1618  * @wdev: Pointer to wdev
1619  * @data: Pointer to data
1620  * @data_len: Data length
1621  *
1622  * Return: 0 if success, non-zero for failure
1623  */
1624 int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1625 					struct wireless_dev *wdev,
1626 					const void *data,
1627 					int data_len)
1628 {
1629 	int ret = 0;
1630 
1631 	cds_ssr_protect(__func__);
1632 	ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
1633 	cds_ssr_unprotect(__func__);
1634 
1635 	return ret;
1636 }
1637 
1638 /**
1639  * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
1640  * @wifi_peer_info: peer information
1641  * @vendor_event: buffer for vendor event
1642  *
1643  * Return: 0 success
1644  */
1645 static inline int
1646 hdd_populate_per_peer_ps_info(tSirWifiPeerInfo *wifi_peer_info,
1647 			      struct sk_buff *vendor_event)
1648 {
1649 	if (!wifi_peer_info) {
1650 		hdd_err("Invalid pointer to peer info.");
1651 		return -EINVAL;
1652 	}
1653 
1654 	if (nla_put_u32(vendor_event,
1655 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
1656 			wifi_peer_info->power_saving) ||
1657 	    nla_put(vendor_event,
1658 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
1659 		    QDF_MAC_ADDR_SIZE, &wifi_peer_info->peerMacAddress)) {
1660 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
1661 		return -EINVAL;
1662 	}
1663 	return 0;
1664 }
1665 
1666 /**
1667  * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
1668  * @data: stats for peer STA
1669  * @vendor_event: buffer for vendor event
1670  *
1671  * Return: 0 success
1672  */
1673 static int hdd_populate_wifi_peer_ps_info(tSirWifiPeerStat *data,
1674 					  struct sk_buff *vendor_event)
1675 {
1676 	uint32_t peer_num, i;
1677 	tSirWifiPeerInfo *wifi_peer_info;
1678 	struct nlattr *peer_info, *peers;
1679 
1680 	if (!data) {
1681 		hdd_err("Invalid pointer to Wifi peer stat.");
1682 		return -EINVAL;
1683 	}
1684 
1685 	peer_num = data->numPeers;
1686 	if (peer_num == 0) {
1687 		hdd_err("Peer number is zero.");
1688 		return -EINVAL;
1689 	}
1690 
1691 	if (nla_put_u32(vendor_event,
1692 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
1693 			peer_num)) {
1694 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1695 		return -EINVAL;
1696 	}
1697 
1698 	peer_info = nla_nest_start(vendor_event,
1699 			       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
1700 	if (peer_info == NULL) {
1701 		hdd_err("nla_nest_start failed");
1702 		return -EINVAL;
1703 	}
1704 
1705 	for (i = 0; i < peer_num; i++) {
1706 		wifi_peer_info = &data->peerInfo[i];
1707 		peers = nla_nest_start(vendor_event, i);
1708 
1709 		if (peers == NULL) {
1710 			hdd_err("nla_nest_start failed");
1711 			return -EINVAL;
1712 		}
1713 
1714 		if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
1715 			return -EINVAL;
1716 
1717 		nla_nest_end(vendor_event, peers);
1718 	}
1719 	nla_nest_end(vendor_event, peer_info);
1720 
1721 	return 0;
1722 }
1723 
1724 /**
1725  * hdd_populate_tx_failure_info() - populate TX failure info
1726  * @tx_fail: TX failure info
1727  * @skb: buffer for vendor event
1728  *
1729  * Return: 0 Success
1730  */
1731 static inline int
1732 hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
1733 			     struct sk_buff *skb)
1734 {
1735 	int status = 0;
1736 
1737 	if (tx_fail == NULL || skb == NULL)
1738 		return -EINVAL;
1739 
1740 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
1741 			tx_fail->tid) ||
1742 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
1743 			tx_fail->msdu_num) ||
1744 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
1745 			tx_fail->status)) {
1746 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1747 		status = -EINVAL;
1748 	}
1749 
1750 	return status;
1751 }
1752 
1753 /**
1754  * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event
1755  * @info: cca info array for all channels
1756  * @vendor_event: vendor event buffer
1757  *
1758  * Return: 0 Success, EINVAL failure
1759  */
1760 static int
1761 hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca,
1762 				   struct sk_buff *vendor_event)
1763 {
1764 	/* There might be no CCA info for a channel */
1765 	if (!cca)
1766 		return 0;
1767 
1768 	if (nla_put_u32(vendor_event,
1769 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
1770 			cca->idle_time) ||
1771 	    nla_put_u32(vendor_event,
1772 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
1773 			cca->tx_time) ||
1774 	    nla_put_u32(vendor_event,
1775 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
1776 			cca->rx_in_bss_time) ||
1777 	    nla_put_u32(vendor_event,
1778 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
1779 			cca->rx_out_bss_time) ||
1780 	    nla_put_u32(vendor_event,
1781 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
1782 			cca->rx_busy_time) ||
1783 	    nla_put_u32(vendor_event,
1784 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
1785 			cca->rx_in_bad_cond_time) ||
1786 	    nla_put_u32(vendor_event,
1787 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
1788 			cca->tx_in_bad_cond_time) ||
1789 	    nla_put_u32(vendor_event,
1790 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
1791 			cca->wlan_not_avail_time) ||
1792 	    nla_put_u32(vendor_event,
1793 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
1794 			cca->vdev_id)) {
1795 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1796 		return -EINVAL;
1797 	}
1798 	return 0;
1799 }
1800 
1801 /**
1802  * hdd_populate_wifi_signal_info - put chain signal info
1803  * @info: RF chain signal info
1804  * @skb: vendor event buffer
1805  *
1806  * Return: 0 Success, EINVAL failure
1807  */
1808 static int
1809 hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal,
1810 			      struct sk_buff *skb)
1811 {
1812 	uint32_t i, chain_count;
1813 	struct nlattr *chains, *att;
1814 
1815 	/* There might be no signal info for a peer */
1816 	if (!peer_signal)
1817 		return 0;
1818 
1819 	chain_count = peer_signal->num_chain < WIFI_MAX_CHAINS ?
1820 		      peer_signal->num_chain : WIFI_MAX_CHAINS;
1821 	if (nla_put_u32(skb,
1822 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
1823 			chain_count)) {
1824 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1825 		return -EINVAL;
1826 	}
1827 
1828 	att = nla_nest_start(skb,
1829 			     QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL);
1830 	if (!att) {
1831 		hdd_err("nla_nest_start failed");
1832 		return -EINVAL;
1833 	}
1834 
1835 	for (i = 0; i < chain_count; i++) {
1836 		chains = nla_nest_start(skb, i);
1837 
1838 		if (!chains) {
1839 			hdd_err("nla_nest_start failed");
1840 			return -EINVAL;
1841 		}
1842 
1843 		hdd_debug("SNR=%d, NF=%d, Rx=%d, Tx=%d",
1844 			  peer_signal->per_ant_snr[i],
1845 			  peer_signal->nf[i],
1846 			  peer_signal->per_ant_rx_mpdus[i],
1847 			  peer_signal->per_ant_tx_mpdus[i]);
1848 		if (nla_put_u32(skb,
1849 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
1850 				peer_signal->per_ant_snr[i]) ||
1851 		    nla_put_u32(skb,
1852 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
1853 				peer_signal->nf[i]) ||
1854 		    nla_put_u32(skb,
1855 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
1856 				peer_signal->per_ant_rx_mpdus[i]) ||
1857 		    nla_put_u32(skb,
1858 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1859 				peer_signal->per_ant_tx_mpdus[i])) {
1860 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1861 			return -EINVAL;
1862 		}
1863 		nla_nest_end(skb, chains);
1864 	}
1865 	nla_nest_end(skb, att);
1866 
1867 	return 0;
1868 }
1869 
1870 /**
1871  * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info
1872  * @info: tx info
1873  * @skb: vendor event buffer
1874  *
1875  * Return: 0 Success, EINVAL failure
1876  */
1877 static int
1878 hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats,
1879 				 struct sk_buff *skb)
1880 {
1881 	uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay;
1882 
1883 	/* There might be no TX info for a peer */
1884 	if (!tx_stats)
1885 		return 0;
1886 
1887 	agg_size = tx_stats->mpdu_aggr_size;
1888 	succ_mcs = tx_stats->success_mcs;
1889 	fail_mcs = tx_stats->fail_mcs;
1890 	delay = tx_stats->delay;
1891 
1892 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
1893 			tx_stats->msdus) ||
1894 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1895 			tx_stats->mpdus) ||
1896 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
1897 			tx_stats->ppdus) ||
1898 	    nla_put_u32(skb,
1899 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
1900 			tx_stats->bytes) ||
1901 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
1902 			tx_stats->drops) ||
1903 	    nla_put_u32(skb,
1904 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
1905 			tx_stats->drop_bytes) ||
1906 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
1907 			tx_stats->retries) ||
1908 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
1909 			tx_stats->failed) ||
1910 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
1911 			tx_stats->aggr_len) ||
1912 	    nla_put_u32(skb,
1913 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
1914 			tx_stats->success_mcs_len) ||
1915 	    nla_put_u32(skb,
1916 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
1917 			tx_stats->fail_mcs_len) ||
1918 	    nla_put_u32(skb,
1919 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
1920 			tx_stats->delay_len))
1921 		goto put_attr_fail;
1922 
1923 	if (agg_size) {
1924 		if (nla_put(skb,
1925 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
1926 			    tx_stats->aggr_len, agg_size))
1927 			goto put_attr_fail;
1928 	}
1929 
1930 	if (succ_mcs) {
1931 		if (nla_put(skb,
1932 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
1933 			    tx_stats->success_mcs_len, succ_mcs))
1934 			goto put_attr_fail;
1935 	}
1936 
1937 	if (fail_mcs) {
1938 		if (nla_put(skb,
1939 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
1940 			    tx_stats->fail_mcs_len, fail_mcs))
1941 			goto put_attr_fail;
1942 	}
1943 
1944 	if (delay) {
1945 		if (nla_put(skb,
1946 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
1947 			    tx_stats->delay_len, delay))
1948 			goto put_attr_fail;
1949 	}
1950 	return 0;
1951 
1952 put_attr_fail:
1953 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1954 	return -EINVAL;
1955 }
1956 
1957 /**
1958  * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info
1959  * @info: rx info
1960  * @skb: vendor event buffer
1961  *
1962  * Return: 0 Success, EINVAL failure
1963  */
1964 static int
1965 hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats,
1966 				 struct sk_buff *skb)
1967 {
1968 	uint32_t *mcs, *aggr;
1969 
1970 	/* There might be no RX info for a peer */
1971 	if (!rx_stats)
1972 		return 0;
1973 
1974 	aggr = rx_stats->mpdu_aggr;
1975 	mcs = rx_stats->mcs;
1976 
1977 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
1978 			rx_stats->mpdus) ||
1979 	    nla_put_u32(skb,
1980 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
1981 			rx_stats->bytes) ||
1982 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
1983 			rx_stats->ppdus) ||
1984 	    nla_put_u32(skb,
1985 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
1986 			rx_stats->ppdu_bytes) ||
1987 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
1988 			rx_stats->mpdu_lost) ||
1989 	    nla_put_u32(skb,
1990 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
1991 			rx_stats->mpdu_retry) ||
1992 	    nla_put_u32(skb,
1993 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
1994 			rx_stats->mpdu_dup) ||
1995 	    nla_put_u32(skb,
1996 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
1997 			rx_stats->mpdu_discard) ||
1998 	    nla_put_u32(skb,
1999 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
2000 			rx_stats->aggr_len) ||
2001 	    nla_put_u32(skb,
2002 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
2003 			rx_stats->mcs_len))
2004 		goto put_attr_fail;
2005 
2006 	if (aggr) {
2007 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
2008 			    rx_stats->aggr_len, aggr))
2009 			goto put_attr_fail;
2010 	}
2011 
2012 	if (mcs) {
2013 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
2014 			    rx_stats->mcs_len, mcs))
2015 			goto put_attr_fail;
2016 	}
2017 
2018 	return 0;
2019 
2020 put_attr_fail:
2021 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2022 	return -EINVAL;
2023 }
2024 
2025 /**
2026  * hdd_populate_wifi_wmm_ac_info() - put WMM AC info
2027  * @info: per AC stats
2028  * @skb: vendor event buffer
2029  *
2030  * Return: 0 Success, EINVAL failure
2031  */
2032 static int
2033 hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats,
2034 			      struct sk_buff *skb)
2035 {
2036 	struct nlattr *wmm;
2037 
2038 	wmm = nla_nest_start(skb, ac_stats->type);
2039 	if (!wmm)
2040 		goto nest_start_fail;
2041 
2042 	if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) ||
2043 	    hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb))
2044 		goto put_attr_fail;
2045 
2046 	nla_nest_end(skb, wmm);
2047 	return 0;
2048 
2049 nest_start_fail:
2050 	hdd_err("nla_nest_start failed");
2051 	return -EINVAL;
2052 
2053 put_attr_fail:
2054 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2055 	return -EINVAL;
2056 }
2057 
2058 /**
2059  * hdd_populate_wifi_ll_ext_peer_info() - put per peer info
2060  * @info: peer stats
2061  * @skb: vendor event buffer
2062  *
2063  * Return: 0 Success, EINVAL failure
2064  */
2065 static int
2066 hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers,
2067 				   struct sk_buff *skb)
2068 {
2069 	uint32_t i;
2070 	struct nlattr *wmm_ac;
2071 
2072 	if (nla_put_u32(skb,
2073 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
2074 			peers->peer_id) ||
2075 	    nla_put_u32(skb,
2076 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
2077 			peers->vdev_id) ||
2078 	    nla_put_u32(skb,
2079 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
2080 			peers->sta_ps_inds) ||
2081 	    nla_put_u32(skb,
2082 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
2083 			peers->sta_ps_durs) ||
2084 	    nla_put_u32(skb,
2085 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
2086 			peers->rx_probe_reqs) ||
2087 	    nla_put_u32(skb,
2088 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
2089 			peers->rx_oth_mgmts) ||
2090 	    nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
2091 		    QDF_MAC_ADDR_SIZE, peers->mac_address) ||
2092 	    hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) {
2093 		hdd_err("put peer signal attr failed");
2094 		return -EINVAL;
2095 	}
2096 
2097 	wmm_ac = nla_nest_start(skb,
2098 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS);
2099 	if (!wmm_ac) {
2100 		hdd_err("nla_nest_start failed");
2101 		return -EINVAL;
2102 	}
2103 
2104 	for (i = 0; i < WLAN_MAX_AC; i++) {
2105 		if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) {
2106 			hdd_err("put WMM AC attr failed");
2107 			return -EINVAL;
2108 		}
2109 	}
2110 
2111 	nla_nest_end(skb, wmm_ac);
2112 	return 0;
2113 }
2114 
2115 /**
2116  * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats
2117  * @info: link layer stats
2118  * @skb: vendor event buffer
2119  *
2120  * Return: 0 Success, EINVAL failure
2121  */
2122 static int
2123 hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats,
2124 			       struct sk_buff *skb)
2125 {
2126 	uint32_t i;
2127 	struct nlattr *peer, *peer_info, *channels, *channel_info;
2128 
2129 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
2130 			stats->trigger_cond_id) ||
2131 	    nla_put_u32(skb,
2132 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
2133 			stats->cca_chgd_bitmap) ||
2134 	    nla_put_u32(skb,
2135 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
2136 			stats->sig_chgd_bitmap) ||
2137 	    nla_put_u32(skb,
2138 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
2139 			stats->tx_chgd_bitmap) ||
2140 	    nla_put_u32(skb,
2141 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
2142 			stats->rx_chgd_bitmap) ||
2143 	    nla_put_u32(skb,
2144 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
2145 			stats->channel_num) ||
2146 	    nla_put_u32(skb,
2147 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
2148 			stats->peer_num)) {
2149 		goto put_attr_fail;
2150 	}
2151 
2152 	channels = nla_nest_start(skb,
2153 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS);
2154 	if (!channels) {
2155 		hdd_err("nla_nest_start failed");
2156 		return -EINVAL;
2157 	}
2158 
2159 	for (i = 0; i < stats->channel_num; i++) {
2160 		channel_info = nla_nest_start(skb, i);
2161 		if (!channel_info) {
2162 			hdd_err("nla_nest_start failed");
2163 			return -EINVAL;
2164 		}
2165 
2166 		if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb))
2167 			goto put_attr_fail;
2168 		nla_nest_end(skb, channel_info);
2169 	}
2170 	nla_nest_end(skb, channels);
2171 
2172 	peer_info = nla_nest_start(skb,
2173 				   QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER);
2174 	if (!peer_info) {
2175 		hdd_err("nla_nest_start failed");
2176 		return -EINVAL;
2177 	}
2178 
2179 	for (i = 0; i < stats->peer_num; i++) {
2180 		peer = nla_nest_start(skb, i);
2181 		if (!peer) {
2182 			hdd_err("nla_nest_start failed");
2183 			return -EINVAL;
2184 		}
2185 
2186 		if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i],
2187 						       skb))
2188 			goto put_attr_fail;
2189 		nla_nest_end(skb, peer);
2190 	}
2191 
2192 	nla_nest_end(skb, peer_info);
2193 	return 0;
2194 
2195 put_attr_fail:
2196 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2197 	return -EINVAL;
2198 }
2199 
2200 /**
2201  * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
2202  * @ctx: HDD context
2203  * @rsp: msg from FW
2204  *
2205  * This function is an extension of
2206  * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
2207  * monitoring parameters offloaded to NL data and send the same to the
2208  * kernel/upper layers.
2209  *
2210  * Return: None
2211  */
2212 void wlan_hdd_cfg80211_link_layer_stats_ext_callback(tHddHandle ctx,
2213 						     tSirLLStatsResults *rsp)
2214 {
2215 	struct hdd_context *hdd_ctx;
2216 	struct sk_buff *skb = NULL;
2217 	uint32_t param_id, index;
2218 	struct hdd_adapter *adapter = NULL;
2219 	tSirLLStatsResults *linkLayer_stats_results;
2220 	tSirWifiPeerStat *peer_stats;
2221 	uint8_t *results;
2222 	int status;
2223 
2224 	ENTER();
2225 
2226 	if (!ctx) {
2227 		hdd_err("Invalid HDD context.");
2228 		return;
2229 	}
2230 
2231 	if (!rsp) {
2232 		hdd_err("Invalid result.");
2233 		return;
2234 	}
2235 
2236 	hdd_ctx = (struct hdd_context *)ctx;
2237 	linkLayer_stats_results = rsp;
2238 
2239 	status = wlan_hdd_validate_context(hdd_ctx);
2240 	if (0 != status)
2241 		return;
2242 
2243 	adapter = hdd_get_adapter_by_vdev(hdd_ctx,
2244 					  linkLayer_stats_results->ifaceId);
2245 
2246 	if (!adapter) {
2247 		hdd_err("vdev_id %d does not exist with host.",
2248 			linkLayer_stats_results->ifaceId);
2249 		return;
2250 	}
2251 
2252 	index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
2253 	skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2254 			NULL, LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
2255 			index, GFP_KERNEL);
2256 	if (!skb) {
2257 		hdd_err("cfg80211_vendor_event_alloc failed.");
2258 		return;
2259 	}
2260 
2261 	results = linkLayer_stats_results->results;
2262 	param_id = linkLayer_stats_results->paramId;
2263 	hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %p",
2264 		 linkLayer_stats_results->paramId,
2265 		 linkLayer_stats_results->ifaceId,
2266 		 linkLayer_stats_results->results);
2267 	if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
2268 		peer_stats = (tSirWifiPeerStat *)results;
2269 		status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
2270 	} else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
2271 		struct sir_wifi_iface_tx_fail *tx_fail;
2272 
2273 		tx_fail = (struct sir_wifi_iface_tx_fail *)results;
2274 		status = hdd_populate_tx_failure_info(tx_fail, skb);
2275 	} else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
2276 		hdd_info("MAC counters stats");
2277 		status = hdd_populate_wifi_ll_ext_stats(
2278 				(struct sir_wifi_ll_ext_stats *)
2279 				rsp->results, skb);
2280 	} else {
2281 		hdd_info("Unknown link layer stats");
2282 		status = -EINVAL;
2283 	}
2284 
2285 	if (status == 0)
2286 		cfg80211_vendor_event(skb, GFP_KERNEL);
2287 	else
2288 		kfree_skb(skb);
2289 	EXIT();
2290 }
2291 
2292 static const struct nla_policy
2293 qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = {
2294 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = {
2295 		.type = NLA_U32
2296 	},
2297 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = {
2298 		.type = NLA_U32
2299 	},
2300 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = {
2301 		.type = NLA_U32
2302 	},
2303 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = {
2304 		.type = NLA_U32
2305 	},
2306 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = {
2307 		.type = NLA_U32
2308 	},
2309 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = {
2310 		.type = NLA_U32
2311 	},
2312 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = {
2313 		.type = NLA_U32
2314 	},
2315 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = {
2316 		.type = NLA_U32
2317 	},
2318 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = {
2319 		.type = NLA_U32
2320 	},
2321 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = {
2322 		.type = NLA_U32
2323 	},
2324 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = {
2325 		.type = NLA_U32
2326 	},
2327 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = {
2328 		.type = NLA_U32
2329 	},
2330 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = {
2331 		.type = NLA_U32
2332 	},
2333 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = {
2334 		.type = NLA_U32
2335 	},
2336 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = {
2337 		.type = NLA_U32
2338 	},
2339 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = {
2340 		.type = NLA_U32
2341 	},
2342 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = {
2343 		.type = NLA_U32
2344 	},
2345 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = {
2346 		.type = NLA_U32
2347 	},
2348 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = {
2349 		.type = NLA_U32
2350 	},
2351 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = {
2352 		.type = NLA_U32
2353 	},
2354 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = {
2355 		.type = NLA_U32
2356 	},
2357 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = {
2358 		.type = NLA_U32
2359 	},
2360 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = {
2361 		.type = NLA_U32
2362 	},
2363 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = {
2364 		.type = NLA_U32
2365 	},
2366 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = {
2367 		.type = NLA_U32
2368 	},
2369 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = {
2370 		.type = NLA_U32
2371 	},
2372 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = {
2373 		.type = NLA_U32
2374 	},
2375 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = {
2376 		.type = NLA_U32
2377 	},
2378 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = {
2379 		.type = NLA_U32
2380 	},
2381 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = {
2382 		.type = NLA_U32
2383 	},
2384 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = {
2385 		.type = NLA_U32
2386 	},
2387 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = {
2388 		.type = NLA_U32
2389 	},
2390 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = {
2391 		.type = NLA_U32
2392 	},
2393 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = {
2394 		.type = NLA_U32
2395 	},
2396 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = {
2397 		.type = NLA_U32
2398 	},
2399 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = {
2400 		.type = NLA_U32
2401 	},
2402 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = {
2403 		.type = NLA_U32
2404 	},
2405 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = {
2406 		.type = NLA_U32
2407 	},
2408 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = {
2409 		.type = NLA_U32
2410 	},
2411 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = {
2412 		.type = NLA_U32
2413 	},
2414 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = {
2415 		.type = NLA_U32
2416 	},
2417 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = {
2418 		.type = NLA_U32
2419 	},
2420 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = {
2421 		.type = NLA_U32
2422 	},
2423 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = {
2424 		.type = NLA_U32
2425 	},
2426 };
2427 
2428 /**
2429  * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2430  * @wiphy: wiphy handle
2431  * @wdev: wdev handle
2432  * @data: user layer input
2433  * @data_len: length of user layer input
2434  *
2435  * this function is called in ssr protected environment.
2436  *
2437  * return: 0 success, none zero for failure
2438  */
2439 static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2440 						      struct wireless_dev *wdev,
2441 						      const void *data,
2442 						      int data_len)
2443 {
2444 	int status;
2445 	uint32_t period;
2446 	struct net_device *dev = wdev->netdev;
2447 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2448 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2449 	struct sir_ll_ext_stats_threshold thresh = {0,};
2450 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1];
2451 
2452 	ENTER_DEV(dev);
2453 
2454 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2455 		hdd_warn("command not allowed in ftm mode");
2456 		return -EPERM;
2457 	}
2458 
2459 	status = wlan_hdd_validate_context(hdd_ctx);
2460 	if (0 != status)
2461 		return -EPERM;
2462 
2463 	if (hdd_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX,
2464 			  (struct nlattr *)data, data_len,
2465 			  qca_wlan_vendor_ll_ext_policy)) {
2466 		hdd_err("maximum attribute not present");
2467 		return -EPERM;
2468 	}
2469 
2470 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) {
2471 		period = nla_get_u32(tb[
2472 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]);
2473 
2474 		if (period != 0 && period < LL_STATS_MIN_PERIOD)
2475 			period = LL_STATS_MIN_PERIOD;
2476 
2477 		/*
2478 		 * Only enable/disbale counters.
2479 		 * Keep the last threshold settings.
2480 		 */
2481 		goto set_period;
2482 	}
2483 
2484 	/* global thresh is not enabled */
2485 	if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) {
2486 		thresh.global = false;
2487 		hdd_warn("global thresh is not set");
2488 	} else {
2489 		thresh.global_threshold = nla_get_u32(tb[
2490 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]);
2491 		thresh.global = true;
2492 		hdd_debug("globle thresh is %d", thresh.global_threshold);
2493 	}
2494 
2495 	if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) {
2496 		thresh.global = false;
2497 		hdd_warn("global thresh is not enabled");
2498 	} else {
2499 		thresh.global = nla_get_u32(tb[
2500 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]);
2501 		hdd_debug("global is %d", thresh.global);
2502 	}
2503 
2504 	thresh.enable_bitmap = false;
2505 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) {
2506 		thresh.tx_bitmap = nla_get_u32(tb[
2507 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]);
2508 		thresh.enable_bitmap = true;
2509 	}
2510 
2511 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) {
2512 		thresh.rx_bitmap = nla_get_u32(tb[
2513 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]);
2514 		thresh.enable_bitmap = true;
2515 	}
2516 
2517 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) {
2518 		thresh.cca_bitmap = nla_get_u32(tb[
2519 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]);
2520 		thresh.enable_bitmap = true;
2521 	}
2522 
2523 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) {
2524 		thresh.signal_bitmap = nla_get_u32(tb[
2525 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]);
2526 		thresh.enable_bitmap = true;
2527 	}
2528 
2529 	if (!thresh.global && !thresh.enable_bitmap) {
2530 		hdd_warn("threshold will be disabled.");
2531 		thresh.enable = false;
2532 
2533 		/* Just disable threshold */
2534 		goto set_thresh;
2535 	} else {
2536 		thresh.enable = true;
2537 	}
2538 
2539 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) {
2540 		thresh.tx.msdu = nla_get_u32(tb[
2541 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]);
2542 	}
2543 
2544 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) {
2545 		thresh.tx.mpdu = nla_get_u32(tb[
2546 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]);
2547 	}
2548 
2549 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) {
2550 		thresh.tx.ppdu = nla_get_u32(tb[
2551 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]);
2552 	}
2553 
2554 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) {
2555 		thresh.tx.bytes = nla_get_u32(tb[
2556 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]);
2557 	}
2558 
2559 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) {
2560 		thresh.tx.msdu_drop = nla_get_u32(
2561 			tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]);
2562 	}
2563 
2564 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) {
2565 		thresh.tx.byte_drop = nla_get_u32(tb[
2566 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]);
2567 	}
2568 
2569 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) {
2570 		thresh.tx.mpdu_retry = nla_get_u32(tb[
2571 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]);
2572 	}
2573 
2574 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) {
2575 		thresh.tx.mpdu_fail = nla_get_u32(tb[
2576 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]);
2577 	}
2578 
2579 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) {
2580 		thresh.tx.ppdu_fail = nla_get_u32(tb[
2581 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]);
2582 	}
2583 
2584 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) {
2585 		thresh.tx.aggregation = nla_get_u32(tb[
2586 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]);
2587 	}
2588 
2589 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) {
2590 		thresh.tx.succ_mcs = nla_get_u32(tb[
2591 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]);
2592 	}
2593 
2594 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) {
2595 		thresh.tx.fail_mcs = nla_get_u32(tb[
2596 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]);
2597 	}
2598 
2599 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) {
2600 		thresh.tx.delay = nla_get_u32(tb[
2601 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]);
2602 	}
2603 
2604 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) {
2605 		thresh.rx.mpdu = nla_get_u32(tb[
2606 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]);
2607 	}
2608 
2609 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) {
2610 		thresh.rx.bytes = nla_get_u32(tb[
2611 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]);
2612 	}
2613 
2614 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) {
2615 		thresh.rx.ppdu = nla_get_u32(tb[
2616 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]);
2617 	}
2618 
2619 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) {
2620 		thresh.rx.ppdu_bytes = nla_get_u32(tb[
2621 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]);
2622 	}
2623 
2624 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) {
2625 		thresh.rx.mpdu_lost = nla_get_u32(tb[
2626 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]);
2627 	}
2628 
2629 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) {
2630 		thresh.rx.mpdu_retry = nla_get_u32(tb[
2631 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]);
2632 	}
2633 
2634 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) {
2635 		thresh.rx.mpdu_dup = nla_get_u32(tb[
2636 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]);
2637 	}
2638 
2639 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) {
2640 		thresh.rx.mpdu_discard = nla_get_u32(tb[
2641 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]);
2642 	}
2643 
2644 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) {
2645 		thresh.rx.aggregation = nla_get_u32(tb[
2646 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]);
2647 	}
2648 
2649 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) {
2650 		thresh.rx.mcs = nla_get_u32(tb[
2651 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]);
2652 	}
2653 
2654 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) {
2655 		thresh.rx.ps_inds = nla_get_u32(tb[
2656 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]);
2657 	}
2658 
2659 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) {
2660 		thresh.rx.ps_durs = nla_get_u32(tb[
2661 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]);
2662 	}
2663 
2664 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) {
2665 		thresh.rx.probe_reqs = nla_get_u32(tb[
2666 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]);
2667 	}
2668 
2669 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) {
2670 		thresh.rx.other_mgmt = nla_get_u32(tb[
2671 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]);
2672 	}
2673 
2674 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) {
2675 		thresh.cca.idle_time = nla_get_u32(tb[
2676 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]);
2677 	}
2678 
2679 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) {
2680 		thresh.cca.tx_time = nla_get_u32(tb[
2681 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]);
2682 	}
2683 
2684 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) {
2685 		thresh.cca.rx_in_bss_time = nla_get_u32(tb[
2686 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]);
2687 	}
2688 
2689 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) {
2690 		thresh.cca.rx_out_bss_time = nla_get_u32(tb[
2691 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]);
2692 	}
2693 
2694 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) {
2695 		thresh.cca.rx_busy_time = nla_get_u32(tb[
2696 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]);
2697 	}
2698 
2699 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) {
2700 		thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[
2701 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]);
2702 	}
2703 
2704 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) {
2705 		thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[
2706 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]);
2707 	}
2708 
2709 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) {
2710 		thresh.cca.wlan_not_avail_time = nla_get_u32(tb[
2711 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]);
2712 	}
2713 
2714 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) {
2715 		thresh.signal.snr = nla_get_u32(tb[
2716 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]);
2717 	}
2718 
2719 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) {
2720 		thresh.signal.nf = nla_get_u32(tb[
2721 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]);
2722 	}
2723 
2724 set_thresh:
2725 	hdd_info("send thresh settings to target");
2726 	if (QDF_STATUS_SUCCESS != sme_ll_stats_set_thresh(hdd_ctx->hHal,
2727 							  &thresh)) {
2728 		hdd_err("sme_ll_stats_set_thresh failed.");
2729 		return -EINVAL;
2730 	}
2731 	return 0;
2732 
2733 set_period:
2734 	hdd_info("send period to target");
2735 	status = wma_cli_set_command(adapter->sessionId,
2736 				     WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD,
2737 				     period, PDEV_CMD);
2738 	if (status) {
2739 		hdd_err("wma_cli_set_command set_period failed.");
2740 		return -EINVAL;
2741 	}
2742 	return 0;
2743 }
2744 
2745 /**
2746  * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2747  * @wiphy: wiphy handle
2748  * @wdev: wdev handle
2749  * @data: user layer input
2750  * @data_len: length of user layer input
2751  *
2752  * return: 0 success, einval failure
2753  */
2754 int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2755 					     struct wireless_dev *wdev,
2756 					     const void *data,
2757 					     int data_len)
2758 {
2759 	int ret;
2760 
2761 	cds_ssr_protect(__func__);
2762 	ret = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev,
2763 							 data, data_len);
2764 	cds_ssr_unprotect(__func__);
2765 
2766 	return ret;
2767 }
2768 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
2769 
2770 #ifdef WLAN_FEATURE_STATS_EXT
2771 /**
2772  * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2773  * @wiphy: Pointer to wiphy
2774  * @wdev: Pointer to wdev
2775  * @data: Pointer to data
2776  * @data_len: Data length
2777  *
2778  * Return: int
2779  */
2780 static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2781 						 struct wireless_dev *wdev,
2782 						 const void *data,
2783 						 int data_len)
2784 {
2785 	tStatsExtRequestReq stats_ext_req;
2786 	struct net_device *dev = wdev->netdev;
2787 	struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2788 	int ret_val;
2789 	QDF_STATUS status;
2790 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2791 
2792 	ENTER_DEV(dev);
2793 
2794 	ret_val = wlan_hdd_validate_context(hdd_ctx);
2795 	if (ret_val)
2796 		return ret_val;
2797 
2798 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2799 		hdd_err("Command not allowed in FTM mode");
2800 		return -EPERM;
2801 	}
2802 
2803 	stats_ext_req.request_data_len = data_len;
2804 	stats_ext_req.request_data = (void *)data;
2805 
2806 	status = sme_stats_ext_request(pAdapter->sessionId, &stats_ext_req);
2807 
2808 	if (QDF_STATUS_SUCCESS != status)
2809 		ret_val = -EINVAL;
2810 
2811 	return ret_val;
2812 }
2813 
2814 /**
2815  * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2816  * @wiphy: Pointer to wiphy
2817  * @wdev: Pointer to wdev
2818  * @data: Pointer to data
2819  * @data_len: Data length
2820  *
2821  * Return: int
2822  */
2823 int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2824 					struct wireless_dev *wdev,
2825 					const void *data,
2826 					int data_len)
2827 {
2828 	int ret;
2829 
2830 	cds_ssr_protect(__func__);
2831 	ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
2832 						    data, data_len);
2833 	cds_ssr_unprotect(__func__);
2834 
2835 	return ret;
2836 }
2837 
2838 /**
2839  * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback
2840  * @ctx: Pointer to HDD context
2841  * @msg: Message received
2842  *
2843  * Return: nothing
2844  */
2845 void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
2846 						 tStatsExtEvent *msg)
2847 {
2848 
2849 	struct hdd_context *hdd_ctx = (struct hdd_context *) ctx;
2850 	struct sk_buff *vendor_event;
2851 	int status;
2852 	int ret_val;
2853 	tStatsExtEvent *data = msg;
2854 	struct hdd_adapter *pAdapter = NULL;
2855 
2856 	status = wlan_hdd_validate_context(hdd_ctx);
2857 	if (status)
2858 		return;
2859 
2860 	pAdapter = hdd_get_adapter_by_vdev(hdd_ctx, data->vdev_id);
2861 
2862 	if (NULL == pAdapter) {
2863 		hdd_err("vdev_id %d does not exist with host", data->vdev_id);
2864 		return;
2865 	}
2866 
2867 	vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2868 						   NULL,
2869 						   data->event_data_len +
2870 						   sizeof(uint32_t) +
2871 						   NLMSG_HDRLEN + NLMSG_HDRLEN,
2872 						   QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2873 						   GFP_KERNEL);
2874 
2875 	if (!vendor_event) {
2876 		hdd_err("cfg80211_vendor_event_alloc failed");
2877 		return;
2878 	}
2879 
2880 	ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
2881 			      pAdapter->dev->ifindex);
2882 	if (ret_val) {
2883 		hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
2884 		kfree_skb(vendor_event);
2885 
2886 		return;
2887 	}
2888 
2889 	ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
2890 			  data->event_data_len, data->event_data);
2891 
2892 	if (ret_val) {
2893 		hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
2894 		kfree_skb(vendor_event);
2895 
2896 		return;
2897 	}
2898 
2899 	cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2900 
2901 }
2902 
2903 void wlan_hdd_cfg80211_stats_ext2_callback(void *ctx,
2904 				struct sir_sme_rx_aggr_hole_ind *pmsg)
2905 {
2906 	struct hdd_context *hdd_ctx = (struct hdd_context *)ctx;
2907 	int status;
2908 	uint32_t data_size, hole_info_size;
2909 	struct sk_buff *vendor_event;
2910 
2911 	status = wlan_hdd_validate_context(hdd_ctx);
2912 	if (0 != status)
2913 		return;
2914 
2915 	if (NULL == pmsg) {
2916 		hdd_err("msg received here is null");
2917 		return;
2918 	}
2919 
2920 	hole_info_size = (pmsg->hole_cnt)*sizeof(pmsg->hole_info_array[0]);
2921 	data_size = sizeof(struct sir_sme_rx_aggr_hole_ind) + hole_info_size;
2922 
2923 	vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2924 			NULL,
2925 			data_size + NLMSG_HDRLEN + NLMSG_HDRLEN,
2926 			QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2927 			GFP_KERNEL);
2928 
2929 	if (!vendor_event) {
2930 		hdd_err("vendor_event_alloc failed for STATS_EXT2");
2931 		return;
2932 	}
2933 
2934 	if (nla_put_u32(vendor_event,
2935 			QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM,
2936 			pmsg->hole_cnt)) {
2937 		hdd_err("%s put fail",
2938 			"QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM");
2939 		kfree_skb(vendor_event);
2940 		return;
2941 	}
2942 	if (nla_put(vendor_event,
2943 		    QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO,
2944 		    hole_info_size,
2945 		    (void *)(pmsg->hole_info_array))) {
2946 		hdd_err("%s put fail",
2947 			"QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO");
2948 		kfree_skb(vendor_event);
2949 		return;
2950 	}
2951 
2952 	cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2953 }
2954 
2955 #endif /* End of WLAN_FEATURE_STATS_EXT */
2956 
2957 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
2958 static inline void wlan_hdd_fill_station_info_signal(struct station_info
2959 						     *sinfo)
2960 {
2961 	sinfo->filled |= STATION_INFO_SIGNAL;
2962 }
2963 #else
2964 static inline void wlan_hdd_fill_station_info_signal(struct station_info
2965 						     *sinfo)
2966 {
2967 	sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2968 }
2969 #endif
2970 
2971 #ifdef LINKSPEED_DEBUG_ENABLED
2972 #define linkspeed_dbg(format, args...) pr_info(format, ## args)
2973 #else
2974 #define linkspeed_dbg(format, args...)
2975 #endif /* LINKSPEED_DEBUG_ENABLED */
2976 
2977 /**
2978  * wlan_hdd_fill_summary_stats() - populate station_info summary stats
2979  * @stats: summary stats to use as a source
2980  * @info: kernel station_info struct to use as a destination
2981  *
2982  * Return: None
2983  */
2984 static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
2985 					struct station_info *info)
2986 {
2987 	int i;
2988 
2989 	info->rx_packets = stats->rx_frm_cnt;
2990 	info->tx_packets = 0;
2991 	info->tx_retries = 0;
2992 	info->tx_failed = 0;
2993 
2994 	for (i = 0; i < WIFI_MAX_AC; ++i) {
2995 		info->tx_packets += stats->tx_frm_cnt[i];
2996 		info->tx_retries += stats->multiple_retry_cnt[i];
2997 		info->tx_failed += stats->fail_cnt[i];
2998 	}
2999 
3000 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
3001 	info->filled |= STATION_INFO_TX_PACKETS |
3002 			STATION_INFO_TX_RETRIES |
3003 			STATION_INFO_TX_FAILED |
3004 			STATION_INFO_RX_PACKETS;
3005 #else
3006 	info->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
3007 			BIT(NL80211_STA_INFO_TX_PACKETS) |
3008 			BIT(NL80211_STA_INFO_TX_RETRIES) |
3009 			BIT(NL80211_STA_INFO_TX_FAILED);
3010 #endif
3011 }
3012 
3013 /**
3014  * wlan_hdd_get_sap_stats() - get aggregate SAP stats
3015  * @adapter: sap adapter to get stats for
3016  * @info: kernel station_info struct to populate
3017  *
3018  * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to
3019  * support "station dump" and "station get" for SAP vdevs, even though they
3020  * aren't technically stations.
3021  *
3022  * Return: errno
3023  */
3024 static int
3025 wlan_hdd_get_sap_stats(struct hdd_adapter *adapter, struct station_info *info)
3026 {
3027 	QDF_STATUS status;
3028 
3029 	status = wlan_hdd_get_station_stats(adapter);
3030 	if (QDF_IS_STATUS_ERROR(status)) {
3031 		hdd_err("Failed to get SAP stats; status:%d", status);
3032 		return qdf_status_to_os_return(status);
3033 	}
3034 
3035 	wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, info);
3036 
3037 	return 0;
3038 }
3039 
3040 /**
3041  * hdd_get_max_rate_legacy() - get max rate for legacy mode
3042  * @stainfo: stainfo pointer
3043  * @rssidx: rssi index
3044  *
3045  * This function will get max rate for legacy mode
3046  *
3047  * Return: max rate on success, otherwise 0
3048  */
3049 static uint32_t hdd_get_max_rate_legacy(hdd_station_info_t *stainfo,
3050 					uint8_t rssidx)
3051 {
3052 	uint32_t maxrate = 0;
3053 	/*Minimum max rate, 6Mbps*/
3054 	int maxidx = 12;
3055 	int i;
3056 
3057 	/* check supported rates */
3058 	if (stainfo->max_supp_idx != 0xff &&
3059 	    maxidx < stainfo->max_supp_idx)
3060 		maxidx = stainfo->max_supp_idx;
3061 
3062 	/* check extended rates */
3063 	if (stainfo->max_ext_idx != 0xff &&
3064 	    maxidx < stainfo->max_ext_idx)
3065 		maxidx = stainfo->max_ext_idx;
3066 
3067 	for (i = 0; QDF_ARRAY_SIZE(supported_data_rate); i++) {
3068 		if (supported_data_rate[i].beacon_rate_index == maxidx)
3069 			maxrate =
3070 				supported_data_rate[i].supported_rate[rssidx];
3071 	}
3072 
3073 	hdd_debug("maxrate %d", maxrate);
3074 
3075 	return maxrate;
3076 }
3077 
3078 /**
3079  * hdd_get_max_rate_ht() - get max rate for ht mode
3080  * @stainfo: stainfo pointer
3081  * @stats: fw txrx status pointer
3082  * @rate_flags: rate flags
3083  * @nss: number of streams
3084  * @maxrate: returned max rate buffer pointer
3085  * @max_mcs_idx: max mcs idx
3086  * @report_max: report max rate or actual rate
3087  *
3088  * This function will get max rate for ht mode
3089  *
3090  * Return: None
3091  */
3092 static void hdd_get_max_rate_ht(hdd_station_info_t *stainfo,
3093 				struct hdd_fw_txrx_stats *stats,
3094 				uint32_t rate_flags,
3095 				uint8_t nss,
3096 				uint32_t *maxrate,
3097 				uint8_t *max_mcs_idx,
3098 				bool report_max)
3099 {
3100 	struct index_data_rate_type *supported_mcs_rate;
3101 	uint32_t tmprate;
3102 	uint8_t flag = 0, mcsidx;
3103 	int8_t rssi = stats->rssi;
3104 	int mode;
3105 	int i;
3106 
3107 	if (rate_flags & eHAL_TX_RATE_HT40)
3108 		mode = 1;
3109 	else
3110 		mode = 0;
3111 
3112 	if (rate_flags & eHAL_TX_RATE_HT40)
3113 		flag |= 1;
3114 	if (rate_flags & eHAL_TX_RATE_SGI)
3115 		flag |= 2;
3116 
3117 	supported_mcs_rate = (struct index_data_rate_type *)
3118 		((nss == 1) ? &supported_mcs_rate_nss1 :
3119 		 &supported_mcs_rate_nss2);
3120 
3121 	if (stainfo->max_mcs_idx == 0xff) {
3122 		hdd_err("invalid max_mcs_idx");
3123 		/* report real mcs idx */
3124 		mcsidx = stats->tx_rate.mcs;
3125 	} else {
3126 		mcsidx = stainfo->max_mcs_idx;
3127 	}
3128 
3129 	if (!report_max) {
3130 		for (i = 0; i < mcsidx; i++) {
3131 			if (rssi <= rssi_mcs_tbl[mode][i]) {
3132 				mcsidx = i;
3133 				break;
3134 			}
3135 		}
3136 		if (mcsidx < stats->tx_rate.mcs)
3137 			mcsidx = stats->tx_rate.mcs;
3138 	}
3139 
3140 	tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
3141 
3142 	hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3143 
3144 	*maxrate = tmprate;
3145 	*max_mcs_idx = mcsidx;
3146 }
3147 
3148 /**
3149  * hdd_get_max_rate_vht() - get max rate for vht mode
3150  * @stainfo: stainfo pointer
3151  * @stats: fw txrx status pointer
3152  * @rate_flags: rate flags
3153  * @nss: number of streams
3154  * @maxrate: returned max rate buffer pointer
3155  * @max_mcs_idx: max mcs idx
3156  * @report_max: report max rate or actual rate
3157  *
3158  * This function will get max rate for vht mode
3159  *
3160  * Return: None
3161  */
3162 static void hdd_get_max_rate_vht(hdd_station_info_t *stainfo,
3163 				 struct hdd_fw_txrx_stats *stats,
3164 				 uint32_t rate_flags,
3165 				 uint8_t nss,
3166 				 uint32_t *maxrate,
3167 				 uint8_t *max_mcs_idx,
3168 				 bool report_max)
3169 {
3170 	struct index_vht_data_rate_type *supported_vht_mcs_rate;
3171 	uint32_t tmprate = 0;
3172 	uint32_t vht_max_mcs;
3173 	uint8_t flag = 0, mcsidx = INVALID_MCS_IDX;
3174 	int8_t rssi = stats->rssi;
3175 	int mode;
3176 	int i;
3177 
3178 	supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
3179 		((nss == 1) ?
3180 		 &supported_vht_mcs_rate_nss1 :
3181 		 &supported_vht_mcs_rate_nss2);
3182 
3183 	if (rate_flags & eHAL_TX_RATE_VHT80)
3184 		mode = 2;
3185 	else if (rate_flags & eHAL_TX_RATE_VHT40)
3186 		mode = 1;
3187 	else
3188 		mode = 0;
3189 
3190 	if (rate_flags &
3191 	    (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 | eHAL_TX_RATE_VHT80)) {
3192 		vht_max_mcs =
3193 			(enum data_rate_11ac_max_mcs)
3194 			(stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK);
3195 		if (rate_flags & eHAL_TX_RATE_SGI)
3196 			flag |= 1;
3197 
3198 		if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) {
3199 			mcsidx = 7;
3200 		} else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) {
3201 			mcsidx = 8;
3202 		} else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) {
3203 			/*
3204 			 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3205 			 * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6
3206 			 * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8
3207 			 */
3208 			if ((rate_flags & eHAL_TX_RATE_VHT20) &&
3209 			    (nss != 3 && nss != 6))
3210 				mcsidx = 8;
3211 			else
3212 				mcsidx = 9;
3213 		} else {
3214 			hdd_err("invalid vht_max_mcs");
3215 			/* report real mcs idx */
3216 			mcsidx = stats->tx_rate.mcs;
3217 		}
3218 
3219 		if (!report_max) {
3220 			for (i = 0; i <= mcsidx; i++) {
3221 				if (rssi <= rssi_mcs_tbl[mode][i]) {
3222 					mcsidx = i;
3223 					break;
3224 				}
3225 			}
3226 			if (mcsidx < stats->tx_rate.mcs)
3227 				mcsidx = stats->tx_rate.mcs;
3228 		}
3229 
3230 		if (rate_flags & eHAL_TX_RATE_VHT80)
3231 			tmprate =
3232 		    supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag];
3233 		else if (rate_flags & eHAL_TX_RATE_VHT40)
3234 			tmprate =
3235 		    supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag];
3236 		else if (rate_flags & eHAL_TX_RATE_VHT20)
3237 			tmprate =
3238 		    supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag];
3239 	}
3240 
3241 	hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3242 
3243 	*maxrate = tmprate;
3244 	*max_mcs_idx = mcsidx;
3245 }
3246 
3247 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
3248 /**
3249  * hdd_fill_bw_mcs() - fill ch width and mcs flags
3250  * @stainfo: stainfo pointer
3251  * @rate_flags: HDD rate flags
3252  * @mcsidx: mcs index
3253  * @nss: number of streams
3254  * @vht: vht mode or not
3255  *
3256  * This function will fill ch width and mcs flags
3257  *
3258  * Return: None
3259  */
3260 static void hdd_fill_bw_mcs(struct station_info *sinfo,
3261 			    uint8_t rate_flags,
3262 			    uint8_t mcsidx,
3263 			    uint8_t nss,
3264 			    bool vht)
3265 {
3266 	if (vht) {
3267 		sinfo->txrate.nss = nss;
3268 		sinfo->txrate.mcs = mcsidx;
3269 		sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3270 		if (rate_flags & eHAL_TX_RATE_VHT80)
3271 			sinfo->txrate.bw = RATE_INFO_BW_80;
3272 		else if (rate_flags & eHAL_TX_RATE_VHT40)
3273 			sinfo->txrate.bw = RATE_INFO_BW_40;
3274 		else if (rate_flags & eHAL_TX_RATE_VHT20)
3275 			sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3276 	} else {
3277 		sinfo->txrate.mcs = (nss - 1) << 3;
3278 		sinfo->txrate.mcs |= mcsidx;
3279 		sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3280 		if (rate_flags & eHAL_TX_RATE_HT40)
3281 			sinfo->txrate.bw = RATE_INFO_BW_40;
3282 	}
3283 }
3284 #else
3285 /**
3286  * hdd_fill_bw_mcs() - fill ch width and mcs flags
3287  * @stainfo: stainfo pointer
3288  * @rate_flags: HDD rate flags
3289  * @mcsidx: mcs index
3290  * @nss: number of streams
3291  * @vht: vht mode or not
3292  *
3293  * This function will fill ch width and mcs flags
3294  *
3295  * Return: None
3296  */
3297 static void hdd_fill_bw_mcs(struct station_info *sinfo,
3298 			    uint8_t rate_flags,
3299 			    uint8_t mcsidx,
3300 			    uint8_t nss,
3301 			    bool vht)
3302 {
3303 	if (vht) {
3304 		sinfo->txrate.nss = nss;
3305 		sinfo->txrate.mcs = mcsidx;
3306 		sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3307 		if (rate_flags & eHAL_TX_RATE_VHT80)
3308 			sinfo->txrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
3309 		else if (rate_flags & eHAL_TX_RATE_VHT40)
3310 			sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
3311 		else if (rate_flags & eHAL_TX_RATE_VHT20)
3312 			sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3313 	} else {
3314 		sinfo->txrate.mcs = (nss - 1) << 3;
3315 		sinfo->txrate.mcs |= mcsidx;
3316 		sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3317 		if (rate_flags & eHAL_TX_RATE_HT40)
3318 			sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
3319 	}
3320 }
3321 #endif
3322 
3323 /**
3324  * hdd_fill_bw_mcs_vht() - fill ch width and mcs flags for VHT mode
3325  * @stainfo: stainfo pointer
3326  * @rate_flags: HDD rate flags
3327  * @mcsidx: mcs index
3328  * @nss: number of streams
3329  *
3330  * This function will fill ch width and mcs flags for VHT mode
3331  *
3332  * Return: None
3333  */
3334 static void hdd_fill_bw_mcs_vht(struct station_info *sinfo,
3335 				uint8_t rate_flags,
3336 				uint8_t mcsidx,
3337 				uint8_t nss)
3338 {
3339 	hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, true);
3340 }
3341 
3342 /**
3343  * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
3344  * @sinfo: station_info struct pointer
3345  * @rate_flags: HDD rate flags
3346  * @mcsidx: mcs index
3347  * @nss: number of streams
3348  * @maxrate: data rate (kbps)
3349  *
3350  * This function will fill rate info of sinfo struct
3351  *
3352  * Return: None
3353  */
3354 static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
3355 				     uint32_t rate_flags,
3356 				     uint8_t mcsidx,
3357 				     uint8_t nss,
3358 				     uint32_t maxrate)
3359 {
3360 	if (rate_flags & eHAL_TX_RATE_LEGACY) {
3361 		/* provide to the UI in units of 100kbps */
3362 		sinfo->txrate.legacy = maxrate;
3363 	} else {
3364 		/* must be MCS */
3365 		if (rate_flags &
3366 				(eHAL_TX_RATE_VHT80 |
3367 				 eHAL_TX_RATE_VHT40 |
3368 				 eHAL_TX_RATE_VHT20))
3369 			hdd_fill_bw_mcs_vht(sinfo, rate_flags, mcsidx, nss);
3370 
3371 		if (rate_flags & (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40))
3372 			hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, false);
3373 
3374 		if (rate_flags & eHAL_TX_RATE_SGI) {
3375 			if (!(sinfo->txrate.flags & RATE_INFO_FLAGS_VHT_MCS))
3376 				sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3377 			sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3378 		}
3379 	}
3380 
3381 	hdd_info("flag %x mcs %d legacy %d nss %d",
3382 		 sinfo->txrate.flags,
3383 		 sinfo->txrate.mcs,
3384 		 sinfo->txrate.legacy,
3385 		 sinfo->txrate.nss);
3386 }
3387 
3388 /**
3389  * hdd_fill_station_info_flags() - fill flags of sinfo struct
3390  * @sinfo: station_info struct pointer
3391  *
3392  * This function will fill flags of sinfo struct
3393  *
3394  * Return: None
3395  */
3396 static void hdd_fill_station_info_flags(struct station_info *sinfo)
3397 {
3398 	sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) |
3399 		BIT(NL80211_STA_INFO_TX_BYTES)   |
3400 		BIT(NL80211_STA_INFO_TX_BYTES64)   |
3401 		BIT(NL80211_STA_INFO_TX_BITRATE) |
3402 		BIT(NL80211_STA_INFO_TX_PACKETS) |
3403 		BIT(NL80211_STA_INFO_TX_RETRIES) |
3404 		BIT(NL80211_STA_INFO_TX_FAILED)  |
3405 		BIT(NL80211_STA_INFO_RX_BYTES)   |
3406 		BIT(NL80211_STA_INFO_RX_BYTES64)   |
3407 		BIT(NL80211_STA_INFO_RX_PACKETS) |
3408 		BIT(NL80211_STA_INFO_INACTIVE_TIME) |
3409 		BIT(NL80211_STA_INFO_CONNECTED_TIME);
3410 }
3411 
3412 /**
3413  * hdd_fill_rate_info() - fill rate info of sinfo
3414  * @sinfo: station_info struct pointer
3415  * @stainfo: stainfo pointer
3416  * @stats: fw txrx status pointer
3417  * @cfg: hdd config pointer
3418  *
3419  * This function will fill rate info of sinfo
3420  *
3421  * Return: None
3422  */
3423 static void hdd_fill_rate_info(struct station_info *sinfo,
3424 			       hdd_station_info_t *stainfo,
3425 			       struct hdd_fw_txrx_stats *stats,
3426 			       struct hdd_config *cfg)
3427 {
3428 	uint8_t rate_flags;
3429 	uint8_t mcsidx = 0xff;
3430 	uint32_t myrate, maxrate, tmprate;
3431 	int rssidx;
3432 	int nss = 1;
3433 
3434 	hdd_info("reportMaxLinkSpeed %d", cfg->reportMaxLinkSpeed);
3435 
3436 	/* convert to 100kbps expected in rate table */
3437 	myrate = stats->tx_rate.rate / 100;
3438 	rate_flags = stainfo->rate_flags;
3439 	if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3440 		nss = stainfo->nss;
3441 		if (eHDD_LINK_SPEED_REPORT_ACTUAL == cfg->reportMaxLinkSpeed) {
3442 			/* Get current rate flags if report actual */
3443 			if (stats->tx_rate.rate_flags)
3444 				rate_flags =
3445 					stats->tx_rate.rate_flags;
3446 			nss = stats->tx_rate.nss;
3447 		}
3448 
3449 		if (stats->tx_rate.mcs == INVALID_MCS_IDX)
3450 			rate_flags = eHAL_TX_RATE_LEGACY;
3451 	}
3452 
3453 	if (eHDD_LINK_SPEED_REPORT_ACTUAL != cfg->reportMaxLinkSpeed) {
3454 		/* we do not want to necessarily report the current speed */
3455 		if (eHDD_LINK_SPEED_REPORT_MAX == cfg->reportMaxLinkSpeed) {
3456 			/* report the max possible speed */
3457 			rssidx = 0;
3458 		} else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
3459 				cfg->reportMaxLinkSpeed) {
3460 			/* report the max possible speed with RSSI scaling */
3461 			if (stats->rssi >= cfg->linkSpeedRssiHigh) {
3462 				/* report the max possible speed */
3463 				rssidx = 0;
3464 			} else if (stats->rssi >=
3465 					cfg->linkSpeedRssiMid) {
3466 				/* report middle speed */
3467 				rssidx = 1;
3468 			} else if (stats->rssi >=
3469 					cfg->linkSpeedRssiLow) {
3470 				/* report middle speed */
3471 				rssidx = 2;
3472 			} else {
3473 				/* report actual speed */
3474 				rssidx = 3;
3475 			}
3476 		} else {
3477 			/* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
3478 			hdd_err("Invalid value for reportMaxLinkSpeed: %u",
3479 				cfg->reportMaxLinkSpeed);
3480 			rssidx = 0;
3481 		}
3482 
3483 		maxrate = hdd_get_max_rate_legacy(stainfo, rssidx);
3484 
3485 		/*
3486 		 * Get MCS Rate Set --
3487 		 * Only if we are connected in non legacy mode and not
3488 		 * reporting actual speed
3489 		 */
3490 		if ((rssidx != 3) &&
3491 		    !(rate_flags & eHAL_TX_RATE_LEGACY)) {
3492 			hdd_get_max_rate_vht(stainfo,
3493 					     stats,
3494 					     rate_flags,
3495 					     nss,
3496 					     &tmprate,
3497 					     &mcsidx,
3498 					     rssidx == 0);
3499 
3500 			if (maxrate < tmprate &&
3501 			    mcsidx != INVALID_MCS_IDX)
3502 				maxrate = tmprate;
3503 
3504 			if (mcsidx == INVALID_MCS_IDX)
3505 				hdd_get_max_rate_ht(stainfo,
3506 						    stats,
3507 						    rate_flags,
3508 						    nss,
3509 						    &tmprate,
3510 						    &mcsidx,
3511 						    rssidx == 0);
3512 
3513 			if (maxrate < tmprate &&
3514 			    mcsidx != INVALID_MCS_IDX)
3515 				maxrate = tmprate;
3516 		} else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3517 			maxrate = myrate;
3518 			mcsidx = stats->tx_rate.mcs;
3519 		}
3520 
3521 		/*
3522 		 * make sure we report a value at least as big as our
3523 		 * current rate
3524 		 */
3525 		if ((maxrate < myrate) || (maxrate == 0)) {
3526 			maxrate = myrate;
3527 			if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3528 				mcsidx = stats->tx_rate.mcs;
3529 				/*
3530 				 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3531 				 * - MCS9 is valid for VHT20 when Nss = 3 or
3532 				 *   Nss = 6
3533 				 * - MCS9 is not valid for VHT20 when
3534 				 *   Nss = 1,2,4,5,7,8
3535 				 */
3536 				if ((rate_flags & eHAL_TX_RATE_VHT20) &&
3537 				    (mcsidx > 8) &&
3538 				    (nss != 3 && nss != 6))
3539 					mcsidx = 8;
3540 			}
3541 		}
3542 	} else {
3543 		/* report current rate instead of max rate */
3544 		maxrate = myrate;
3545 		if (!(rate_flags & eHAL_TX_RATE_LEGACY))
3546 			mcsidx = stats->tx_rate.mcs;
3547 	}
3548 
3549 	hdd_fill_sinfo_rate_info(sinfo,
3550 				 rate_flags,
3551 				 mcsidx,
3552 				 nss,
3553 				 maxrate);
3554 }
3555 
3556 /**
3557  * wlan_hdd_fill_station_info() - fill station_info struct
3558  * @sinfo: station_info struct pointer
3559  * @stainfo: stainfo pointer
3560  * @stats: fw txrx status pointer
3561  * @cfg: hdd config pointer
3562  *
3563  * This function will fill station_info struct
3564  *
3565  * Return: None
3566  */
3567 static void wlan_hdd_fill_station_info(struct station_info *sinfo,
3568 				       hdd_station_info_t *stainfo,
3569 				       struct hdd_fw_txrx_stats *stats,
3570 				       struct hdd_config *cfg)
3571 {
3572 	qdf_time_t curr_time, dur;
3573 
3574 	curr_time = qdf_system_ticks();
3575 	dur = curr_time - stainfo->assoc_ts;
3576 	sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000;
3577 	dur = curr_time - stainfo->last_tx_rx_ts;
3578 	sinfo->inactive_time = qdf_system_ticks_to_msecs(dur);
3579 	sinfo->signal = stats->rssi;
3580 	sinfo->tx_bytes = stats->tx_bytes;
3581 	sinfo->tx_packets = stats->tx_packets;
3582 	sinfo->rx_bytes = stats->rx_bytes;
3583 	sinfo->rx_packets = stats->rx_packets;
3584 	sinfo->tx_failed = stats->tx_failed;
3585 	sinfo->tx_retries = stats->tx_retries;
3586 
3587 	/* tx rate info */
3588 	hdd_fill_rate_info(sinfo, stainfo, stats, cfg);
3589 
3590 	hdd_fill_station_info_flags(sinfo);
3591 
3592 	/* dump sta info*/
3593 	hdd_info("dump stainfo");
3594 	hdd_info("con_time %d inact_time %d tx_pkts %d rx_pkts %d",
3595 		 sinfo->connected_time, sinfo->inactive_time,
3596 		 sinfo->tx_packets, sinfo->rx_packets);
3597 	hdd_info("failed %d retries %d tx_bytes %lld rx_bytes %lld",
3598 		 sinfo->tx_failed, sinfo->tx_retries,
3599 		 sinfo->tx_bytes, sinfo->rx_bytes);
3600 	hdd_info("rssi %d mcs %d legacy %d nss %d flags %x",
3601 		 sinfo->signal, sinfo->txrate.mcs,
3602 		 sinfo->txrate.legacy, sinfo->txrate.nss,
3603 		 sinfo->txrate.flags);
3604 }
3605 
3606 /**
3607  * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs
3608  * @rate: Data rate (100 kbps)
3609  * @nss: Number of streams
3610  * @mcs: HT mcs index
3611  *
3612  * This function is used to construct HT rate flag with rate, nss and mcs
3613  *
3614  * Return: rate flags for success, 0 on failure.
3615  */
3616 static uint8_t hdd_get_rate_flags_ht(uint32_t rate,
3617 				     uint8_t nss,
3618 				     uint8_t mcs)
3619 {
3620 	struct index_data_rate_type *mcs_rate;
3621 	uint8_t flags = 0;
3622 
3623 	mcs_rate = (struct index_data_rate_type *)
3624 		((nss == 1) ? &supported_mcs_rate_nss1 :
3625 		 &supported_mcs_rate_nss2);
3626 
3627 	if (rate == mcs_rate[mcs].supported_rate[0]) {
3628 		flags |= eHAL_TX_RATE_HT20;
3629 	} else if (rate == mcs_rate[mcs].supported_rate[1]) {
3630 		flags |= eHAL_TX_RATE_HT40;
3631 	} else if (rate == mcs_rate[mcs].supported_rate[2]) {
3632 		flags |= eHAL_TX_RATE_HT20;
3633 		flags |= eHAL_TX_RATE_SGI;
3634 	} else if (rate == mcs_rate[mcs].supported_rate[3]) {
3635 		flags |= eHAL_TX_RATE_HT40;
3636 		flags |= eHAL_TX_RATE_SGI;
3637 	} else {
3638 		hdd_err("invalid params rate %d nss %d mcs %d",
3639 			rate, nss, mcs);
3640 	}
3641 
3642 	return flags;
3643 }
3644 
3645 /**
3646  * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs
3647  * @rate: Data rate (100 kbps)
3648  * @nss: Number of streams
3649  * @mcs: VHT mcs index
3650  *
3651  * This function is used to construct VHT rate flag with rate, nss and mcs
3652  *
3653  * Return: rate flags for success, 0 on failure.
3654  */
3655 static uint8_t hdd_get_rate_flags_vht(uint32_t rate,
3656 				      uint8_t nss,
3657 				      uint8_t mcs)
3658 {
3659 	struct index_vht_data_rate_type *mcs_rate;
3660 	uint8_t flags = 0;
3661 
3662 	mcs_rate = (struct index_vht_data_rate_type *)
3663 		((nss == 1) ?
3664 		 &supported_vht_mcs_rate_nss1 :
3665 		 &supported_vht_mcs_rate_nss2);
3666 
3667 	if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
3668 		flags |= eHAL_TX_RATE_VHT80;
3669 	} else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
3670 		flags |= eHAL_TX_RATE_VHT80;
3671 		flags |= eHAL_TX_RATE_SGI;
3672 	} else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
3673 		flags |= eHAL_TX_RATE_VHT40;
3674 	} else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
3675 		flags |= eHAL_TX_RATE_VHT40;
3676 		flags |= eHAL_TX_RATE_SGI;
3677 	} else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
3678 		flags |= eHAL_TX_RATE_VHT20;
3679 	} else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
3680 		flags |= eHAL_TX_RATE_VHT20;
3681 		flags |= eHAL_TX_RATE_SGI;
3682 	} else {
3683 		hdd_err("invalid params rate %d nss %d mcs %d",
3684 			rate, nss, mcs);
3685 	}
3686 
3687 	return flags;
3688 }
3689 
3690 /**
3691  * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs
3692  * @rate: Data rate (100 kbps)
3693  * @mode: Tx/Rx mode
3694  * @nss: Number of streams
3695  * @mcs: Mcs index
3696  *
3697  * This function is used to construct rate flag with rate, nss and mcs
3698  *
3699  * Return: rate flags for success, 0 on failure.
3700  */
3701 static uint8_t hdd_get_rate_flags(uint32_t rate,
3702 				  uint8_t mode,
3703 				  uint8_t nss,
3704 				  uint8_t mcs)
3705 {
3706 	uint8_t flags = 0;
3707 
3708 	if (mode == SIR_SME_PHY_MODE_HT)
3709 		flags = hdd_get_rate_flags_ht(rate, nss, mcs);
3710 	else if (mode == SIR_SME_PHY_MODE_VHT)
3711 		flags = hdd_get_rate_flags_vht(rate, nss, mcs);
3712 	else
3713 		hdd_err("invalid mode param %d", mode);
3714 
3715 	return flags;
3716 }
3717 
3718 /**
3719  * wlan_hdd_fill_rate_info() - fill HDD rate info from SIR peer info
3720  * @ap_ctx: AP Context
3721  * @peer_info: SIR peer info pointer
3722  *
3723  * This function is used to fill HDD rate info rom SIR peer info
3724  *
3725  * Return: None
3726  */
3727 static void wlan_hdd_fill_rate_info(struct hdd_ap_ctx *ap_ctx,
3728 				    struct sir_peer_info_ext *peer_info)
3729 {
3730 	uint8_t flags;
3731 	uint32_t rate_code;
3732 
3733 	/* tx rate info */
3734 	ap_ctx->txrx_stats.tx_rate.rate = peer_info->tx_rate;
3735 	rate_code = peer_info->tx_rate_code;
3736 
3737 	if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3738 			WMI_RATE_PREAMBLE_HT)
3739 		ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_HT;
3740 	else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3741 			WMI_RATE_PREAMBLE_VHT)
3742 		ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_VHT;
3743 	else
3744 		ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
3745 
3746 	ap_ctx->txrx_stats.tx_rate.nss =
3747 		WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3748 	ap_ctx->txrx_stats.tx_rate.mcs =
3749 		WMI_GET_HW_RATECODE_RATE_V1(rate_code);
3750 
3751 	flags = hdd_get_rate_flags(ap_ctx->txrx_stats.tx_rate.rate / 100,
3752 				   ap_ctx->txrx_stats.tx_rate.mode,
3753 				   ap_ctx->txrx_stats.tx_rate.nss,
3754 				   ap_ctx->txrx_stats.tx_rate.mcs);
3755 
3756 	ap_ctx->txrx_stats.tx_rate.rate_flags = flags;
3757 
3758 	hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x",
3759 		  ap_ctx->txrx_stats.tx_rate.mode,
3760 		  ap_ctx->txrx_stats.tx_rate.nss,
3761 		  ap_ctx->txrx_stats.tx_rate.mcs,
3762 		  ap_ctx->txrx_stats.tx_rate.rate_flags,
3763 		  flags);
3764 
3765 	/* rx rate info */
3766 	ap_ctx->txrx_stats.rx_rate.rate = peer_info->rx_rate;
3767 	rate_code = peer_info->rx_rate_code;
3768 
3769 	if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3770 			WMI_RATE_PREAMBLE_HT)
3771 		ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_HT;
3772 	else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3773 			WMI_RATE_PREAMBLE_VHT)
3774 		ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_VHT;
3775 	else
3776 		ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
3777 
3778 	ap_ctx->txrx_stats.rx_rate.nss =
3779 		WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3780 	ap_ctx->txrx_stats.rx_rate.mcs =
3781 		WMI_GET_HW_RATECODE_RATE_V1(rate_code);
3782 
3783 	flags = hdd_get_rate_flags(ap_ctx->txrx_stats.rx_rate.rate / 100,
3784 				   ap_ctx->txrx_stats.rx_rate.mode,
3785 				   ap_ctx->txrx_stats.rx_rate.nss,
3786 				   ap_ctx->txrx_stats.rx_rate.mcs);
3787 
3788 	ap_ctx->txrx_stats.rx_rate.rate_flags = flags;
3789 
3790 	hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x",
3791 		 ap_ctx->txrx_stats.rx_rate.mode,
3792 		 ap_ctx->txrx_stats.rx_rate.nss,
3793 		 ap_ctx->txrx_stats.rx_rate.mcs,
3794 		 ap_ctx->txrx_stats.rx_rate.rate_flags,
3795 		 flags);
3796 }
3797 
3798 int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3799 				struct net_device *dev,
3800 				const u8 *mac,
3801 				struct station_info *sinfo);
3802 
3803 /**
3804  * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
3805  * @wiphy: pointer to wiphy
3806  * @dev: pointer to net_device structure
3807  * @mac: request peer mac address
3808  * @sinfo: pointer to station_info struct
3809  *
3810  * This function will get remote peer info from fw and fill sinfo struct
3811  *
3812  * Return: 0 on success, otherwise error value
3813  */
3814 int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3815 				struct net_device *dev,
3816 				const u8 *mac,
3817 				struct station_info *sinfo)
3818 {
3819 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3820 	struct hdd_context *hddctx = wiphy_priv(wiphy);
3821 	struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
3822 	hdd_station_info_t *stainfo = NULL;
3823 	struct hdd_config *cfg;
3824 	struct qdf_mac_addr macaddr;
3825 	struct sir_peer_info_ext peer_info;
3826 	int status;
3827 	int i;
3828 
3829 	status = wlan_hdd_validate_context(hddctx);
3830 	if (status != 0)
3831 		return status;
3832 
3833 	cfg = hddctx->config;
3834 
3835 	hdd_debug("get peer %pM info", mac);
3836 
3837 	for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
3838 		if (!qdf_mem_cmp(adapter->aStaInfo[i].macAddrSTA.bytes,
3839 				 mac,
3840 				 QDF_MAC_ADDR_SIZE)) {
3841 			stainfo = &adapter->aStaInfo[i];
3842 			break;
3843 		}
3844 	}
3845 
3846 	if (!stainfo) {
3847 		hdd_err("peer %pM not found", mac);
3848 		return -EINVAL;
3849 	}
3850 
3851 	qdf_mem_copy(macaddr.bytes, mac, QDF_MAC_ADDR_SIZE);
3852 	status = wlan_hdd_get_peer_info(adapter, macaddr, &peer_info);
3853 	if (status) {
3854 		hdd_err("fail to get peer info from fw");
3855 		return -EPERM;
3856 	}
3857 
3858 	qdf_mem_zero(&ap_ctx->txrx_stats, sizeof(ap_ctx->txrx_stats));
3859 	ap_ctx->txrx_stats.tx_packets = peer_info.tx_packets;
3860 	ap_ctx->txrx_stats.tx_bytes = peer_info.tx_bytes;
3861 	ap_ctx->txrx_stats.rx_packets = peer_info.rx_packets;
3862 	ap_ctx->txrx_stats.rx_bytes = peer_info.rx_bytes;
3863 	ap_ctx->txrx_stats.tx_retries = peer_info.tx_retries;
3864 	ap_ctx->txrx_stats.tx_failed = peer_info.tx_failed;
3865 	ap_ctx->txrx_stats.rssi =
3866 		peer_info.rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM;
3867 	wlan_hdd_fill_rate_info(ap_ctx, &peer_info);
3868 
3869 	wlan_hdd_fill_station_info(sinfo, stainfo, &ap_ctx->txrx_stats, cfg);
3870 
3871 	return status;
3872 }
3873 
3874 /**
3875  * __wlan_hdd_cfg80211_get_station() - get station statistics
3876  * @wiphy: Pointer to wiphy
3877  * @dev: Pointer to network device
3878  * @mac: Pointer to mac
3879  * @sinfo: Pointer to station info
3880  *
3881  * Return: 0 for success, non-zero for failure
3882  */
3883 static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
3884 					   struct net_device *dev,
3885 					   const uint8_t *mac,
3886 					   struct station_info *sinfo)
3887 {
3888 	struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3889 	struct hdd_station_ctx *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
3890 	int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length;
3891 	uint8_t rate_flags;
3892 	uint8_t mcs_index;
3893 
3894 	struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
3895 	struct hdd_config *pCfg = hdd_ctx->config;
3896 
3897 	uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
3898 	uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX;
3899 	uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
3900 	uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
3901 	uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET];
3902 	uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET;
3903 	uint16_t maxRate = 0;
3904 	int8_t snr = 0;
3905 	uint16_t myRate;
3906 	uint16_t currentRate = 0;
3907 	uint8_t maxSpeedMCS = 0;
3908 	uint8_t maxMCSIdx = 0;
3909 	uint8_t rateFlag = 1;
3910 	uint8_t i, j, rssidx;
3911 	uint8_t nss = 1;
3912 	int status, mode = 0, maxHtIdx;
3913 	struct index_vht_data_rate_type *supported_vht_mcs_rate;
3914 	struct index_data_rate_type *supported_mcs_rate;
3915 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
3916 	bool rssi_stats_valid = false;
3917 #endif
3918 
3919 	uint32_t vht_mcs_map;
3920 	enum data_rate_11ac_max_mcs vht_max_mcs;
3921 
3922 	ENTER_DEV(dev);
3923 
3924 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3925 		hdd_err("Command not allowed in FTM mode");
3926 		return -EINVAL;
3927 	}
3928 
3929 	status = wlan_hdd_validate_context(hdd_ctx);
3930 	if (status)
3931 		return status;
3932 
3933 	if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
3934 		hdd_err("invalid session id: %d", pAdapter->sessionId);
3935 		return -EINVAL;
3936 	}
3937 
3938 	if (pAdapter->device_mode == QDF_SAP_MODE)
3939 		return wlan_hdd_get_sap_stats(pAdapter, sinfo);
3940 
3941 	if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) ||
3942 	    (0 == ssidlen)) {
3943 		hdd_debug("Not associated or Invalid ssidlen, %d",
3944 			ssidlen);
3945 		/*To keep GUI happy */
3946 		return 0;
3947 	}
3948 
3949 	if (true == pHddStaCtx->hdd_ReassocScenario) {
3950 		hdd_debug("Roaming is in progress, cannot continue with this request");
3951 		/*
3952 		 * supplicant reports very low rssi to upper layer
3953 		 * and handover happens to cellular.
3954 		 * send the cached rssi when get_station
3955 		 */
3956 		sinfo->signal = pAdapter->rssi;
3957 		wlan_hdd_fill_station_info_signal(sinfo);
3958 		return 0;
3959 	}
3960 
3961 	wlan_hdd_get_station_stats(pAdapter);
3962 
3963 	if (pAdapter->hdd_stats.summary_stat.rssi)
3964 		pAdapter->rssi = pAdapter->hdd_stats.summary_stat.rssi;
3965 
3966 	/* for new connection there might be no valid previous RSSI */
3967 	if (!pAdapter->rssi) {
3968 		hdd_get_rssi_snr_by_bssid(pAdapter,
3969 				pHddStaCtx->conn_info.bssId.bytes,
3970 				&pAdapter->rssi, NULL);
3971 	}
3972 
3973 	sinfo->signal = pAdapter->rssi;
3974 	snr = pAdapter->hdd_stats.summary_stat.snr;
3975 	hdd_debug("snr: %d, rssi: %d",
3976 		pAdapter->hdd_stats.summary_stat.snr,
3977 		pAdapter->hdd_stats.summary_stat.rssi);
3978 	pHddStaCtx->conn_info.signal = sinfo->signal;
3979 	pHddStaCtx->conn_info.noise =
3980 		pHddStaCtx->conn_info.signal - snr;
3981 
3982 	wlan_hdd_fill_station_info_signal(sinfo);
3983 
3984 	/*
3985 	 * we notify connect to lpass here instead of during actual
3986 	 * connect processing because rssi info is not accurate during
3987 	 * actual connection.  lpass will ensure the notification is
3988 	 * only processed once per association.
3989 	 */
3990 	hdd_lpass_notify_connect(pAdapter);
3991 
3992 	rate_flags = pAdapter->hdd_stats.ClassA_stat.tx_rate_flags;
3993 	mcs_index = pAdapter->hdd_stats.ClassA_stat.mcs_index;
3994 
3995 	/* convert to the UI units of 100kbps */
3996 	myRate = pAdapter->hdd_stats.ClassA_stat.tx_rate * 5;
3997 	if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3998 		nss = pAdapter->hdd_stats.ClassA_stat.nss;
3999 		if ((nss > 1) &&
4000 		    policy_mgr_is_current_hwmode_dbs(hdd_ctx->hdd_psoc) &&
4001 		    !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->hdd_psoc)) {
4002 			hdd_debug("Hw mode is DBS, Reduce nss(%d) to 1", nss);
4003 			nss--;
4004 		}
4005 
4006 		if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) {
4007 			/* Get current rate flags if report actual */
4008 			/* WMA fails to find mcs_index for legacy tx rates */
4009 			if (mcs_index == INVALID_MCS_IDX && myRate)
4010 				rate_flags = eHAL_TX_RATE_LEGACY;
4011 			else
4012 				rate_flags =
4013 				 pAdapter->hdd_stats.ClassA_stat.mcs_rate_flags;
4014 		}
4015 
4016 		if (mcs_index == INVALID_MCS_IDX)
4017 			mcs_index = 0;
4018 	}
4019 
4020 	hdd_debug("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d",
4021 		 sinfo->signal, pCfg->reportMaxLinkSpeed, myRate,
4022 		 (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid,
4023 		 (int)pCfg->linkSpeedRssiLow, (int)rate_flags, (int)mcs_index);
4024 
4025 	/* assume basic BW. anything else will override this later */
4026 	hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_20);
4027 
4028 	if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) {
4029 		/* we do not want to necessarily report the current speed */
4030 		if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) {
4031 			/* report the max possible speed */
4032 			rssidx = 0;
4033 		} else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
4034 			   pCfg->reportMaxLinkSpeed) {
4035 			/* report the max possible speed with RSSI scaling */
4036 			if (sinfo->signal >= pCfg->linkSpeedRssiHigh) {
4037 				/* report the max possible speed */
4038 				rssidx = 0;
4039 			} else if (sinfo->signal >= pCfg->linkSpeedRssiMid) {
4040 				/* report middle speed */
4041 				rssidx = 1;
4042 			} else if (sinfo->signal >= pCfg->linkSpeedRssiLow) {
4043 				/* report middle speed */
4044 				rssidx = 2;
4045 			} else {
4046 				/* report actual speed */
4047 				rssidx = 3;
4048 			}
4049 		} else {
4050 			/* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
4051 			hdd_err("Invalid value for reportMaxLinkSpeed: %u",
4052 			       pCfg->reportMaxLinkSpeed);
4053 			rssidx = 0;
4054 		}
4055 
4056 		maxRate = 0;
4057 
4058 		/* Get Basic Rate Set */
4059 		if (0 !=
4060 		    sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
4061 				    WNI_CFG_OPERATIONAL_RATE_SET,
4062 				    OperationalRates,
4063 				    &ORLeng)) {
4064 			hdd_err("cfg get returned failure");
4065 			/*To keep GUI happy */
4066 			return 0;
4067 		}
4068 
4069 		for (i = 0; i < ORLeng; i++) {
4070 			for (j = 0;
4071 			     j < ARRAY_SIZE(supported_data_rate); j++) {
4072 				/* Validate Rate Set */
4073 				if (supported_data_rate[j].beacon_rate_index ==
4074 				    (OperationalRates[i] & 0x7F)) {
4075 					currentRate =
4076 						supported_data_rate[j].
4077 						supported_rate[rssidx];
4078 					break;
4079 				}
4080 			}
4081 			/* Update MAX rate */
4082 			maxRate =
4083 				(currentRate > maxRate) ? currentRate : maxRate;
4084 		}
4085 
4086 		/* Get Extended Rate Set */
4087 		if (0 !=
4088 		    sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
4089 				    WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
4090 				    ExtendedRates, &ERLeng)) {
4091 			hdd_err("cfg get returned failure");
4092 			/*To keep GUI happy */
4093 			return 0;
4094 		}
4095 
4096 		for (i = 0; i < ERLeng; i++) {
4097 			for (j = 0;
4098 			     j < ARRAY_SIZE(supported_data_rate); j++) {
4099 				if (supported_data_rate[j].beacon_rate_index ==
4100 				    (ExtendedRates[i] & 0x7F)) {
4101 					currentRate =
4102 						supported_data_rate[j].
4103 						supported_rate[rssidx];
4104 					break;
4105 				}
4106 			}
4107 			/* Update MAX rate */
4108 			maxRate =
4109 				(currentRate > maxRate) ? currentRate : maxRate;
4110 		}
4111 		/*
4112 		 * Get MCS Rate Set --
4113 		 * Only if we are connected in non legacy mode and not
4114 		 * reporting actual speed
4115 		 */
4116 		if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) {
4117 			if (0 !=
4118 			    sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
4119 					    WNI_CFG_CURRENT_MCS_SET, MCSRates,
4120 					    &MCSLeng)) {
4121 				hdd_err("cfg get returned failure");
4122 				/*To keep GUI happy */
4123 				return 0;
4124 			}
4125 			rateFlag = 0;
4126 			supported_vht_mcs_rate =
4127 				(struct index_vht_data_rate_type *)
4128 				((nss ==
4129 				  1) ? &supported_vht_mcs_rate_nss1 :
4130 				 &supported_vht_mcs_rate_nss2);
4131 
4132 			if (rate_flags & eHAL_TX_RATE_VHT80)
4133 				mode = 2;
4134 			else if ((rate_flags & eHAL_TX_RATE_VHT40) ||
4135 				 (rate_flags & eHAL_TX_RATE_HT40))
4136 				mode = 1;
4137 			else
4138 				mode = 0;
4139 
4140 			/* VHT80 rate has seperate rate table */
4141 			if (rate_flags &
4142 			    (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
4143 			     eHAL_TX_RATE_VHT80)) {
4144 				sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter),
4145 						WNI_CFG_VHT_TX_MCS_MAP,
4146 						&vht_mcs_map);
4147 				vht_max_mcs = (enum data_rate_11ac_max_mcs)
4148 					(vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
4149 				if (rate_flags & eHAL_TX_RATE_SGI)
4150 					rateFlag |= 1;
4151 
4152 				if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs)
4153 					maxMCSIdx = 7;
4154 				else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs)
4155 					maxMCSIdx = 8;
4156 				else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs)
4157 					maxMCSIdx = 9;
4158 
4159 				if (rssidx != 0) {
4160 					for (i = 0; i <= maxMCSIdx; i++) {
4161 						if (sinfo->signal <=
4162 						    rssi_mcs_tbl[mode][i]) {
4163 							maxMCSIdx = i;
4164 							break;
4165 						}
4166 					}
4167 				}
4168 
4169 				if (rate_flags & eHAL_TX_RATE_VHT80) {
4170 					currentRate =
4171 					  supported_vht_mcs_rate[mcs_index].
4172 					  supported_VHT80_rate[rateFlag];
4173 					maxRate =
4174 					  supported_vht_mcs_rate[maxMCSIdx].
4175 						supported_VHT80_rate[rateFlag];
4176 				} else if (rate_flags & eHAL_TX_RATE_VHT40) {
4177 					currentRate =
4178 					  supported_vht_mcs_rate[mcs_index].
4179 					  supported_VHT40_rate[rateFlag];
4180 					maxRate =
4181 					  supported_vht_mcs_rate[maxMCSIdx].
4182 						supported_VHT40_rate[rateFlag];
4183 				} else if (rate_flags & eHAL_TX_RATE_VHT20) {
4184 					currentRate =
4185 					  supported_vht_mcs_rate[mcs_index].
4186 					  supported_VHT20_rate[rateFlag];
4187 					maxRate =
4188 					  supported_vht_mcs_rate[maxMCSIdx].
4189 					  supported_VHT20_rate[rateFlag];
4190 				}
4191 
4192 				maxSpeedMCS = 1;
4193 				if (currentRate > maxRate)
4194 					maxRate = currentRate;
4195 
4196 			} else {
4197 				if (rate_flags & eHAL_TX_RATE_HT40)
4198 					rateFlag |= 1;
4199 				if (rate_flags & eHAL_TX_RATE_SGI)
4200 					rateFlag |= 2;
4201 
4202 				supported_mcs_rate =
4203 					(struct index_data_rate_type *)
4204 					((nss ==
4205 					  1) ? &supported_mcs_rate_nss1 :
4206 					 &supported_mcs_rate_nss2);
4207 
4208 				maxHtIdx = MAX_HT_MCS_IDX;
4209 				if (rssidx != 0) {
4210 					for (i = 0; i < MAX_HT_MCS_IDX; i++) {
4211 						if (sinfo->signal <=
4212 						    rssi_mcs_tbl[mode][i]) {
4213 							maxHtIdx = i + 1;
4214 							break;
4215 						}
4216 					}
4217 				}
4218 
4219 				for (i = 0; i < MCSLeng; i++) {
4220 					for (j = 0; j < maxHtIdx; j++) {
4221 						if (supported_mcs_rate[j].
4222 						    beacon_rate_index ==
4223 						    MCSRates[i]) {
4224 							currentRate =
4225 							  supported_mcs_rate[j].
4226 							  supported_rate
4227 							  [rateFlag];
4228 							maxMCSIdx =
4229 							  supported_mcs_rate[j].
4230 							  beacon_rate_index;
4231 							break;
4232 						}
4233 					}
4234 
4235 					if ((j < MAX_HT_MCS_IDX)
4236 					    && (currentRate > maxRate)) {
4237 						maxRate = currentRate;
4238 					}
4239 					maxSpeedMCS = 1;
4240 				}
4241 			}
4242 		}
4243 
4244 		else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
4245 			maxRate = myRate;
4246 			maxSpeedMCS = 1;
4247 			maxMCSIdx = mcs_index;
4248 		}
4249 		/* report a value at least as big as current rate */
4250 		if ((maxRate < myRate) || (0 == maxRate)) {
4251 			maxRate = myRate;
4252 			if (rate_flags & eHAL_TX_RATE_LEGACY) {
4253 				maxSpeedMCS = 0;
4254 			} else {
4255 				maxSpeedMCS = 1;
4256 				maxMCSIdx = mcs_index;
4257 			}
4258 		}
4259 
4260 		if (rate_flags & eHAL_TX_RATE_LEGACY) {
4261 			sinfo->txrate.legacy = maxRate;
4262 			linkspeed_dbg("Reporting legacy rate %d\n",
4263 				      sinfo->txrate.legacy);
4264 		} else {
4265 			sinfo->txrate.mcs = maxMCSIdx;
4266 			sinfo->txrate.nss = nss;
4267 			sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
4268 
4269 			if (rate_flags & eHAL_TX_RATE_VHT80)
4270 				hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_80);
4271 			else if (rate_flags & eHAL_TX_RATE_VHT40)
4272 				hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_40);
4273 
4274 			if (rate_flags &
4275 			    (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
4276 				sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
4277 				if (rate_flags & eHAL_TX_RATE_HT40)
4278 					hdd_set_rate_bw(&sinfo->txrate,
4279 							HDD_RATE_BW_40);
4280 			}
4281 
4282 			if (rate_flags & eHAL_TX_RATE_SGI) {
4283 				if (!
4284 				    (sinfo->txrate.
4285 				     flags & RATE_INFO_FLAGS_VHT_MCS))
4286 					sinfo->txrate.flags |=
4287 						RATE_INFO_FLAGS_MCS;
4288 				sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
4289 			}
4290 			linkspeed_dbg("Reporting MCS rate %d flags %x\n",
4291 				      sinfo->txrate.mcs, sinfo->txrate.flags);
4292 		}
4293 	} else {
4294 		/* report current rate instead of max rate */
4295 
4296 		if (rate_flags & eHAL_TX_RATE_LEGACY) {
4297 			/* provide to the UI in units of 100kbps */
4298 			sinfo->txrate.legacy = myRate;
4299 			linkspeed_dbg("Reporting actual legacy rate %d\n",
4300 				      sinfo->txrate.legacy);
4301 		} else {
4302 			/* must be MCS */
4303 			sinfo->txrate.mcs = mcs_index;
4304 			sinfo->txrate.nss = nss;
4305 			sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
4306 
4307 			if (rate_flags & eHAL_TX_RATE_VHT80)
4308 				hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_80);
4309 			else if (rate_flags & eHAL_TX_RATE_VHT40)
4310 				hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_40);
4311 
4312 			if (rate_flags &
4313 			    (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
4314 				sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
4315 				if (rate_flags & eHAL_TX_RATE_HT40)
4316 					hdd_set_rate_bw(&sinfo->txrate,
4317 							HDD_RATE_BW_40);
4318 			}
4319 
4320 			if (rate_flags & eHAL_TX_RATE_SGI) {
4321 				sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
4322 				sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
4323 			}
4324 
4325 			linkspeed_dbg("Reporting actual MCS rate %d flags %x\n",
4326 				      sinfo->txrate.mcs, sinfo->txrate.flags);
4327 		}
4328 	}
4329 
4330 	wlan_hdd_fill_summary_stats(&pAdapter->hdd_stats.summary_stat, sinfo);
4331 	sinfo->tx_bytes = pAdapter->stats.tx_bytes;
4332 	sinfo->rx_bytes = pAdapter->stats.rx_bytes;
4333 	sinfo->rx_packets = pAdapter->stats.rx_packets;
4334 
4335 	qdf_mem_copy(&pHddStaCtx->conn_info.txrate,
4336 		     &sinfo->txrate, sizeof(sinfo->txrate));
4337 
4338 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
4339 	sinfo->filled |= STATION_INFO_TX_BITRATE |
4340 			 STATION_INFO_TX_BYTES   |
4341 			 STATION_INFO_RX_BYTES   |
4342 			 STATION_INFO_RX_PACKETS;
4343 #else
4344 	sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE) |
4345 			 BIT(NL80211_STA_INFO_TX_BYTES)   |
4346 			 BIT(NL80211_STA_INFO_RX_BYTES)   |
4347 			 BIT(NL80211_STA_INFO_RX_PACKETS);
4348 #endif
4349 
4350 	if (rate_flags & eHAL_TX_RATE_LEGACY)
4351 		hdd_debug("Reporting legacy rate %d pkt cnt tx %d rx %d",
4352 			sinfo->txrate.legacy, sinfo->tx_packets,
4353 			sinfo->rx_packets);
4354 	else
4355 		hdd_debug("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d",
4356 			sinfo->txrate.mcs, sinfo->txrate.flags,
4357 			sinfo->tx_packets, sinfo->rx_packets);
4358 
4359 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
4360 	sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
4361 	for (i = 0; i < NUM_CHAINS_MAX; i++) {
4362 		sinfo->chain_signal_avg[i] =
4363 			   pAdapter->hdd_stats.per_chain_rssi_stats.rssi[i];
4364 		sinfo->chains |= 1 << i;
4365 		if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
4366 				   sinfo->chain_signal_avg[i] != 0)
4367 			sinfo->signal_avg = sinfo->chain_signal_avg[i];
4368 
4369 		hdd_debug("RSSI for chain %d, vdev_id %d is %d",
4370 			i, pAdapter->sessionId, sinfo->chain_signal_avg[i]);
4371 
4372 		if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
4373 			rssi_stats_valid = true;
4374 	}
4375 
4376 	if (rssi_stats_valid) {
4377 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
4378 		sinfo->filled |= STATION_INFO_CHAIN_SIGNAL_AVG;
4379 		sinfo->filled |= STATION_INFO_SIGNAL_AVG;
4380 #else
4381 		sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
4382 		sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
4383 #endif
4384 	}
4385 #endif
4386 
4387 	MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
4388 			 TRACE_CODE_HDD_CFG80211_GET_STA,
4389 			 pAdapter->sessionId, maxRate));
4390 
4391 	EXIT();
4392 
4393 	return 0;
4394 }
4395 
4396 /**
4397  * wlan_hdd_cfg80211_get_station() - get station statistics
4398  * @wiphy: Pointer to wiphy
4399  * @dev: Pointer to network device
4400  * @mac: Pointer to mac
4401  * @sinfo: Pointer to station info
4402  *
4403  * Return: 0 for success, non-zero for failure
4404  */
4405 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
4406 int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4407 				  struct net_device *dev, const uint8_t *mac,
4408 				  struct station_info *sinfo)
4409 #else
4410 int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4411 				  struct net_device *dev, uint8_t *mac,
4412 				  struct station_info *sinfo)
4413 #endif
4414 {
4415 	int ret;
4416 
4417 	cds_ssr_protect(__func__);
4418 	ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4419 	cds_ssr_unprotect(__func__);
4420 
4421 	return ret;
4422 }
4423 
4424 /**
4425  * __wlan_hdd_cfg80211_dump_station() - dump station statistics
4426  * @wiphy: Pointer to wiphy
4427  * @dev: Pointer to network device
4428  * @idx: variable to determine whether to get stats or not
4429  * @mac: Pointer to mac
4430  * @sinfo: Pointer to station info
4431  *
4432  * Return: 0 for success, non-zero for failure
4433  */
4434 static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4435 				struct net_device *dev,
4436 				int idx, u8 *mac,
4437 				struct station_info *sinfo)
4438 {
4439 	struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
4440 
4441 	hdd_debug("%s: idx %d", __func__, idx);
4442 	if (idx != 0)
4443 		return -ENOENT;
4444 	qdf_mem_copy(mac, hdd_ctx->config->intfMacAddr[0].bytes,
4445 				QDF_MAC_ADDR_SIZE);
4446 	return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4447 }
4448 
4449 /**
4450  * wlan_hdd_cfg80211_dump_station() - dump station statistics
4451  * @wiphy: Pointer to wiphy
4452  * @dev: Pointer to network device
4453  * @idx: variable to determine whether to get stats or not
4454  * @mac: Pointer to mac
4455  * @sinfo: Pointer to station info
4456  *
4457  * Return: 0 for success, non-zero for failure
4458  */
4459 int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4460 				struct net_device *dev,
4461 				int idx, u8 *mac,
4462 				struct station_info *sinfo)
4463 {
4464 	int ret;
4465 
4466 	cds_ssr_protect(__func__);
4467 	ret = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
4468 	cds_ssr_unprotect(__func__);
4469 	return ret;
4470 }
4471 
4472 /**
4473  * hdd_get_stats() - Function to retrieve interface statistics
4474  * @dev: pointer to network device
4475  *
4476  * This function is the ndo_get_stats method for all netdevs
4477  * registered with the kernel
4478  *
4479  * Return: pointer to net_device_stats structure
4480  */
4481 struct net_device_stats *hdd_get_stats(struct net_device *dev)
4482 {
4483 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4484 
4485 	ENTER_DEV(dev);
4486 	return &adapter->stats;
4487 }
4488 
4489 
4490 /*
4491  * time = cycle_count * cycle
4492  * cycle = 1 / clock_freq
4493  * Since the unit of clock_freq reported from
4494  * FW is MHZ, and we want to calculate time in
4495  * ms level, the result is
4496  * time = cycle / (clock_freq * 1000)
4497  */
4498 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
4499 static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4500 				    struct scan_chan_info *chan_info,
4501 				    struct ieee80211_channel *channels)
4502 {
4503 	uint64_t clock_freq = chan_info->clock_freq * 1000;
4504 
4505 	if (channels->center_freq != (uint16_t)chan_info->freq)
4506 		return false;
4507 
4508 	survey->channel = channels;
4509 	survey->noise = chan_info->noise_floor;
4510 	survey->filled = SURVEY_INFO_NOISE_DBM;
4511 
4512 	if (opfreq == chan_info->freq)
4513 		survey->filled |= SURVEY_INFO_IN_USE;
4514 
4515 	if (clock_freq == 0)
4516 		return true;
4517 
4518 	survey->time = chan_info->cycle_count / clock_freq;
4519 	survey->time_busy = chan_info->rx_clear_count / clock_freq;
4520 	survey->time_tx = chan_info->tx_frame_count / clock_freq;
4521 
4522 	survey->filled |= SURVEY_INFO_TIME |
4523 			  SURVEY_INFO_TIME_BUSY |
4524 			  SURVEY_INFO_TIME_TX;
4525 	return true;
4526 }
4527 #else
4528 static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4529 				    struct scan_chan_info *chan_info,
4530 				    struct ieee80211_channel *channels)
4531 {
4532 	uint64_t clock_freq = chan_info->clock_freq * 1000;
4533 
4534 	if (channels->center_freq != (uint16_t)chan_info->freq)
4535 		return false;
4536 
4537 	survey->channel = channels;
4538 	survey->noise = chan_info->noise_floor;
4539 	survey->filled = SURVEY_INFO_NOISE_DBM;
4540 
4541 	if (opfreq == chan_info->freq)
4542 		survey->filled |= SURVEY_INFO_IN_USE;
4543 
4544 	if (clock_freq == 0)
4545 		return true;
4546 
4547 	survey->channel_time = chan_info->cycle_count / clock_freq;
4548 	survey->channel_time_busy = chan_info->rx_clear_count / clock_freq;
4549 	survey->channel_time_tx = chan_info->tx_frame_count / clock_freq;
4550 
4551 	survey->filled |= SURVEY_INFO_CHANNEL_TIME |
4552 			  SURVEY_INFO_CHANNEL_TIME_BUSY |
4553 			  SURVEY_INFO_CHANNEL_TIME_TX;
4554 	return true;
4555 }
4556 #endif
4557 
4558 static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
4559 		struct hdd_adapter *pAdapter, struct survey_info *survey, int idx)
4560 {
4561 	bool filled = false;
4562 	int i, j = 0;
4563 	uint32_t channel = 0, opfreq; /* Initialization Required */
4564 	struct hdd_context *hdd_ctx;
4565 
4566 	hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
4567 	sme_get_operation_channel(hdd_ctx->hHal, &channel, pAdapter->sessionId);
4568 	hdd_wlan_get_freq(channel, &opfreq);
4569 
4570 	mutex_lock(&hdd_ctx->chan_info_lock);
4571 
4572 	for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) {
4573 		if (wiphy->bands[i] == NULL)
4574 			continue;
4575 
4576 		for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
4577 			struct ieee80211_supported_band *band = wiphy->bands[i];
4578 			filled = wlan_fill_survey_result(survey, opfreq,
4579 				&hdd_ctx->chan_info[idx],
4580 				&band->channels[j]);
4581 		}
4582 	}
4583 	mutex_unlock(&hdd_ctx->chan_info_lock);
4584 
4585 	return filled;
4586 }
4587 
4588 /**
4589  * __wlan_hdd_cfg80211_dump_survey() - get survey related info
4590  * @wiphy: Pointer to wiphy
4591  * @dev: Pointer to network device
4592  * @idx: Index
4593  * @survey: Pointer to survey info
4594  *
4595  * Return: 0 for success, non-zero for failure
4596  */
4597 static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4598 					   struct net_device *dev,
4599 					   int idx, struct survey_info *survey)
4600 {
4601 	struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
4602 	struct hdd_context *hdd_ctx;
4603 	struct hdd_station_ctx *pHddStaCtx;
4604 	int status;
4605 	bool filled = false;
4606 
4607 	ENTER_DEV(dev);
4608 
4609 	hdd_debug("dump survey index: %d", idx);
4610 	if (idx > QDF_MAX_NUM_CHAN - 1)
4611 		return -EINVAL;
4612 
4613 	hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
4614 	status = wlan_hdd_validate_context(hdd_ctx);
4615 	if (0 != status)
4616 		return status;
4617 
4618 	if (hdd_ctx->chan_info == NULL) {
4619 		hdd_err("chan_info is NULL");
4620 		return -EINVAL;
4621 	}
4622 
4623 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
4624 		hdd_err("Command not allowed in FTM mode");
4625 		return -EINVAL;
4626 	}
4627 
4628 	pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
4629 
4630 	if (hdd_ctx->config->fEnableSNRMonitoring == 0)
4631 		return -ENONET;
4632 
4633 	if (pHddStaCtx->hdd_ReassocScenario) {
4634 		hdd_info("Roaming in progress, hence return");
4635 		return -ENONET;
4636 	}
4637 
4638 	filled = wlan_hdd_update_survey_info(wiphy, pAdapter, survey, idx);
4639 
4640 	if (!filled)
4641 		return -ENONET;
4642 	EXIT();
4643 	return 0;
4644 }
4645 
4646 /**
4647  * wlan_hdd_cfg80211_dump_survey() - get survey related info
4648  * @wiphy: Pointer to wiphy
4649  * @dev: Pointer to network device
4650  * @idx: Index
4651  * @survey: Pointer to survey info
4652  *
4653  * Return: 0 for success, non-zero for failure
4654  */
4655 int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4656 				  struct net_device *dev,
4657 				  int idx, struct survey_info *survey)
4658 {
4659 	int ret;
4660 
4661 	cds_ssr_protect(__func__);
4662 	ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
4663 	cds_ssr_unprotect(__func__);
4664 
4665 	return ret;
4666 }
4667 /**
4668  * hdd_init_ll_stats_ctx() - initialize link layer stats context
4669  *
4670  * Return: none
4671  */
4672 inline void hdd_init_ll_stats_ctx(void)
4673 {
4674 	spin_lock_init(&ll_stats_context.context_lock);
4675 	init_completion(&ll_stats_context.response_event);
4676 	ll_stats_context.request_bitmap = 0;
4677 }
4678 
4679 /**
4680  * hdd_display_hif_stats() - display hif stats
4681  *
4682  * Return: none
4683  *
4684  */
4685 void hdd_display_hif_stats(void)
4686 {
4687 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
4688 
4689 	if (!hif_ctx)
4690 		return;
4691 
4692 	hif_display_stats(hif_ctx);
4693 }
4694 
4695 /**
4696  * hdd_clear_hif_stats() - clear hif stats
4697  *
4698  * Return: none
4699  */
4700 void hdd_clear_hif_stats(void)
4701 {
4702 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
4703 
4704 	if (!hif_ctx)
4705 		return;
4706 	hif_clear_stats(hif_ctx);
4707 }
4708