xref: /wlan-dirver/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c (revision 9bab9cd8c24a02986ba0b33326aa381d69e5a346)
1 /*
2  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: wlan_hdd_stats.c
22  *
23  * WLAN Host Device Driver statistics related implementation
24  *
25  */
26 
27 #include "wlan_hdd_stats.h"
28 #include "sme_api.h"
29 #include "cds_sched.h"
30 #include "osif_sync.h"
31 #include "wlan_hdd_trace.h"
32 #include "wlan_hdd_lpass.h"
33 #include "hif.h"
34 #include <qca_vendor.h>
35 #include "wma_api.h"
36 #include "wlan_hdd_hostapd.h"
37 #include "wlan_osif_request_manager.h"
38 #include "wlan_hdd_debugfs_llstat.h"
39 #include "wlan_hdd_debugfs_mibstat.h"
40 #include "wlan_reg_services_api.h"
41 #include <wlan_cfg80211_mc_cp_stats.h>
42 #include "wlan_cp_stats_mc_ucfg_api.h"
43 #include "wlan_mlme_ucfg_api.h"
44 #include "wlan_mlme_ucfg_api.h"
45 #include "wlan_hdd_sta_info.h"
46 #include "cdp_txrx_misc.h"
47 #include "cdp_txrx_host_stats.h"
48 #include "wlan_hdd_object_manager.h"
49 #include "wlan_hdd_eht.h"
50 #include "wlan_dp_ucfg_api.h"
51 #include "wlan_cm_roam_ucfg_api.h"
52 #include <wlan_cp_stats_chipset_stats.h>
53 #include <wlan_cp_stats_ucfg_api.h>
54 #ifdef CNSS_GENL
55 #ifdef CONFIG_CNSS_OUT_OF_TREE
56 #include "cnss_nl.h"
57 #else
58 #include <net/cnss_nl.h>
59 #endif
60 #endif
61 #include "wlan_nan_api.h"
62 
63 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
64 #define HDD_INFO_SIGNAL                 STATION_INFO_SIGNAL
65 #define HDD_INFO_SIGNAL_AVG             STATION_INFO_SIGNAL_AVG
66 #define HDD_INFO_TX_PACKETS             STATION_INFO_TX_PACKETS
67 #define HDD_INFO_TX_RETRIES             STATION_INFO_TX_RETRIES
68 #define HDD_INFO_TX_FAILED              STATION_INFO_TX_FAILED
69 #define HDD_INFO_TX_BITRATE             STATION_INFO_TX_BITRATE
70 #define HDD_INFO_RX_BITRATE             STATION_INFO_RX_BITRATE
71 #define HDD_INFO_TX_BYTES               STATION_INFO_TX_BYTES
72 #define HDD_INFO_CHAIN_SIGNAL_AVG       STATION_INFO_CHAIN_SIGNAL_AVG
73 #define HDD_INFO_EXPECTED_THROUGHPUT    0
74 #define HDD_INFO_RX_BYTES               STATION_INFO_RX_BYTES
75 #define HDD_INFO_RX_PACKETS             STATION_INFO_RX_PACKETS
76 #define HDD_INFO_TX_BYTES64             0
77 #define HDD_INFO_RX_BYTES64             0
78 #define HDD_INFO_INACTIVE_TIME          0
79 #define HDD_INFO_CONNECTED_TIME         0
80 #define HDD_INFO_STA_FLAGS              0
81 #define HDD_INFO_RX_MPDUS               0
82 #define HDD_INFO_FCS_ERROR_COUNT        0
83 #else
84 #define HDD_INFO_SIGNAL                 BIT(NL80211_STA_INFO_SIGNAL)
85 #define HDD_INFO_SIGNAL_AVG             BIT(NL80211_STA_INFO_SIGNAL_AVG)
86 #define HDD_INFO_TX_PACKETS             BIT(NL80211_STA_INFO_TX_PACKETS)
87 #define HDD_INFO_TX_RETRIES             BIT(NL80211_STA_INFO_TX_RETRIES)
88 #define HDD_INFO_TX_FAILED              BIT(NL80211_STA_INFO_TX_FAILED)
89 #define HDD_INFO_TX_BITRATE             BIT(NL80211_STA_INFO_TX_BITRATE)
90 #define HDD_INFO_RX_BITRATE             BIT(NL80211_STA_INFO_RX_BITRATE)
91 #define HDD_INFO_TX_BYTES               BIT(NL80211_STA_INFO_TX_BYTES)
92 #define HDD_INFO_CHAIN_SIGNAL_AVG       BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
93 #define HDD_INFO_EXPECTED_THROUGHPUT  BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)
94 #define HDD_INFO_RX_BYTES               BIT(NL80211_STA_INFO_RX_BYTES)
95 #define HDD_INFO_RX_PACKETS             BIT(NL80211_STA_INFO_RX_PACKETS)
96 #define HDD_INFO_TX_BYTES64             BIT(NL80211_STA_INFO_TX_BYTES64)
97 #define HDD_INFO_RX_BYTES64             BIT(NL80211_STA_INFO_RX_BYTES64)
98 #define HDD_INFO_INACTIVE_TIME          BIT(NL80211_STA_INFO_INACTIVE_TIME)
99 #define HDD_INFO_CONNECTED_TIME         BIT(NL80211_STA_INFO_CONNECTED_TIME)
100 #define HDD_INFO_STA_FLAGS              BIT(NL80211_STA_INFO_STA_FLAGS)
101 #define HDD_INFO_RX_MPDUS             BIT_ULL(NL80211_STA_INFO_RX_MPDUS)
102 #define HDD_INFO_FCS_ERROR_COUNT      BIT_ULL(NL80211_STA_INFO_FCS_ERROR_COUNT)
103 #endif /* kernel version less than 4.0.0 && no_backport */
104 
105 #define HDD_LINK_STATS_MAX		5
106 #define HDD_MAX_ALLOWED_LL_STATS_FAILURE	5
107 
108 #define INVALID_PREAMBLE 0xFF
109 
110 #define MAX_RSSI_MCS_INDEX 14
111 
112 #define MAX_HT_MCS_INDEX 7
113 
114 /* 11B, 11G Rate table include Basic rate and Extended rate
115  * The IDX field is the rate index
116  * The HI field is the rate when RSSI is strong or being ignored
117  *  (in this case we report actual rate)
118  * The MID field is the rate when RSSI is moderate
119  * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
120  * The LO field is the rate when RSSI is low
121  *  (in this case we don't report rates, actual current rate used)
122  */
123 static const struct index_data_rate_type supported_data_rate[] = {
124 	/* IDX     HI  HM  LM LO (RSSI-based index */
125 	{2,   { 10,  10, 10, 0} },
126 	{4,   { 20,  20, 10, 0} },
127 	{11,  { 55,  20, 10, 0} },
128 	{12,  { 60,  55, 20, 0} },
129 	{18,  { 90,  55, 20, 0} },
130 	{22,  {110,  55, 20, 0} },
131 	{24,  {120,  90, 60, 0} },
132 	{36,  {180, 120, 60, 0} },
133 	{44,  {220, 180, 60, 0} },
134 	{48,  {240, 180, 90, 0} },
135 	{66,  {330, 180, 90, 0} },
136 	{72,  {360, 240, 90, 0} },
137 	{96,  {480, 240, 120, 0} },
138 	{108, {540, 240, 120, 0} }
139 };
140 /* MCS Based rate table HT MCS parameters with Nss = 1 */
141 static const struct index_data_rate_type supported_mcs_rate_nss1[] = {
142 /* MCS  L20   L40   S20  S40 */
143 	{0, {65, 135, 72, 150} },
144 	{1, {130, 270, 144, 300} },
145 	{2, {195, 405, 217, 450} },
146 	{3, {260, 540, 289, 600} },
147 	{4, {390, 810, 433, 900} },
148 	{5, {520, 1080, 578, 1200} },
149 	{6, {585, 1215, 650, 1350} },
150 	{7, {650, 1350, 722, 1500} }
151 };
152 
153 /* HT MCS parameters with Nss = 2 */
154 static const struct index_data_rate_type supported_mcs_rate_nss2[] = {
155 /* MCS  L20    L40   S20   S40 */
156 	{0, {130, 270, 144, 300} },
157 	{1, {260, 540, 289, 600} },
158 	{2, {390, 810, 433, 900} },
159 	{3, {520, 1080, 578, 1200} },
160 	{4, {780, 1620, 867, 1800} },
161 	{5, {1040, 2160, 1156, 2400} },
162 	{6, {1170, 2430, 1300, 2700} },
163 	{7, {1300, 2700, 1444, 3000} }
164 };
165 
166 /* MCS Based VHT rate table MCS parameters with Nss = 1*/
167 static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
168 /* MCS  L80    S80     L40   S40    L20   S40*/
169 	{0, {293, 325}, {135, 150}, {65, 72} },
170 	{1, {585, 650}, {270, 300}, {130, 144} },
171 	{2, {878, 975}, {405, 450}, {195, 217} },
172 	{3, {1170, 1300}, {540, 600}, {260, 289} },
173 	{4, {1755, 1950}, {810, 900}, {390, 433} },
174 	{5, {2340, 2600}, {1080, 1200}, {520, 578} },
175 	{6, {2633, 2925}, {1215, 1350}, {585, 650} },
176 	{7, {2925, 3250}, {1350, 1500}, {650, 722} },
177 	{8, {3510, 3900}, {1620, 1800}, {780, 867} },
178 	{9, {3900, 4333}, {1800, 2000}, {780, 867} },
179 	{10, {4388, 4875}, {2025, 2250}, {975, 1083} },
180 	{11, {4875, 5417}, {2250, 2500}, {1083, 1203} }
181 };
182 
183 /*MCS parameters with Nss = 2*/
184 static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
185 /* MCS  L80    S80     L40   S40    L20   S40*/
186 	{0, {585, 650}, {270, 300}, {130, 144} },
187 	{1, {1170, 1300}, {540, 600}, {260, 289} },
188 	{2, {1755, 1950}, {810, 900}, {390, 433} },
189 	{3, {2340, 2600}, {1080, 1200}, {520, 578} },
190 	{4, {3510, 3900}, {1620, 1800}, {780, 867} },
191 	{5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
192 	{6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
193 	{7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
194 	{8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
195 	{9, {7800, 8667}, {3600, 4000}, {1730, 1920} },
196 	{10, {8775, 9750}, {4050, 4500}, {1950, 2167} },
197 	{11, {9750, 10833}, {4500, 5000}, {2167, 2407} }
198 };
199 
200 /*array index points to MCS and array value points respective rssi*/
201 static int rssi_mcs_tbl[][MAX_RSSI_MCS_INDEX] = {
202 /*  MCS 0   1    2   3    4    5    6    7    8    9    10   11   12   13*/
203 	/* 20 */
204 	{-82, -79, -77, -74, -70, -66, -65, -64, -59, -57, -52, -48, -46, -42},
205 	/* 40 */
206 	{-79, -76, -74, -71, -67, -63, -62, -61, -56, -54, -49, -45, -43, -39},
207 	/* 80 */
208 	{-76, -73, -71, -68, -64, -60, -59, -58, -53, -51, -46, -42, -46, -36}
209 };
210 
211 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
212 static bool wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)
213 {
214 	if (he_mcs_12_13_map)
215 		return true;
216 	else
217 		return false;
218 }
219 #else
220 static bool wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)
221 {
222 	return false;
223 }
224 #endif
225 
226 static bool get_station_fw_request_needed = true;
227 
228 /*
229  * copy_station_stats_to_adapter() - Copy station stats to adapter
230  * @link_info: Pointer to link_info in adapter
231  * @stats: Pointer to the station stats event
232  *
233  * Return: 0 if success, non-zero for failure
234  */
235 static int copy_station_stats_to_adapter(struct wlan_hdd_link_info *link_info,
236 					 struct stats_event *stats)
237 {
238 	int ret = 0;
239 	struct wlan_mlme_nss_chains *dynamic_cfg;
240 	uint32_t tx_nss, rx_nss;
241 	struct wlan_objmgr_vdev *vdev;
242 	uint16_t he_mcs_12_13_map;
243 	bool is_he_mcs_12_13_supported;
244 	struct hdd_stats *hdd_stats;
245 	struct hdd_adapter *adapter = link_info->adapter;
246 
247 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
248 	if (!vdev)
249 		return -EINVAL;
250 
251 	hdd_stats = &link_info->hdd_stats;
252 	/* save summary stats to legacy location */
253 	qdf_mem_copy(hdd_stats->summary_stat.retry_cnt,
254 		     stats->vdev_summary_stats[0].stats.retry_cnt,
255 		     sizeof(hdd_stats->summary_stat.retry_cnt));
256 	qdf_mem_copy(hdd_stats->summary_stat.multiple_retry_cnt,
257 		     stats->vdev_summary_stats[0].stats.multiple_retry_cnt,
258 		     sizeof(hdd_stats->summary_stat.multiple_retry_cnt));
259 	qdf_mem_copy(hdd_stats->summary_stat.tx_frm_cnt,
260 		     stats->vdev_summary_stats[0].stats.tx_frm_cnt,
261 		     sizeof(hdd_stats->summary_stat.tx_frm_cnt));
262 	qdf_mem_copy(hdd_stats->summary_stat.fail_cnt,
263 		     stats->vdev_summary_stats[0].stats.fail_cnt,
264 		     sizeof(hdd_stats->summary_stat.fail_cnt));
265 	hdd_stats->summary_stat.snr = stats->vdev_summary_stats[0].stats.snr;
266 	hdd_stats->summary_stat.rssi = stats->vdev_summary_stats[0].stats.rssi;
267 	hdd_stats->summary_stat.rx_frm_cnt =
268 			stats->vdev_summary_stats[0].stats.rx_frm_cnt;
269 	hdd_stats->summary_stat.frm_dup_cnt =
270 			stats->vdev_summary_stats[0].stats.frm_dup_cnt;
271 	hdd_stats->summary_stat.rts_fail_cnt =
272 			stats->vdev_summary_stats[0].stats.rts_fail_cnt;
273 	hdd_stats->summary_stat.ack_fail_cnt =
274 			stats->vdev_summary_stats[0].stats.ack_fail_cnt;
275 	hdd_stats->summary_stat.rts_succ_cnt =
276 			stats->vdev_summary_stats[0].stats.rts_succ_cnt;
277 	hdd_stats->summary_stat.rx_discard_cnt =
278 			stats->vdev_summary_stats[0].stats.rx_discard_cnt;
279 	hdd_stats->summary_stat.rx_error_cnt =
280 			stats->vdev_summary_stats[0].stats.rx_error_cnt;
281 	hdd_stats->peer_stats.rx_count = stats->peer_adv_stats->rx_count;
282 	hdd_stats->peer_stats.rx_bytes = stats->peer_adv_stats->rx_bytes;
283 	hdd_stats->peer_stats.fcs_count = stats->peer_adv_stats->fcs_count;
284 	adapter->tx_power.tx_pwr = stats->pdev_stats->max_pwr;
285 	adapter->tx_power.tx_pwr_cached_timestamp =
286 			qdf_system_ticks_to_msecs(qdf_system_ticks());
287 	/* Copy vdev status info sent by FW */
288 	if (stats->vdev_extd_stats)
289 		link_info->is_mlo_vdev_active =
290 			stats->vdev_extd_stats[0].is_mlo_vdev_active;
291 
292 	dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
293 	if (!dynamic_cfg) {
294 		hdd_err("nss chain dynamic config NULL");
295 		ret = -EINVAL;
296 		goto out;
297 	}
298 
299 	switch (hdd_conn_get_connected_band(link_info)) {
300 	case BAND_2G:
301 		tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ];
302 		rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ];
303 		break;
304 	case BAND_5G:
305 		tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ];
306 		rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ];
307 		break;
308 	default:
309 		tx_nss = wlan_vdev_mlme_get_nss(vdev);
310 		rx_nss = wlan_vdev_mlme_get_nss(vdev);
311 	}
312 
313 	/* Intersection of self and AP's NSS capability */
314 	if (tx_nss > wlan_vdev_mlme_get_nss(vdev))
315 		tx_nss = wlan_vdev_mlme_get_nss(vdev);
316 
317 	if (rx_nss > wlan_vdev_mlme_get_nss(vdev))
318 		rx_nss = wlan_vdev_mlme_get_nss(vdev);
319 
320 	/* save class a stats to legacy location */
321 	hdd_stats->class_a_stat.tx_nss = tx_nss;
322 	hdd_stats->class_a_stat.rx_nss = rx_nss;
323 	hdd_stats->class_a_stat.tx_rate = stats->tx_rate;
324 	hdd_stats->class_a_stat.rx_rate = stats->rx_rate;
325 	hdd_stats->class_a_stat.tx_rx_rate_flags = stats->tx_rate_flags;
326 
327 	he_mcs_12_13_map = wlan_vdev_mlme_get_he_mcs_12_13_map(vdev);
328 	is_he_mcs_12_13_supported =
329 			wlan_hdd_is_he_mcs_12_13_supported(he_mcs_12_13_map);
330 	hdd_stats->class_a_stat.tx_mcs_index =
331 		sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags,
332 				is_he_mcs_12_13_supported,
333 				&hdd_stats->class_a_stat.tx_nss,
334 				&hdd_stats->class_a_stat.tx_dcm,
335 				&hdd_stats->class_a_stat.tx_gi,
336 				&hdd_stats->class_a_stat.tx_mcs_rate_flags);
337 	hdd_stats->class_a_stat.rx_mcs_index =
338 		sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags,
339 				is_he_mcs_12_13_supported,
340 				&hdd_stats->class_a_stat.rx_nss,
341 				&hdd_stats->class_a_stat.rx_dcm,
342 				&hdd_stats->class_a_stat.rx_gi,
343 				&hdd_stats->class_a_stat.rx_mcs_rate_flags);
344 
345 	/* save per chain rssi to legacy location */
346 	qdf_mem_copy(hdd_stats->per_chain_rssi_stats.rssi,
347 		     stats->vdev_chain_rssi[0].chain_rssi,
348 		     sizeof(stats->vdev_chain_rssi[0].chain_rssi));
349 	hdd_stats->bcn_protect_stats = stats->bcn_protect_stats;
350 out:
351 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
352 	return ret;
353 }
354 
355 #ifdef WLAN_FEATURE_BIG_DATA_STATS
356 /*
357  * copy_station_big_data_stats_to_adapter() - Copy big data stats to adapter
358  * @link_info: Link info pointer in HDD adapter.
359  * @stats: Pointer to the big data stats event
360  *
361  * Return: 0 if success, non-zero for failure
362  */
363 static void
364 copy_station_big_data_stats_to_adapter(struct wlan_hdd_link_info *link_info,
365 				       struct big_data_stats_event *stats)
366 {
367 	struct big_data_stats_event *big_data_stats =
368 						&link_info->big_data_stats;
369 
370 	big_data_stats->vdev_id = stats->vdev_id;
371 	big_data_stats->tsf_out_of_sync = stats->tsf_out_of_sync;
372 	big_data_stats->ani_level = stats->ani_level;
373 	big_data_stats->last_data_tx_pwr = stats->last_data_tx_pwr;
374 	big_data_stats->target_power_dsss = stats->target_power_dsss;
375 	big_data_stats->target_power_ofdm = stats->target_power_ofdm;
376 	big_data_stats->last_tx_data_rix = stats->last_tx_data_rix;
377 	big_data_stats->last_tx_data_rate_kbps = stats->last_tx_data_rate_kbps;
378 }
379 #endif
380 
381 #ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
382 static void
383 hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter)
384 {
385 	adapter->sta_stats_cached_timestamp =
386 				qdf_system_ticks_to_msecs(qdf_system_ticks());
387 }
388 #else
389 static void
390 hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter)
391 {
392 }
393 #endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
394 
395 #ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI
396 /**
397  * wlan_hdd_qmi_get_sync_resume() - Get operation to trigger RTPM
398  * sync resume without WoW exit
399  *
400  * call qmi_get before sending qmi, and do qmi_put after all the
401  * qmi response rececived from fw. so this request wlan host to
402  * wait for the last qmi response, if it doesn't wait, qmi put
403  * which cause MHI enter M3(suspend) before all the qmi response,
404  * and MHI will trigger a RTPM resume, this violated design of by
405  * sending cmd by qmi without wow resume.
406  *
407  * Returns: 0 for success, non-zero for failure
408  */
409 int wlan_hdd_qmi_get_sync_resume(void)
410 {
411 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
412 	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
413 
414 	if (wlan_hdd_validate_context(hdd_ctx))
415 		return -EINVAL;
416 
417 	if (!hdd_ctx->config->is_qmi_stats_enabled) {
418 		hdd_debug("periodic stats over qmi is disabled");
419 		return 0;
420 	}
421 
422 	if (!qdf_ctx) {
423 		hdd_err("qdf_ctx is null");
424 		return -EINVAL;
425 	}
426 
427 	return pld_qmi_send_get(qdf_ctx->dev);
428 }
429 
430 /**
431  * wlan_hdd_qmi_put_suspend() - Put operation to trigger RTPM suspend
432  * without WoW entry
433  *
434  * Returns: 0 for success, non-zero for failure
435  */
436 int wlan_hdd_qmi_put_suspend(void)
437 {
438 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
439 	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
440 
441 	if (wlan_hdd_validate_context(hdd_ctx))
442 		return -EINVAL;
443 
444 	if (!hdd_ctx->config->is_qmi_stats_enabled) {
445 		hdd_debug("periodic stats over qmi is disabled");
446 		return 0;
447 	}
448 
449 	if (!qdf_ctx) {
450 		hdd_err("qdf_ctx is null");
451 		return -EINVAL;
452 	}
453 
454 	return pld_qmi_send_put(qdf_ctx->dev);
455 }
456 #else
457 int wlan_hdd_qmi_get_sync_resume(void)
458 {
459 	return 0;
460 }
461 
462 int wlan_hdd_qmi_put_suspend(void)
463 {
464 	return 0;
465 }
466 #endif /* end if of WLAN_FEATURE_WMI_SEND_RECV_QMI */
467 
468 /*
469  * wlan_hdd_is_mlo_connection() - Check if connection is legacy or mlo
470  * @link_info: Link info pointer in HDD adapter
471  *
472  * Return: True if MLO connection, else False
473  */
474 static bool wlan_hdd_is_mlo_connection(struct wlan_hdd_link_info *link_info)
475 {
476 	struct wlan_objmgr_vdev *vdev;
477 	bool ret = false;
478 
479 	if (!link_info) {
480 		hdd_err("Invalid link_info");
481 		return ret;
482 	}
483 
484 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
485 	if (!vdev) {
486 		hdd_err("invalid vdev");
487 		return ret;
488 	}
489 
490 	if (wlan_vdev_mlme_is_mlo_vdev(vdev))
491 		ret = true;
492 
493 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
494 	return ret;
495 }
496 
497 static struct wlan_hdd_link_info *
498 hdd_get_link_info_by_bssid(struct hdd_context *hdd_ctx, const uint8_t *bssid)
499 {
500 	struct hdd_adapter *adapter, *next_adapter = NULL;
501 	struct hdd_station_ctx *sta_ctx;
502 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_BSSID;
503 	struct wlan_hdd_link_info *link_info;
504 
505 	if (qdf_is_macaddr_zero((struct qdf_mac_addr *)bssid))
506 		return NULL;
507 
508 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
509 					   dbgid) {
510 		hdd_adapter_for_each_link_info(adapter, link_info) {
511 			sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
512 			if (qdf_is_macaddr_equal((struct qdf_mac_addr *)bssid,
513 						 &sta_ctx->conn_info.bssid)) {
514 				hdd_adapter_dev_put_debug(adapter, dbgid);
515 				if (next_adapter)
516 					hdd_adapter_dev_put_debug(next_adapter,
517 								  dbgid);
518 				return link_info;
519 			}
520 		}
521 		hdd_adapter_dev_put_debug(adapter, dbgid);
522 	}
523 	return NULL;
524 }
525 
526 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
527 #define WLAN_INVALID_RSSI_VALUE -128
528 /**
529  * wlan_hdd_is_per_link_stats_supported - Check if FW supports per link stats
530  * @hdd_ctx: Pointer to hdd context
531  *
532  * Return: true if FW supports, else False
533  */
534 static bool
535 wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
536 {
537 	if (hdd_ctx->is_mlo_per_link_stats_supported)
538 		return true;
539 
540 	hdd_debug("mlo per link stats is not supported by FW");
541 	return false;
542 }
543 
544 /**
545  * wlan_hdd_get_bss_peer_mld_mac() - get bss peer mld mac address
546  * @link_info: Link info pointer in HDD adapter
547  * @mld_mac: pointer to mld mac address
548  *
549  * Return: QDF_STATUS
550  */
551 static QDF_STATUS
552 wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
553 			      struct qdf_mac_addr *mld_mac)
554 {
555 	struct wlan_objmgr_vdev *vdev;
556 	QDF_STATUS status;
557 
558 	vdev = hdd_objmgr_get_vdev_by_user(link_info,
559 					   WLAN_OSIF_STATS_ID);
560 	if (!vdev)
561 		return QDF_STATUS_E_INVAL;
562 
563 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
564 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
565 		return QDF_STATUS_E_INVAL;
566 	}
567 
568 	status = wlan_vdev_get_bss_peer_mld_mac(vdev, mld_mac);
569 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
570 	return status;
571 }
572 
573 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
574 static bool
575 wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
576 {
577 	struct wlan_objmgr_vdev *vdev;
578 	bool ret = false;
579 
580 	if (!link_info) {
581 		hdd_err_rl("Invalid link info");
582 		return ret;
583 	}
584 
585 	if (!wlan_hdd_is_mlo_connection(link_info))
586 		return ret;
587 
588 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
589 	if (!vdev) {
590 		hdd_err("invalid vdev");
591 		return ret;
592 	}
593 
594 	ret = mlo_mgr_is_link_switch_in_progress(vdev);
595 
596 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
597 	return ret;
598 }
599 #else
600 static inline bool
601 wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
602 {
603 	return false;
604 }
605 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
606 
607 /**
608  * wlan_hdd_copy_sinfo_to_link_info() - Copy sinfo to link_info
609  * @link_info: Pointer to the hdd link info
610  * @sinfo: Pointer to kernel station info struct
611  *
612  * Return: none
613  */
614 static void
615 wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info,
616 				 struct station_info *sinfo)
617 {
618 	struct wlan_hdd_station_stats_info *hdd_sinfo;
619 	struct hdd_station_ctx *sta_ctx;
620 	uint8_t i, *link_mac;
621 
622 	if (!wlan_hdd_is_mlo_connection(link_info))
623 		return;
624 
625 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
626 
627 	hdd_sinfo = &link_info->hdd_sinfo;
628 
629 	hdd_sinfo->signal = sinfo->signal;
630 	hdd_sinfo->signal_avg = sinfo->signal_avg;
631 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
632 		hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i];
633 
634 	qdf_mem_copy(&hdd_sinfo->txrate,
635 		     &sinfo->txrate, sizeof(sinfo->txrate));
636 
637 	qdf_mem_copy(&hdd_sinfo->rxrate,
638 		     &sinfo->rxrate, sizeof(sinfo->rxrate));
639 	hdd_sinfo->rx_bytes = sinfo->rx_bytes;
640 	hdd_sinfo->tx_bytes = sinfo->tx_bytes;
641 	hdd_sinfo->rx_packets = sinfo->rx_packets;
642 	hdd_sinfo->tx_packets = sinfo->tx_packets;
643 	hdd_sinfo->tx_retries = sinfo->tx_retries;
644 	hdd_sinfo->tx_failed = sinfo->tx_failed;
645 	hdd_sinfo->rx_mpdu_count = sinfo->rx_mpdu_count;
646 	hdd_sinfo->fcs_err_count = sinfo->fcs_err_count;
647 
648 	link_mac = sta_ctx->conn_info.bssid.bytes;
649 	hdd_nofl_debug("copied sinfo for " QDF_MAC_ADDR_FMT " into link_info",
650 		       QDF_MAC_ADDR_REF(link_mac));
651 }
652 
653 /**
654  * wlan_hdd_copy_hdd_stats_to_sinfo() - Copy hdd station stats info to sinfo
655  * @sinfo: Pointer to kernel station info struct
656  * @hdd_sinfo: Pointer to the hdd station stats info struct
657  *
658  * Return: none
659  */
660 static void
661 wlan_hdd_copy_hdd_stats_to_sinfo(struct station_info *sinfo,
662 				 struct wlan_hdd_station_stats_info *hdd_sinfo)
663 {
664 	uint8_t i;
665 
666 	sinfo->signal = hdd_sinfo->signal;
667 	sinfo->signal_avg = hdd_sinfo->signal_avg;
668 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
669 		sinfo->chain_signal_avg[i] = hdd_sinfo->chain_signal_avg[i];
670 
671 	if (!hdd_sinfo->signal) {
672 		sinfo->signal = WLAN_INVALID_RSSI_VALUE;
673 		sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
674 		for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
675 			sinfo->chain_signal_avg[i] = WLAN_INVALID_RSSI_VALUE;
676 	}
677 
678 	qdf_mem_copy(&sinfo->txrate,
679 		     &hdd_sinfo->txrate, sizeof(sinfo->txrate));
680 
681 	qdf_mem_copy(&sinfo->rxrate,
682 		     &hdd_sinfo->rxrate, sizeof(sinfo->rxrate));
683 	sinfo->rx_bytes = hdd_sinfo->rx_bytes;
684 	sinfo->tx_bytes = hdd_sinfo->tx_bytes;
685 	sinfo->rx_packets = hdd_sinfo->rx_packets;
686 	sinfo->tx_packets = hdd_sinfo->tx_packets;
687 	sinfo->tx_retries = hdd_sinfo->tx_retries;
688 	sinfo->tx_failed = hdd_sinfo->tx_failed;
689 	sinfo->rx_mpdu_count = hdd_sinfo->rx_mpdu_count;
690 	sinfo->fcs_err_count = hdd_sinfo->fcs_err_count;
691 }
692 
693 /**
694  * wlan_hdd_update_sinfo() - Function to update station info structure
695  * @sinfo: kernel station_info to populate
696  * @link_info: Pointer to the hdd link info
697  *
698  * Return: None
699  */
700 static void wlan_hdd_update_sinfo(struct station_info *sinfo,
701 				  struct wlan_hdd_link_info *link_info)
702 {
703 	uint8_t i;
704 
705 	if (!link_info) {
706 		hdd_err("Invalid link_info");
707 		return;
708 	}
709 
710 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &link_info->hdd_sinfo);
711 
712 	if (link_info->vdev_id == WLAN_INVALID_VDEV_ID) {
713 		sinfo->signal = WLAN_INVALID_RSSI_VALUE;
714 		sinfo->signal_avg = WLAN_INVALID_RSSI_VALUE;
715 		for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
716 			sinfo->chain_signal_avg[i] = WLAN_INVALID_RSSI_VALUE;
717 	}
718 
719 	sinfo->filled |= HDD_INFO_SIGNAL | HDD_INFO_SIGNAL_AVG |
720 			HDD_INFO_CHAIN_SIGNAL_AVG | HDD_INFO_TX_PACKETS |
721 			HDD_INFO_TX_RETRIES | HDD_INFO_TX_FAILED |
722 			HDD_INFO_TX_BITRATE | HDD_INFO_RX_BITRATE |
723 			HDD_INFO_TX_BYTES | HDD_INFO_RX_BYTES |
724 			HDD_INFO_RX_PACKETS | HDD_INFO_FCS_ERROR_COUNT |
725 			HDD_INFO_RX_MPDUS;
726 }
727 
728 static void
729 wlan_hdd_get_mlo_links_count(struct hdd_adapter *adapter, uint32_t *count)
730 {
731 	struct wlan_hdd_link_info *link_info;
732 	struct hdd_station_ctx *sta_ctx;
733 	u32 num_links = 0;
734 
735 	hdd_adapter_for_each_link_info(adapter, link_info) {
736 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
737 		if (sta_ctx->conn_info.ieee_link_id != WLAN_INVALID_LINK_ID)
738 			num_links++;
739 	}
740 
741 	*count = num_links;
742 }
743 
744 #else
745 static inline bool
746 wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
747 {
748 	return false;
749 }
750 
751 static inline QDF_STATUS
752 wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
753 			      struct qdf_mac_addr *mld_mac)
754 {
755 	return QDF_STATUS_E_FAILURE;
756 }
757 
758 static inline bool
759 wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
760 {
761 	return false;
762 }
763 
764 static inline void
765 wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info,
766 				 struct station_info *sinfo)
767 {
768 }
769 
770 static inline void
771 wlan_hdd_update_sinfo(struct station_info *sinfo,
772 		      struct wlan_hdd_link_info *link_info)
773 {
774 }
775 
776 static inline void
777 wlan_hdd_get_mlo_links_count(struct hdd_adapter *adapter, uint32_t *count)
778 {
779 }
780 #endif
781 
782 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
783 
784 /**
785  * struct hdd_ll_stats - buffered hdd link layer stats
786  * @ll_stats_node: pointer to next stats buffered in scheduler thread context
787  * @result_param_id: Received link layer stats ID
788  * @result: received stats from FW
789  * @more_data: if more stats are pending
790  * @stats_nradio_npeer: union of counts
791  * @stats_nradio_npeer.no_of_radios: no of radios
792  * @stats_nradio_npeer.no_of_peers: no of peers
793  */
794 struct hdd_ll_stats {
795 	qdf_list_node_t ll_stats_node;
796 	u32 result_param_id;
797 	void *result;
798 	u32 more_data;
799 	union {
800 		u32 no_of_radios;
801 		u32 no_of_peers;
802 	} stats_nradio_npeer;
803 };
804 
805 /**
806  * struct hdd_ll_stats_priv - hdd link layer stats private
807  * @ll_stats_q: head to different link layer stats received in scheduler
808  *            thread context
809  * @request_id: userspace-assigned link layer stats request id
810  * @request_bitmap: userspace-assigned link layer stats request bitmap
811  * @ll_stats_lock: Lock to serially access request_bitmap
812  * @vdev_id: id of vdev handle
813  * @is_mlo_req: is the request for mlo link layer stats
814  * @mlo_vdev_id_bitmap: bitmap of all ml vdevs
815  */
816 struct hdd_ll_stats_priv {
817 	qdf_list_t ll_stats_q;
818 	uint32_t request_id;
819 	uint32_t request_bitmap;
820 	qdf_spinlock_t ll_stats_lock;
821 	uint8_t vdev_id;
822 	bool is_mlo_req;
823 	uint32_t mlo_vdev_id_bitmap;
824 };
825 
826 /*
827  * Used to allocate the size of 4096 for the link layer stats.
828  * The size of 4096 is considered assuming that all data per
829  * respective event fit with in the limit.Please take a call
830  * on the limit based on the data requirements on link layer
831  * statistics.
832  */
833 #define LL_STATS_EVENT_BUF_SIZE 4096
834 
835 /**
836  * put_wifi_rate_stat() - put wifi rate stats
837  * @stats: Pointer to stats context
838  * @vendor_event: Pointer to vendor event
839  *
840  * Return: bool
841  */
842 static bool put_wifi_rate_stat(struct wifi_rate_stat *stats,
843 			       struct sk_buff *vendor_event)
844 {
845 	if (nla_put_u8(vendor_event,
846 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
847 		       stats->rate.preamble) ||
848 	    nla_put_u8(vendor_event,
849 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
850 		       stats->rate.nss) ||
851 	    nla_put_u8(vendor_event,
852 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
853 		       stats->rate.bw) ||
854 	    nla_put_u8(vendor_event,
855 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
856 		       stats->rate.rate_or_mcs_index) ||
857 	    nla_put_u32(vendor_event,
858 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
859 			stats->rate.bitrate) ||
860 	    nla_put_u32(vendor_event,
861 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
862 			stats->tx_mpdu) ||
863 	    nla_put_u32(vendor_event,
864 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
865 			stats->rx_mpdu) ||
866 	    nla_put_u32(vendor_event,
867 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
868 			stats->mpdu_lost) ||
869 	    nla_put_u32(vendor_event,
870 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
871 			stats->retries) ||
872 	    nla_put_u32(vendor_event,
873 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
874 			stats->retries_short) ||
875 	    nla_put_u32(vendor_event,
876 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
877 			stats->retries_long)) {
878 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
879 		return false;
880 	}
881 
882 	return true;
883 }
884 
885 /**
886  * put_wifi_peer_rates() - put wifi peer rate info
887  * @stats: Pointer to stats context
888  * @vendor_event: Pointer to vendor event
889  *
890  * Return: bool
891  */
892 static bool put_wifi_peer_rates(struct wifi_peer_info *stats,
893 				struct sk_buff *vendor_event)
894 {
895 	uint32_t i;
896 	struct wifi_rate_stat *rate_stat;
897 	int nest_id;
898 	struct nlattr *info;
899 	struct nlattr *rates;
900 
901 	/* no rates is ok */
902 	if (!stats->num_rate)
903 		return true;
904 
905 	nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO;
906 	info = nla_nest_start(vendor_event, nest_id);
907 	if (!info)
908 		return false;
909 
910 	for (i = 0; i < stats->num_rate; i++) {
911 		rates = nla_nest_start(vendor_event, i);
912 		if (!rates)
913 			return false;
914 		rate_stat = &stats->rate_stats[i];
915 		if (!put_wifi_rate_stat(rate_stat, vendor_event)) {
916 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
917 			return false;
918 		}
919 		nla_nest_end(vendor_event, rates);
920 	}
921 	nla_nest_end(vendor_event, info);
922 
923 	return true;
924 }
925 
926 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
927 /**
928  * wlan_hdd_put_mlo_link_iface_info() - Send per mlo link info to framework
929  * @info: Pointer to wlan_hdd_mlo_iface_stats_info struct
930  * @skb: Pointer to data buffer
931  *
932  * Return: True on success, False on failure
933  */
934 static bool
935 wlan_hdd_put_mlo_link_iface_info(struct wlan_hdd_mlo_iface_stats_info *info,
936 				 struct sk_buff *skb)
937 {
938 	if (nla_put_u8(skb,
939 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID,
940 		       info->link_id) ||
941 	    nla_put_u32(skb,
942 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
943 			info->radio_id) ||
944 	    nla_put_u32(skb,
945 			QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
946 			info->freq)) {
947 		hdd_err("wlan_hdd_put_mlo_link_iface_info failed");
948 		return false;
949 	}
950 
951 	return true;
952 }
953 
954 /**
955  * wlan_hdd_get_connected_link_info() - Get connected links' id and frequency
956  * @link_info: Link info pointerin adapter
957  * @info: Pointer to wlan_hdd_mlo_iface_stats_info struct
958  *
959  * Return: True on success, False on failure
960  */
961 static void
962 wlan_hdd_get_connected_link_info(struct wlan_hdd_link_info *link_info,
963 				 struct wlan_hdd_mlo_iface_stats_info *info)
964 {
965 	struct hdd_station_ctx *sta_ctx;
966 
967 	if (!link_info) {
968 		hdd_err("Invalid link_info");
969 		info->link_id = WLAN_INVALID_LINK_ID;
970 		return;
971 	}
972 
973 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
974 	info->link_id = sta_ctx->conn_info.ieee_link_id;
975 	info->freq = sta_ctx->conn_info.chan_freq;
976 }
977 #endif
978 
979 /**
980  * put_wifi_peer_info() - put wifi peer info
981  * @stats: Pointer to stats context
982  * @vendor_event: Pointer to vendor event
983  *
984  * Return: bool
985  */
986 static bool put_wifi_peer_info(struct wifi_peer_info *stats,
987 			       struct sk_buff *vendor_event)
988 {
989 	if (nla_put_u32(vendor_event,
990 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
991 			wmi_to_sir_peer_type(stats->type)) ||
992 	    nla_put(vendor_event,
993 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
994 		       QDF_MAC_ADDR_SIZE, &stats->peer_macaddr.bytes[0]) ||
995 	    nla_put_u32(vendor_event,
996 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
997 			stats->capabilities) ||
998 	    nla_put_u32(vendor_event,
999 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
1000 			stats->num_rate)) {
1001 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1002 		return false;
1003 	}
1004 
1005 	return put_wifi_peer_rates(stats, vendor_event);
1006 }
1007 
1008 /**
1009  * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
1010  * @stats: Pointer to stats context
1011  * @vendor_event: Pointer to vendor event
1012  *
1013  * Return: bool
1014  */
1015 static bool put_wifi_wmm_ac_stat(wmi_wmm_ac_stats *stats,
1016 				 struct sk_buff *vendor_event)
1017 {
1018 	if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
1019 			stats->ac_type) ||
1020 	    nla_put_u32(vendor_event,
1021 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
1022 			stats->tx_mpdu) ||
1023 	    nla_put_u32(vendor_event,
1024 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
1025 			stats->rx_mpdu) ||
1026 	    nla_put_u32(vendor_event,
1027 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
1028 			stats->tx_mcast) ||
1029 	    nla_put_u32(vendor_event,
1030 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
1031 			stats->rx_mcast) ||
1032 	    nla_put_u32(vendor_event,
1033 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
1034 			stats->rx_ampdu) ||
1035 	    nla_put_u32(vendor_event,
1036 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
1037 			stats->tx_ampdu) ||
1038 	    nla_put_u32(vendor_event,
1039 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
1040 			stats->mpdu_lost) ||
1041 	    nla_put_u32(vendor_event,
1042 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
1043 			stats->retries) ||
1044 	    nla_put_u32(vendor_event,
1045 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
1046 			stats->retries_short) ||
1047 	    nla_put_u32(vendor_event,
1048 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
1049 			stats->retries_long) ||
1050 	    nla_put_u32(vendor_event,
1051 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
1052 			stats->contention_time_min) ||
1053 	    nla_put_u32(vendor_event,
1054 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
1055 			stats->contention_time_max) ||
1056 	    nla_put_u32(vendor_event,
1057 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
1058 			stats->contention_time_avg) ||
1059 	    nla_put_u32(vendor_event,
1060 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
1061 			stats->contention_num_samples)) {
1062 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1063 		return false;
1064 	}
1065 
1066 	return true;
1067 }
1068 
1069 /**
1070  * put_wifi_interface_info() - put wifi interface info
1071  * @stats: Pointer to stats context
1072  * @vendor_event: Pointer to vendor event
1073  *
1074  * Return: bool
1075  */
1076 static bool put_wifi_interface_info(struct wifi_interface_info *stats,
1077 				    struct sk_buff *vendor_event)
1078 {
1079 	if (nla_put_u32(vendor_event,
1080 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
1081 			stats->mode) ||
1082 	    nla_put(vendor_event,
1083 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
1084 		    QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
1085 	    nla_put_u32(vendor_event,
1086 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
1087 			stats->state) ||
1088 	    nla_put_u32(vendor_event,
1089 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
1090 			stats->roaming) ||
1091 	    nla_put_u32(vendor_event,
1092 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
1093 			stats->capabilities) ||
1094 	    nla_put(vendor_event,
1095 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
1096 		    strlen(stats->ssid), stats->ssid) ||
1097 	    nla_put(vendor_event,
1098 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
1099 		    QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
1100 	    nla_put(vendor_event,
1101 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
1102 		    REG_ALPHA2_LEN + 1, stats->apCountryStr) ||
1103 	    nla_put(vendor_event,
1104 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
1105 		    REG_ALPHA2_LEN + 1, stats->countryStr) ||
1106 	    nla_put_u8(vendor_event,
1107 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_TS_DUTY_CYCLE,
1108 		       stats->time_slice_duty_cycle)) {
1109 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1110 		return false;
1111 	}
1112 
1113 	return true;
1114 }
1115 
1116 /**
1117  * put_wifi_iface_stats() - put wifi interface stats
1118  * @if_stat: Pointer to interface stats context
1119  * @num_peers: Number of peers
1120  * @vendor_event: Pointer to vendor event
1121  *
1122  * Return: bool
1123  */
1124 static bool put_wifi_iface_stats(struct wifi_interface_stats *if_stat,
1125 				 u32 num_peers, struct sk_buff *vendor_event)
1126 {
1127 	int i = 0;
1128 	struct nlattr *wmm_info;
1129 	struct nlattr *wmm_stats;
1130 	u64 average_tsf_offset;
1131 	wmi_iface_link_stats *link_stats = &if_stat->link_stats;
1132 
1133 	if (!put_wifi_interface_info(&if_stat->info, vendor_event)) {
1134 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1135 		return false;
1136 
1137 	}
1138 
1139 	average_tsf_offset =  link_stats->avg_bcn_spread_offset_high;
1140 	average_tsf_offset =  (average_tsf_offset << 32) |
1141 		link_stats->avg_bcn_spread_offset_low;
1142 
1143 	if (nla_put_u32(vendor_event,
1144 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
1145 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_IFACE) ||
1146 	    nla_put_u32(vendor_event,
1147 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
1148 			num_peers) ||
1149 	    nla_put_u32(vendor_event,
1150 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
1151 			link_stats->beacon_rx) ||
1152 	    nla_put_u32(vendor_event,
1153 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
1154 			link_stats->mgmt_rx) ||
1155 	    nla_put_u32(vendor_event,
1156 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
1157 			link_stats->mgmt_action_rx) ||
1158 	    nla_put_u32(vendor_event,
1159 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
1160 			link_stats->mgmt_action_tx) ||
1161 	    nla_put_u32(vendor_event,
1162 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
1163 			link_stats->rssi_mgmt) ||
1164 	    nla_put_u32(vendor_event,
1165 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
1166 			link_stats->rssi_data) ||
1167 	    nla_put_u32(vendor_event,
1168 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
1169 			link_stats->rssi_ack) ||
1170 	    nla_put_u32(vendor_event,
1171 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
1172 			link_stats->is_leaky_ap) ||
1173 	    nla_put_u32(vendor_event,
1174 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
1175 			link_stats->avg_rx_frms_leaked) ||
1176 	    nla_put_u32(vendor_event,
1177 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
1178 			link_stats->rx_leak_window) ||
1179 	    nla_put_s32(vendor_event,
1180 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NF_CAL_VAL,
1181 			link_stats->nf_cal_val) ||
1182 	    hdd_wlan_nla_put_u64(vendor_event,
1183 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
1184 			average_tsf_offset) ||
1185 	    nla_put_u32(vendor_event,
1186 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT,
1187 			if_stat->rts_succ_cnt) ||
1188 	    nla_put_u32(vendor_event,
1189 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT,
1190 			if_stat->rts_fail_cnt) ||
1191 	    nla_put_u32(vendor_event,
1192 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT,
1193 			if_stat->ppdu_succ_cnt) ||
1194 	    nla_put_u32(vendor_event,
1195 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT,
1196 			if_stat->ppdu_fail_cnt)) {
1197 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1198 		return false;
1199 	}
1200 
1201 	wmm_info = nla_nest_start(vendor_event,
1202 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
1203 	if (!wmm_info)
1204 		return false;
1205 
1206 	for (i = 0; i < WIFI_AC_MAX; i++) {
1207 		wmm_stats = nla_nest_start(vendor_event, i);
1208 		if (!wmm_stats)
1209 			return false;
1210 
1211 		if (!put_wifi_wmm_ac_stat(&if_stat->ac_stats[i],
1212 					  vendor_event)) {
1213 			hdd_err("put_wifi_wmm_ac_stat Fail");
1214 			return false;
1215 		}
1216 
1217 		nla_nest_end(vendor_event, wmm_stats);
1218 	}
1219 	nla_nest_end(vendor_event, wmm_info);
1220 
1221 	if (nla_put_u32(vendor_event,
1222 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON,
1223 			if_stat->powersave_stats.tot_tim_bcn) ||
1224 	    nla_put_u32(vendor_event,
1225 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON_ERR,
1226 			if_stat->powersave_stats.tot_err_tim_bcn)) {
1227 		hdd_err("QCA_WLAN_VENDOR_ATTR put powersave_stat fail");
1228 		return false;
1229 	}
1230 
1231 	return true;
1232 }
1233 
1234 /**
1235  * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
1236  * @device_mode: Device mode
1237  *
1238  * Return: interface mode
1239  */
1240 static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int device_mode)
1241 {
1242 	switch (device_mode) {
1243 	case QDF_STA_MODE:
1244 		return WIFI_INTERFACE_STA;
1245 	case QDF_SAP_MODE:
1246 		return WIFI_INTERFACE_SOFTAP;
1247 	case QDF_P2P_CLIENT_MODE:
1248 		return WIFI_INTERFACE_P2P_CLIENT;
1249 	case QDF_P2P_GO_MODE:
1250 		return WIFI_INTERFACE_P2P_GO;
1251 	default:
1252 		/* Return Interface Mode as STA for all the unsupported modes */
1253 		return WIFI_INTERFACE_STA;
1254 	}
1255 }
1256 
1257 bool hdd_get_interface_info(struct wlan_hdd_link_info *link_info,
1258 			    struct wifi_interface_info *info)
1259 {
1260 	struct hdd_station_ctx *sta_ctx;
1261 	struct sap_config *config;
1262 	struct qdf_mac_addr *mac;
1263 	struct hdd_adapter *adapter = link_info->adapter;
1264 
1265 	info->mode = hdd_map_device_to_ll_iface_mode(adapter->device_mode);
1266 
1267 	mac = hdd_adapter_get_link_mac_addr(link_info);
1268 	if (!mac) {
1269 		hdd_debug("Invalid HDD link info");
1270 		return false;
1271 	}
1272 
1273 	qdf_copy_macaddr(&info->macAddr, mac);
1274 
1275 	if (((QDF_STA_MODE == adapter->device_mode) ||
1276 	     (QDF_P2P_CLIENT_MODE == adapter->device_mode) ||
1277 	     (QDF_P2P_DEVICE_MODE == adapter->device_mode))) {
1278 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1279 		if (hdd_cm_is_disconnected(link_info))
1280 			info->state = WIFI_DISCONNECTED;
1281 
1282 		if (hdd_cm_is_connecting(link_info)) {
1283 			hdd_debug("Session ID %d, Connection is in progress",
1284 				  link_info->vdev_id);
1285 			info->state = WIFI_ASSOCIATING;
1286 		}
1287 		if (hdd_cm_is_vdev_associated(link_info) &&
1288 		    !sta_ctx->conn_info.is_authenticated) {
1289 			hdd_err("client " QDF_MAC_ADDR_FMT
1290 				" is in the middle of WPS/EAPOL exchange.",
1291 				QDF_MAC_ADDR_REF(mac->bytes));
1292 			info->state = WIFI_AUTHENTICATING;
1293 		}
1294 		if (hdd_cm_is_vdev_associated(link_info) ||
1295 		    link_info->vdev_id == WLAN_INVALID_VDEV_ID) {
1296 			info->state = WIFI_ASSOCIATED;
1297 			qdf_copy_macaddr(&info->bssid,
1298 					 &sta_ctx->conn_info.bssid);
1299 			qdf_mem_copy(info->ssid,
1300 				     sta_ctx->conn_info.ssid.SSID.ssId,
1301 				     sta_ctx->conn_info.ssid.SSID.length);
1302 			/*
1303 			 * NULL Terminate the string
1304 			 */
1305 			info->ssid[sta_ctx->conn_info.ssid.SSID.length] = 0;
1306 		}
1307 	}
1308 
1309 	if ((adapter->device_mode == QDF_SAP_MODE ||
1310 	     adapter->device_mode == QDF_P2P_GO_MODE) &&
1311 	    test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) {
1312 		config = &link_info->session.ap.sap_config;
1313 		qdf_copy_macaddr(&info->bssid, &config->self_macaddr);
1314 	}
1315 	wlan_reg_get_cc_and_src(adapter->hdd_ctx->psoc, info->countryStr);
1316 	wlan_reg_get_cc_and_src(adapter->hdd_ctx->psoc, info->apCountryStr);
1317 
1318 	return true;
1319 }
1320 
1321 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
1322 /**
1323  * hdd_cache_ll_iface_stats() - Caches ll_stats received from fw
1324  * @hdd_ctx: Pointer to hdd_context
1325  * @if_stat: Pointer to stats data
1326  *
1327  * After receiving Link Layer Interface statistics from FW.
1328  * This function caches them into wlan_hdd_link_info.
1329  *
1330  * Return: None
1331  */
1332 static void
1333 hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx,
1334 			 struct wifi_interface_stats *if_stat)
1335 {
1336 	struct wlan_hdd_link_info *link_info;
1337 
1338 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, if_stat->vdev_id);
1339 	if (!link_info) {
1340 		hdd_err("Invalid link_info. Unable to cache mlo iface stats");
1341 		return;
1342 	}
1343 	/*
1344 	 * There is no need for wlan_hdd_validate_context here. This is a NB
1345 	 * operation that will come with DSC synchronization. This ensures that
1346 	 * no driver transition will take place as long as this operation is
1347 	 * not complete. Thus the need to check validity of hdd_context is not
1348 	 * required.
1349 	 */
1350 	hdd_nofl_debug("Copying iface stats for vdev_id[%u] into link_info",
1351 		       link_info->vdev_id);
1352 	link_info->ll_iface_stats = *if_stat;
1353 }
1354 
1355 /**
1356  * wlan_hdd_update_wmm_ac_stats() - Populate ll_iface ac stats
1357  * @link_info: Link info pointer of STA adapter
1358  * @if_stat: Pointer to wifi_interface_stats structure
1359  * @update_contention_stats: whether to update contention stats or not
1360  *
1361  * Return: none
1362  */
1363 static void
1364 wlan_hdd_update_wmm_ac_stats(struct wlan_hdd_link_info *link_info,
1365 			     struct wifi_interface_stats *if_stat,
1366 			     bool update_contention_stats)
1367 {
1368 	int i;
1369 	wmi_wmm_ac_stats *hdd_ac_stats, *stats;
1370 
1371 	for (i = 0; i < WIFI_AC_MAX; i++) {
1372 		hdd_ac_stats = &link_info->ll_iface_stats.ac_stats[i];
1373 		stats = &if_stat->ac_stats[i];
1374 		stats->ac_type = hdd_ac_stats->ac_type;
1375 		stats->tx_mpdu += hdd_ac_stats->tx_mpdu;
1376 		stats->rx_mpdu += hdd_ac_stats->rx_mpdu;
1377 		stats->tx_mcast += hdd_ac_stats->tx_mcast;
1378 		stats->rx_mcast += hdd_ac_stats->rx_mcast;
1379 		stats->rx_ampdu += hdd_ac_stats->rx_ampdu;
1380 		stats->tx_ampdu += hdd_ac_stats->tx_ampdu;
1381 		stats->mpdu_lost += hdd_ac_stats->mpdu_lost;
1382 		stats->retries += hdd_ac_stats->retries;
1383 		stats->retries_short += hdd_ac_stats->retries_short;
1384 		stats->retries_long += hdd_ac_stats->retries_long;
1385 		if (!update_contention_stats)
1386 			continue;
1387 		stats->contention_time_min = hdd_ac_stats->contention_time_min;
1388 		stats->contention_time_max = hdd_ac_stats->contention_time_max;
1389 		stats->contention_time_avg = hdd_ac_stats->contention_time_avg;
1390 		stats->contention_num_samples =
1391 					hdd_ac_stats->contention_num_samples;
1392 	}
1393 }
1394 
1395 /**
1396  * wlan_hdd_update_iface_stats_info() - Populate ll_iface stats info
1397  * @link_info: Link info pointer of STA adapter
1398  * @if_stat: Pointer to wifi_interface_stats structure
1399  * @update_stats: whether to update iface stats
1400  *
1401  * Return: none
1402  */
1403 static void
1404 wlan_hdd_update_iface_stats_info(struct wlan_hdd_link_info *link_info,
1405 				 struct wifi_interface_stats *if_stat,
1406 				 bool update_stats)
1407 {
1408 	wmi_iface_link_stats *hdd_stats, *stats;
1409 
1410 	hdd_stats = &link_info->ll_iface_stats.link_stats;
1411 	stats = &if_stat->link_stats;
1412 
1413 	if (!update_stats) {
1414 		wlan_hdd_update_wmm_ac_stats(link_info, if_stat, update_stats);
1415 		return;
1416 	}
1417 
1418 	stats->beacon_rx = hdd_stats->beacon_rx;
1419 	stats->mgmt_rx = hdd_stats->mgmt_rx;
1420 	stats->mgmt_action_rx = hdd_stats->mgmt_action_rx;
1421 	stats->mgmt_action_tx = hdd_stats->mgmt_action_tx;
1422 	stats->rssi_mgmt = hdd_stats->rssi_mgmt;
1423 	stats->rssi_data = hdd_stats->rssi_data;
1424 	stats->rssi_ack = hdd_stats->rssi_ack;
1425 	stats->avg_bcn_spread_offset_low =
1426 			hdd_stats->avg_bcn_spread_offset_low;
1427 	stats->avg_bcn_spread_offset_high =
1428 			hdd_stats->avg_bcn_spread_offset_high;
1429 	stats->is_leaky_ap = hdd_stats->is_leaky_ap;
1430 	stats->avg_rx_frms_leaked = hdd_stats->avg_rx_frms_leaked;
1431 	stats->rx_leak_window = hdd_stats->rx_leak_window;
1432 	stats->nf_cal_val = hdd_stats->nf_cal_val;
1433 	stats->num_peers = hdd_stats->num_peers;
1434 	stats->num_ac = hdd_stats->num_ac;
1435 
1436 	if_stat->rts_succ_cnt = link_info->ll_iface_stats.rts_succ_cnt;
1437 	if_stat->rts_fail_cnt = link_info->ll_iface_stats.rts_fail_cnt;
1438 	if_stat->ppdu_succ_cnt = link_info->ll_iface_stats.ppdu_succ_cnt;
1439 	if_stat->ppdu_fail_cnt = link_info->ll_iface_stats.ppdu_fail_cnt;
1440 
1441 	if_stat->powersave_stats.tot_tim_bcn =
1442 		link_info->ll_iface_stats.powersave_stats.tot_tim_bcn;
1443 	if_stat->powersave_stats.tot_err_tim_bcn =
1444 		link_info->ll_iface_stats.powersave_stats.tot_err_tim_bcn;
1445 
1446 	wlan_hdd_update_wmm_ac_stats(link_info, if_stat, update_stats);
1447 }
1448 
1449 /**
1450  * wlan_hdd_copy_mlo_peer_stats() - copy mlo peer stats to link_info
1451  * @adapter: Pointer to HDD adapter
1452  * @peer_stat: Pointer to wifi_peer_stat
1453  *
1454  * Return: none
1455  */
1456 static void
1457 wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter *adapter,
1458 			     struct wifi_peer_stat *peer_stat)
1459 {
1460 	uint8_t i, j, num_rate;
1461 	struct wifi_peer_info *peer_info = NULL;
1462 	struct wifi_rate_stat *rate_stat;
1463 	struct wlan_hdd_link_info *link_info;
1464 	struct hdd_station_ctx *sta_ctx;
1465 
1466 	if (!peer_stat) {
1467 		hdd_err("Invalid mlo peer stats");
1468 		return;
1469 	}
1470 
1471 	if (!peer_stat->num_peers) {
1472 		hdd_err("No mlo peers");
1473 		return;
1474 	}
1475 
1476 	/* Firmware doesn't send peer stats for stanby link, but we need to
1477 	 * send peer stats for stanby link as well to userspace. So, in that
1478 	 * case we fill partial values for stanby link and full stats received
1479 	 * from firmware for active links and set the flag stats_cached in
1480 	 * the link_info->mlo_peer_info structure.
1481 	 */
1482 
1483 	peer_info = (struct wifi_peer_info *)peer_stat->peer_info;
1484 
1485 	hdd_adapter_for_each_link_info(adapter, link_info) {
1486 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1487 		link_info->mlo_peer_info.link_id =
1488 						sta_ctx->conn_info.ieee_link_id;
1489 
1490 		if (link_info->mlo_peer_info.stats_cached)
1491 			continue;
1492 
1493 		/* since for stanby link we don't have valid values from
1494 		 * firmware, we just fill peer mac and link id.
1495 		 */
1496 		qdf_mem_copy(&link_info->mlo_peer_info.peer_mac,
1497 			     &sta_ctx->conn_info.bssid, QDF_MAC_ADDR_SIZE);
1498 		link_info->mlo_peer_info.type = peer_info->type;
1499 		link_info->mlo_peer_info.num_rate = HDD_MAX_PER_PEER_RATES;
1500 		for (j = 0; j < HDD_MAX_PER_PEER_RATES; j++)
1501 			qdf_mem_zero(&link_info->mlo_peer_info.rate_stats[j],
1502 				     sizeof(struct wifi_rate_stat));
1503 		hdd_debug("Default values for standby link " QDF_MAC_ADDR_FMT,
1504 			  QDF_MAC_ADDR_REF(sta_ctx->conn_info.bssid.bytes));
1505 	}
1506 
1507 	for (i = 1; i <= peer_stat->num_peers; i++) {
1508 		link_info = hdd_get_link_info_by_bssid(adapter->hdd_ctx,
1509 						peer_info->peer_macaddr.bytes);
1510 		if (!link_info) {
1511 			hdd_err("invalid link_info");
1512 			continue;
1513 		}
1514 
1515 		num_rate = peer_info->num_rate;
1516 		if (num_rate > HDD_MAX_PER_PEER_RATES) {
1517 			hdd_err("For peer " QDF_MAC_ADDR_FMT " got %u rate stats, expected %d",
1518 				QDF_MAC_ADDR_REF(peer_info->peer_macaddr.bytes),
1519 				num_rate, HDD_MAX_PER_PEER_RATES);
1520 			return;
1521 		}
1522 
1523 		link_info->mlo_peer_info.type = peer_info->type;
1524 		qdf_mem_copy(&link_info->mlo_peer_info.peer_mac,
1525 			     &peer_info->peer_macaddr, QDF_MAC_ADDR_SIZE);
1526 		link_info->mlo_peer_info.capabilities = peer_info->capabilities;
1527 		link_info->mlo_peer_info.num_rate = peer_info->num_rate;
1528 		link_info->mlo_peer_info.power_saving = peer_info->power_saving;
1529 
1530 		for (j = 0; j < num_rate; j++) {
1531 			rate_stat = &peer_info->rate_stats[j];
1532 			qdf_mem_copy(&link_info->mlo_peer_info.rate_stats[j],
1533 				     rate_stat, sizeof(struct wifi_rate_stat));
1534 		}
1535 
1536 		/* peer stats for active link are cached in link_info
1537 		 * so set the flag stats_cahed to true.
1538 		 */
1539 		link_info->mlo_peer_info.stats_cached = true;
1540 
1541 		peer_info = (struct wifi_peer_info *)
1542 				((uint8_t *)peer_stat->peer_info +
1543 				(i * sizeof(struct wifi_peer_info)) +
1544 				(num_rate * sizeof(struct wifi_rate_stat)));
1545 	}
1546 	hdd_debug_rl("Copied MLO Peer stats into link_info");
1547 }
1548 
1549 /**
1550  * wlan_hdd_put_mlo_peer_info() - send mlo peer info to userspace
1551  * @link_info: Link info pointer of STA adapter
1552  * @skb: Pointer to vendor event
1553  *
1554  * Return: none
1555  */
1556 static bool wlan_hdd_put_mlo_peer_info(struct wlan_hdd_link_info *link_info,
1557 				       struct sk_buff *skb)
1558 {
1559 	struct wifi_rate_stat *rate_stat;
1560 	struct nlattr *rate_nest, *rates;
1561 	int rate_nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO;
1562 	uint8_t i;
1563 
1564 	if (!link_info) {
1565 		hdd_err("Invalid link_info");
1566 		return false;
1567 	}
1568 
1569 	if (nla_put_u32(skb,
1570 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
1571 			wmi_to_sir_peer_type(link_info->mlo_peer_info.type)) ||
1572 	    nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
1573 		    QDF_MAC_ADDR_SIZE,
1574 		    &link_info->mlo_peer_info.peer_mac.bytes[0]) ||
1575 	    nla_put_u32(skb,
1576 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
1577 			link_info->mlo_peer_info.capabilities) ||
1578 	    nla_put_u32(skb,
1579 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
1580 			link_info->mlo_peer_info.num_rate) ||
1581 	    nla_put_u8(skb,
1582 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID,
1583 		       link_info->mlo_peer_info.link_id)) {
1584 		hdd_err("put mlo peer info fail");
1585 		return false;
1586 	}
1587 
1588 	/* no rates is ok */
1589 	if (!link_info->mlo_peer_info.num_rate)
1590 		return true;
1591 
1592 	rate_nest = nla_nest_start(skb, rate_nest_id);
1593 	if (!rate_nest)
1594 		return false;
1595 
1596 	for (i = 0; i < link_info->mlo_peer_info.num_rate; i++) {
1597 		rates = nla_nest_start(skb, i);
1598 		if (!rates)
1599 			return false;
1600 		rate_stat = &link_info->mlo_peer_info.rate_stats[i];
1601 		if (!put_wifi_rate_stat(rate_stat, skb)) {
1602 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1603 			return false;
1604 		}
1605 		nla_nest_end(skb, rates);
1606 	}
1607 	nla_nest_end(skb, rate_nest);
1608 
1609 	return true;
1610 }
1611 
1612 /**
1613  * wlan_hdd_send_mlo_ll_peer_stats_to_user() - send mlo ll peer stats to userspace
1614  * @adapter: Pointer to HDD adapter
1615  *
1616  * Return: none
1617  */
1618 static void
1619 wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter *adapter)
1620 {
1621 	struct sk_buff *skb;
1622 	struct nlattr *peers, *peer_nest;
1623 	struct wlan_hdd_link_info *link_info;
1624 	struct wlan_hdd_mlo_iface_stats_info info = {0};
1625 	int peer_nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO;
1626 	u32 num_peers;
1627 	uint8_t i = 0;
1628 
1629 	wlan_hdd_get_mlo_links_count(adapter, &num_peers);
1630 
1631 	hdd_debug_rl("WMI_MLO_LINK_STATS_PEER. Num Peers: %u", num_peers);
1632 
1633 	if (!num_peers) {
1634 		hdd_err("No mlo peers");
1635 		return;
1636 	}
1637 
1638 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(adapter->hdd_ctx->wiphy,
1639 						       LL_STATS_EVENT_BUF_SIZE);
1640 	if (!skb) {
1641 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1642 		return;
1643 	}
1644 
1645 	if (nla_put_u32(skb,
1646 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
1647 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS) ||
1648 	    nla_put_u32(skb,
1649 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
1650 			adapter->hdd_ctx->more_peer_data) ||
1651 	    nla_put_u32(skb,
1652 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
1653 			num_peers)) {
1654 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1655 
1656 		goto exit;
1657 	}
1658 
1659 	peer_nest = nla_nest_start(skb, peer_nest_id);
1660 	if (!peer_nest) {
1661 		hdd_err("nla_nest_start failed");
1662 		goto exit;
1663 	}
1664 
1665 	hdd_adapter_for_each_link_info(adapter, link_info) {
1666 		wlan_hdd_get_connected_link_info(link_info, &info);
1667 		if (info.link_id == WLAN_INVALID_LINK_ID)
1668 			continue;
1669 
1670 		peers = nla_nest_start(skb, i);
1671 		if (!peers) {
1672 			hdd_err("nla_nest_start failed");
1673 			goto exit;
1674 		}
1675 
1676 		if (!wlan_hdd_put_mlo_peer_info(link_info, skb)) {
1677 			hdd_err("put_wifi_peer_info fail");
1678 			goto exit;
1679 		}
1680 		nla_nest_end(skb, peers);
1681 		i++;
1682 	}
1683 	nla_nest_end(skb, peer_nest);
1684 
1685 	wlan_cfg80211_vendor_cmd_reply(skb);
1686 
1687 	hdd_debug_rl("Sent %u MLO Peer stats to User Space", i);
1688 	return;
1689 exit:
1690 	wlan_cfg80211_vendor_free_skb(skb);
1691 }
1692 
1693 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
1694 /**
1695  * wlan_hdd_get_iface_stats() - Get ll_iface stats info from link_info
1696  * @link_info: Link info pointer of STA adapter
1697  * @if_stat: Pointer to wifi_interface_stats structure
1698  *
1699  * Return: 0 on success, error on failure
1700  */
1701 static int wlan_hdd_get_iface_stats(struct wlan_hdd_link_info *link_info,
1702 				    struct wifi_interface_stats *if_stat)
1703 {
1704 	if (!link_info || !if_stat) {
1705 		hdd_err("Invalid link_info or interface stats");
1706 		return -EINVAL;
1707 	}
1708 
1709 	qdf_mem_copy(if_stat, &link_info->ll_iface_stats,
1710 		     sizeof(link_info->ll_iface_stats));
1711 
1712 	if (!hdd_get_interface_info(link_info, &if_stat->info)) {
1713 		hdd_err("Unable to get iface info for vdev[%u]",
1714 			if_stat->vdev_id);
1715 		return -EINVAL;
1716 	}
1717 
1718 	return 0;
1719 }
1720 
1721 static bool
1722 wlan_hdd_get_mlo_iface_info(struct hdd_context *hdd_ctx,
1723 			    struct wifi_interface_stats *stats,
1724 			    struct wlan_hdd_mlo_iface_stats_info *info)
1725 {
1726 	struct wlan_hdd_link_info *link_info;
1727 	struct hdd_station_ctx *sta_ctx;
1728 
1729 	if (!stats) {
1730 		hdd_err("invalid wifi interface stats");
1731 		return false;
1732 	}
1733 
1734 	link_info = hdd_get_link_info_by_bssid(hdd_ctx,
1735 				(const uint8_t *)stats->info.bssid.bytes);
1736 
1737 	if (!link_info) {
1738 		hdd_err("invalid link_info");
1739 		return false;
1740 	}
1741 
1742 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1743 	info->link_id = sta_ctx->conn_info.ieee_link_id;
1744 	info->freq = sta_ctx->conn_info.chan_freq;
1745 
1746 	return true;
1747 }
1748 
1749 /**
1750  * wlan_hdd_send_mlo_ll_iface_stats_to_user() - send mlo ll stats to userspace
1751  * @adapter: Pointer to adapter
1752  *
1753  * Return: none
1754  */
1755 static void
1756 wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter)
1757 {
1758 	struct hdd_mlo_adapter_info *mlo_adapter_info;
1759 	struct hdd_adapter *link_adapter, *ml_adapter;
1760 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1761 	u32 num_links, per_link_peers;
1762 	uint8_t i, j = 0;
1763 	int8_t rssi;
1764 	struct wifi_interface_stats cumulative_if_stat = {0};
1765 	struct wlan_hdd_mlo_iface_stats_info info = {0};
1766 	struct wifi_interface_stats *link_if_stat;
1767 	bool update_stats = false;
1768 	QDF_STATUS status;
1769 	struct nlattr *ml_iface_nest, *ml_iface_links;
1770 	struct sk_buff *skb;
1771 	struct wlan_hdd_link_info *link_info;
1772 	struct qdf_mac_addr *netdev_addr;
1773 
1774 	if (wlan_hdd_validate_context(hdd_ctx)) {
1775 		hdd_err("Invalid hdd context");
1776 		return;
1777 	}
1778 
1779 	ml_adapter = adapter;
1780 	if (hdd_adapter_is_link_adapter(adapter))
1781 		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
1782 
1783 	link_info = ml_adapter->deflink;
1784 	rssi = link_info->rssi;
1785 	wlan_hdd_get_mlo_links_count(adapter, &num_links);
1786 
1787 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
1788 						       LL_STATS_EVENT_BUF_SIZE);
1789 
1790 	if (!skb) {
1791 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1792 		return;
1793 	}
1794 
1795 	link_if_stat = qdf_mem_malloc(sizeof(*link_if_stat) * num_links);
1796 	if (!link_if_stat) {
1797 		hdd_err("failed to allocate memory for link iface stat");
1798 		goto err;
1799 	}
1800 
1801 	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_links = %u", num_links);
1802 
1803 	if (!hdd_get_interface_info(link_info, &cumulative_if_stat.info)) {
1804 		hdd_err("hdd_get_interface_info get fail for ml_adapter");
1805 		goto err;
1806 	}
1807 
1808 	wlan_hdd_update_iface_stats_info(link_info, &cumulative_if_stat,
1809 					 true);
1810 
1811 	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
1812 	for (i = 0; i < WLAN_MAX_MLD; i++) {
1813 		link_adapter = mlo_adapter_info->link_adapter[i];
1814 
1815 		if (!link_adapter)
1816 			continue;
1817 
1818 		link_info = link_adapter->deflink;
1819 		if (!hdd_cm_is_vdev_associated(link_info)) {
1820 			hdd_debug_rl("vdev_id[%u] is not associated\n",
1821 				     link_info->vdev_id);
1822 			continue;
1823 		}
1824 
1825 		if (hdd_adapter_is_associated_with_ml_adapter(link_adapter)) {
1826 			if (wlan_hdd_get_iface_stats(ml_adapter->deflink,
1827 						     &link_if_stat[j]))
1828 				goto err;
1829 			j++;
1830 			if (j == num_links)
1831 				break;
1832 			continue;
1833 		}
1834 
1835 		if (wlan_hdd_get_iface_stats(link_info, &link_if_stat[j]))
1836 			goto err;
1837 		j++;
1838 		if (j == num_links)
1839 			break;
1840 
1841 		if (rssi <= link_info->rssi) {
1842 			rssi = link_info->rssi;
1843 			update_stats = true;
1844 		}
1845 
1846 		wlan_hdd_update_iface_stats_info(link_info,
1847 						 &cumulative_if_stat,
1848 						 update_stats);
1849 	}
1850 
1851 	netdev_addr = hdd_adapter_get_netdev_mac_addr(ml_adapter);
1852 	qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr);
1853 
1854 	status = wlan_hdd_get_bss_peer_mld_mac(ml_adapter->deflink,
1855 					       &cumulative_if_stat.info.bssid);
1856 	if (QDF_IS_STATUS_ERROR(status))
1857 		hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac");
1858 
1859 	if (!put_wifi_iface_stats(&cumulative_if_stat, num_links, skb)) {
1860 		hdd_err("put_wifi_iface_stats fail");
1861 		goto err;
1862 	}
1863 
1864 	ml_iface_nest = nla_nest_start(skb,
1865 				       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK);
1866 	if (!ml_iface_nest) {
1867 		hdd_err("Nesting mlo iface stats info failed");
1868 		goto err;
1869 	}
1870 
1871 	for (i = 0; i < num_links; i++) {
1872 		ml_iface_links = nla_nest_start(skb, i);
1873 		if (!ml_iface_links) {
1874 			hdd_err("per link mlo iface stats failed");
1875 			goto err;
1876 		}
1877 
1878 		per_link_peers =
1879 			link_info->ll_iface_stats.link_stats.num_peers;
1880 
1881 		if (!wlan_hdd_get_mlo_iface_info(hdd_ctx,
1882 						 &link_if_stat[i], &info))
1883 			goto err;
1884 
1885 		if (!wlan_hdd_put_mlo_link_iface_info(&info, skb))
1886 			goto err;
1887 
1888 		if (!put_wifi_iface_stats(&link_if_stat[i],
1889 					  per_link_peers, skb)) {
1890 			hdd_err("put_wifi_iface_stats failed for link[%u]", i);
1891 			goto err;
1892 		}
1893 
1894 		nla_nest_end(skb, ml_iface_links);
1895 	}
1896 	nla_nest_end(skb, ml_iface_nest);
1897 
1898 	wlan_cfg80211_vendor_cmd_reply(skb);
1899 	qdf_mem_free(link_if_stat);
1900 	hdd_nofl_debug("Sent mlo interface stats to userspace");
1901 	return;
1902 err:
1903 	wlan_cfg80211_vendor_free_skb(skb);
1904 	qdf_mem_free(link_if_stat);
1905 }
1906 #else
1907 static void
1908 wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter)
1909 {
1910 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1911 	u32 num_links, per_link_peers;
1912 	uint8_t i = 0;
1913 	int8_t rssi = WLAN_INVALID_RSSI_VALUE;
1914 	struct wifi_interface_stats cumulative_if_stat = {0};
1915 	struct wlan_hdd_mlo_iface_stats_info info = {0};
1916 	struct wifi_interface_stats *stats;
1917 	struct wifi_interface_info *iface_info;
1918 	bool update_stats;
1919 	QDF_STATUS status;
1920 	struct nlattr *ml_iface_nest, *ml_iface_links;
1921 	struct sk_buff *skb;
1922 	struct wlan_hdd_link_info *link_info;
1923 	struct qdf_mac_addr *netdev_addr;
1924 
1925 	if (!wlan_hdd_is_mlo_connection(adapter->deflink))
1926 		return;
1927 
1928 	if (wlan_hdd_validate_context(hdd_ctx)) {
1929 		hdd_err("Invalid hdd context");
1930 		return;
1931 	}
1932 
1933 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
1934 						       LL_STATS_EVENT_BUF_SIZE);
1935 
1936 	if (!skb) {
1937 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1938 		return;
1939 	}
1940 
1941 	wlan_hdd_get_mlo_links_count(adapter, &num_links);
1942 
1943 	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_links = %u", num_links);
1944 
1945 	hdd_adapter_for_each_link_info(adapter, link_info) {
1946 		wlan_hdd_get_connected_link_info(link_info, &info);
1947 		if (info.link_id == WLAN_INVALID_LINK_ID)
1948 			continue;
1949 
1950 		if ((link_info->rssi != 0) && (rssi <= link_info->rssi)) {
1951 			rssi = link_info->rssi;
1952 			update_stats = true;
1953 			if (!hdd_get_interface_info(link_info,
1954 						    &cumulative_if_stat.info)) {
1955 				hdd_err("failed to get iface info for link %u",
1956 					info.link_id);
1957 				goto err;
1958 			}
1959 		} else {
1960 			update_stats = false;
1961 		}
1962 
1963 		iface_info = &link_info->ll_iface_stats.info;
1964 		if (!hdd_get_interface_info(link_info, iface_info)) {
1965 			hdd_err("get iface info failed for link %u", info.link_id);
1966 			goto err;
1967 		}
1968 
1969 		wlan_hdd_update_iface_stats_info(link_info, &cumulative_if_stat,
1970 						 update_stats);
1971 	}
1972 
1973 	netdev_addr = hdd_adapter_get_netdev_mac_addr(adapter);
1974 	qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr);
1975 
1976 	status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink,
1977 					       &cumulative_if_stat.info.bssid);
1978 	if (QDF_IS_STATUS_ERROR(status))
1979 		hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac");
1980 
1981 	if (!put_wifi_iface_stats(&cumulative_if_stat, num_links, skb)) {
1982 		hdd_err("put_wifi_iface_stats fail");
1983 		goto err;
1984 	}
1985 
1986 	ml_iface_nest =
1987 		nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK);
1988 
1989 	if (!ml_iface_nest) {
1990 		hdd_err("Nesting mlo iface stats info failed");
1991 		goto err;
1992 	}
1993 
1994 	hdd_adapter_for_each_link_info(adapter, link_info) {
1995 		wlan_hdd_get_connected_link_info(link_info, &info);
1996 		if (info.link_id == WLAN_INVALID_LINK_ID)
1997 			continue;
1998 
1999 		ml_iface_links = nla_nest_start(skb, i);
2000 		if (!ml_iface_links) {
2001 			hdd_err("per link mlo iface stats failed");
2002 			goto err;
2003 		}
2004 
2005 		stats = &link_info->ll_iface_stats;
2006 		per_link_peers = stats->link_stats.num_peers;
2007 
2008 		if (!wlan_hdd_put_mlo_link_iface_info(&info, skb))
2009 			goto err;
2010 
2011 		if (!put_wifi_iface_stats(stats, per_link_peers, skb)) {
2012 			hdd_err("put iface stats failed for link[%u]", info.link_id);
2013 			goto err;
2014 		}
2015 
2016 		nla_nest_end(skb, ml_iface_links);
2017 		i++;
2018 	}
2019 	nla_nest_end(skb, ml_iface_nest);
2020 
2021 	wlan_cfg80211_vendor_cmd_reply(skb);
2022 	hdd_nofl_debug("Sent mlo interface stats to userspace");
2023 	return;
2024 err:
2025 	wlan_cfg80211_vendor_free_skb(skb);
2026 }
2027 #endif
2028 #else
2029 static void
2030 hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx,
2031 			 struct wifi_interface_stats *if_stat)
2032 {
2033 }
2034 
2035 static inline void
2036 wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter)
2037 {
2038 }
2039 
2040 static inline void
2041 wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter *adapter)
2042 {
2043 }
2044 
2045 static inline bool
2046 wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter *adapter,
2047 			     struct wifi_peer_stat *peer_stat)
2048 {
2049 	return true;
2050 }
2051 #endif
2052 
2053 /**
2054  * hdd_link_layer_process_peer_stats() - This function is called after
2055  * @adapter: Pointer to device adapter
2056  * @more_data: More data
2057  * @peer_stat: Pointer to stats data
2058  *
2059  * Receiving Link Layer Peer statistics from FW.This function converts
2060  * the firmware data to the NL data and sends the same to the kernel/upper
2061  * layers.
2062  *
2063  * Return: None
2064  */
2065 static void hdd_link_layer_process_peer_stats(struct hdd_adapter *adapter,
2066 					      u32 more_data,
2067 					      struct wifi_peer_stat *peer_stat)
2068 {
2069 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2070 	struct wifi_peer_info *peer_info;
2071 	struct sk_buff *skb;
2072 	int i, nestid;
2073 	struct nlattr *peers;
2074 	int num_rate;
2075 
2076 	if (wlan_hdd_validate_context(hdd_ctx))
2077 		return;
2078 
2079 	if ((adapter->device_mode == QDF_STA_MODE ||
2080 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) &&
2081 	    wlan_hdd_is_mlo_connection(adapter->deflink)) {
2082 		wlan_hdd_copy_mlo_peer_stats(adapter, peer_stat);
2083 		return;
2084 	}
2085 
2086 	hdd_nofl_debug("LL_STATS_PEER_ALL : num_peers %u, more data = %u",
2087 		       peer_stat->num_peers, more_data);
2088 
2089 	/*
2090 	 * Allocate a size of 4096 for the peer stats comprising
2091 	 * each of size = sizeof (struct wifi_peer_info) + num_rate *
2092 	 * sizeof (struct wifi_rate_stat).Each field is put with an
2093 	 * NL attribute.The size of 4096 is considered assuming
2094 	 * that number of rates shall not exceed beyond 50 with
2095 	 * the sizeof (struct wifi_rate_stat) being 32.
2096 	 */
2097 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
2098 						       LL_STATS_EVENT_BUF_SIZE);
2099 
2100 	if (!skb) {
2101 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
2102 		return;
2103 	}
2104 
2105 	if (nla_put_u32(skb,
2106 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
2107 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS) ||
2108 	    nla_put_u32(skb,
2109 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
2110 			more_data) ||
2111 	    nla_put_u32(skb,
2112 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
2113 			peer_stat->num_peers)) {
2114 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2115 
2116 		wlan_cfg80211_vendor_free_skb(skb);
2117 		return;
2118 	}
2119 
2120 	peer_info = (struct wifi_peer_info *) ((uint8_t *)
2121 					     peer_stat->peer_info);
2122 
2123 	if (peer_stat->num_peers) {
2124 		struct nlattr *peer_nest;
2125 
2126 		nestid = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO;
2127 		peer_nest = nla_nest_start(skb, nestid);
2128 		if (!peer_nest) {
2129 			hdd_err("nla_nest_start failed");
2130 			wlan_cfg80211_vendor_free_skb(skb);
2131 			return;
2132 		}
2133 
2134 		for (i = 1; i <= peer_stat->num_peers; i++) {
2135 			peers = nla_nest_start(skb, i);
2136 			if (!peers) {
2137 				hdd_err("nla_nest_start failed");
2138 				wlan_cfg80211_vendor_free_skb(skb);
2139 				return;
2140 			}
2141 
2142 			num_rate = peer_info->num_rate;
2143 
2144 			if (!put_wifi_peer_info(peer_info, skb)) {
2145 				hdd_err("put_wifi_peer_info fail");
2146 				wlan_cfg80211_vendor_free_skb(skb);
2147 				return;
2148 			}
2149 
2150 			peer_info = (struct wifi_peer_info *)
2151 				((uint8_t *)peer_stat->peer_info +
2152 				 (i * sizeof(struct wifi_peer_info)) +
2153 				 (num_rate * sizeof(struct wifi_rate_stat)));
2154 			nla_nest_end(skb, peers);
2155 		}
2156 		nla_nest_end(skb, peer_nest);
2157 	}
2158 
2159 	wlan_cfg80211_vendor_cmd_reply(skb);
2160 }
2161 
2162 /**
2163  * hdd_link_layer_process_iface_stats() - This function is called after
2164  * @link_info: Link info pointer in HDD adapter
2165  * @if_stat: Pointer to stats data
2166  * @num_peers: Number of peers
2167  *
2168  * Receiving Link Layer Interface statistics from FW.This function converts
2169  * the firmware data to the NL data and sends the same to the kernel/upper
2170  * layers.
2171  *
2172  * Return: None
2173  */
2174 static void
2175 hdd_link_layer_process_iface_stats(struct wlan_hdd_link_info *link_info,
2176 				   struct wifi_interface_stats *if_stat,
2177 				   u32 num_peers)
2178 {
2179 	struct sk_buff *skb;
2180 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2181 
2182 	if (wlan_hdd_is_mlo_connection(link_info)) {
2183 		hdd_cache_ll_iface_stats(hdd_ctx, if_stat);
2184 		return;
2185 	}
2186 
2187 	/*
2188 	 * There is no need for wlan_hdd_validate_context here. This is a NB
2189 	 * operation that will come with DSC synchronization. This ensures that
2190 	 * no driver transition will take place as long as this operation is
2191 	 * not complete. Thus the need to check validity of hdd_context is not
2192 	 * required.
2193 	 */
2194 
2195 	/*
2196 	 * Allocate a size of 4096 for the interface stats comprising
2197 	 * sizeof (struct wifi_interface_stats *).The size of 4096 is considered
2198 	 * assuming that all these fit with in the limit.Please take
2199 	 * a call on the limit based on the data requirements on
2200 	 * interface statistics.
2201 	 */
2202 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
2203 						       LL_STATS_EVENT_BUF_SIZE);
2204 
2205 	if (!skb) {
2206 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
2207 		return;
2208 	}
2209 
2210 	hdd_debug("WMI_LINK_STATS_IFACE Data");
2211 
2212 	if (!hdd_get_interface_info(link_info, &if_stat->info)) {
2213 		hdd_err("hdd_get_interface_info get fail");
2214 		wlan_cfg80211_vendor_free_skb(skb);
2215 		return;
2216 	}
2217 
2218 	if (!put_wifi_iface_stats(if_stat, num_peers, skb)) {
2219 		hdd_err("put_wifi_iface_stats fail");
2220 		wlan_cfg80211_vendor_free_skb(skb);
2221 		return;
2222 	}
2223 
2224 	wlan_cfg80211_vendor_cmd_reply(skb);
2225 }
2226 
2227 /**
2228  * put_channel_stats_chload - put chload of channel stats
2229  * @vendor_event: vendor event
2230  * @channel_stats: Pointer to channel stats
2231  *
2232  * Return: bool
2233  */
2234 static bool put_channel_stats_chload(struct sk_buff *vendor_event,
2235 				     struct wifi_channel_stats *channel_stats)
2236 {
2237 	uint64_t txrx_time;
2238 	uint32_t chload;
2239 
2240 	if (!channel_stats->on_time)
2241 		return true;
2242 
2243 	txrx_time = (channel_stats->tx_time + channel_stats->rx_time) * 100;
2244 	chload = qdf_do_div(txrx_time, channel_stats->on_time);
2245 
2246 	if (nla_put_u8(vendor_event,
2247 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE,
2248 		       chload))
2249 		return false;
2250 
2251 	return true;
2252 }
2253 
2254 /**
2255  * hdd_llstats_radio_fill_channels() - radio stats fill channels
2256  * @adapter: Pointer to device adapter
2257  * @radiostat: Pointer to stats data
2258  * @vendor_event: vendor event
2259  *
2260  * Return: 0 on success; errno on failure
2261  */
2262 static int hdd_llstats_radio_fill_channels(struct hdd_adapter *adapter,
2263 					   struct wifi_radio_stats *radiostat,
2264 					   struct sk_buff *vendor_event)
2265 {
2266 	struct wifi_channel_stats *channel_stats;
2267 	struct nlattr *chlist;
2268 	struct nlattr *chinfo;
2269 	int i;
2270 
2271 	chlist = nla_nest_start(vendor_event,
2272 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
2273 	if (!chlist) {
2274 		hdd_err("nla_nest_start failed, %u", radiostat->num_channels);
2275 		return -EINVAL;
2276 	}
2277 
2278 	for (i = 0; i < radiostat->num_channels; i++) {
2279 		channel_stats = (struct wifi_channel_stats *) ((uint8_t *)
2280 				     radiostat->channels +
2281 				     (i * sizeof(struct wifi_channel_stats)));
2282 
2283 		chinfo = nla_nest_start(vendor_event, i);
2284 		if (!chinfo) {
2285 			hdd_err("nla_nest_start failed, chan number %u",
2286 				radiostat->num_channels);
2287 			return -EINVAL;
2288 		}
2289 
2290 		if (nla_put_u32(vendor_event,
2291 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
2292 				channel_stats->channel.width) ||
2293 		    nla_put_u32(vendor_event,
2294 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
2295 				channel_stats->channel.center_freq) ||
2296 		    nla_put_u32(vendor_event,
2297 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
2298 				channel_stats->channel.center_freq0) ||
2299 		    nla_put_u32(vendor_event,
2300 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
2301 				channel_stats->channel.center_freq1) ||
2302 		    nla_put_u32(vendor_event,
2303 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
2304 				channel_stats->on_time) ||
2305 		    nla_put_u32(vendor_event,
2306 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
2307 				channel_stats->cca_busy_time)) {
2308 			hdd_err("nla_put failed for channel info (%u, %d, %u)",
2309 				radiostat->num_channels, i,
2310 				channel_stats->channel.center_freq);
2311 			return -EINVAL;
2312 		}
2313 
2314 		if (adapter->hdd_ctx &&
2315 		    adapter->hdd_ctx->ll_stats_per_chan_rx_tx_time) {
2316 			if (nla_put_u32(
2317 				vendor_event,
2318 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_TX_TIME,
2319 				channel_stats->tx_time) ||
2320 			    nla_put_u32(
2321 				vendor_event,
2322 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME,
2323 				channel_stats->rx_time)) {
2324 				hdd_err("nla_put failed for tx time (%u, %d)",
2325 					radiostat->num_channels, i);
2326 				return -EINVAL;
2327 			}
2328 
2329 			if (!put_channel_stats_chload(vendor_event,
2330 						      channel_stats)) {
2331 				hdd_err("nla_put failed for chload (%u, %d)",
2332 					radiostat->num_channels, i);
2333 				return -EINVAL;
2334 			}
2335 		}
2336 
2337 		nla_nest_end(vendor_event, chinfo);
2338 	}
2339 	nla_nest_end(vendor_event, chlist);
2340 
2341 	return 0;
2342 }
2343 
2344 /**
2345  * hdd_llstats_free_radio_stats() - free wifi_radio_stats member pointers
2346  * @radiostat: Pointer to stats data
2347  *
2348  * Return: void
2349  */
2350 static void hdd_llstats_free_radio_stats(struct wifi_radio_stats *radiostat)
2351 {
2352 	if (radiostat->total_num_tx_power_levels &&
2353 	    radiostat->tx_time_per_power_level) {
2354 		qdf_mem_free(radiostat->tx_time_per_power_level);
2355 		radiostat->tx_time_per_power_level = NULL;
2356 	}
2357 	if (radiostat->num_channels && radiostat->channels) {
2358 		qdf_mem_free(radiostat->channels);
2359 		radiostat->channels = NULL;
2360 	}
2361 }
2362 
2363 /**
2364  * hdd_llstats_post_radio_stats() - post radio stats
2365  * @adapter: Pointer to device adapter
2366  * @more_data: More data
2367  * @radiostat: Pointer to stats data
2368  * @num_radio: Number of radios
2369  *
2370  * Return: void
2371  */
2372 static void hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
2373 					 u32 more_data,
2374 					 struct wifi_radio_stats *radiostat,
2375 					 u32 num_radio)
2376 {
2377 	struct sk_buff *vendor_event;
2378 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2379 	int ret;
2380 
2381 	/*
2382 	 * Allocate a size of 4096 for the Radio stats comprising
2383 	 * sizeof (struct wifi_radio_stats) + num_channels * sizeof
2384 	 * (struct wifi_channel_stats).Each channel data is put with an
2385 	 * NL attribute.The size of 4096 is considered assuming that
2386 	 * number of channels shall not exceed beyond  60 with the
2387 	 * sizeof (struct wifi_channel_stats) being 24 bytes.
2388 	 */
2389 
2390 	vendor_event = wlan_cfg80211_vendor_cmd_alloc_reply_skb(
2391 					hdd_ctx->wiphy,
2392 					LL_STATS_EVENT_BUF_SIZE);
2393 
2394 	if (!vendor_event) {
2395 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
2396 		hdd_llstats_free_radio_stats(radiostat);
2397 		return;
2398 	}
2399 
2400 	if (nla_put_u32(vendor_event,
2401 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
2402 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_RADIO) ||
2403 	    nla_put_u32(vendor_event,
2404 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
2405 			more_data) ||
2406 	    nla_put_u32(vendor_event,
2407 			QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
2408 			num_radio) ||
2409 	    nla_put_u32(vendor_event,
2410 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
2411 			radiostat->radio) ||
2412 	    nla_put_u32(vendor_event,
2413 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
2414 			radiostat->on_time) ||
2415 	    nla_put_u32(vendor_event,
2416 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
2417 			radiostat->tx_time) ||
2418 	    nla_put_u32(vendor_event,
2419 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
2420 			radiostat->rx_time) ||
2421 	    nla_put_u32(vendor_event,
2422 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
2423 			radiostat->on_time_scan) ||
2424 	    nla_put_u32(vendor_event,
2425 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
2426 			radiostat->on_time_nbd) ||
2427 	    nla_put_u32(vendor_event,
2428 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
2429 			radiostat->on_time_gscan) ||
2430 	    nla_put_u32(vendor_event,
2431 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
2432 			radiostat->on_time_roam_scan) ||
2433 	    nla_put_u32(vendor_event,
2434 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
2435 			radiostat->on_time_pno_scan) ||
2436 	    nla_put_u32(vendor_event,
2437 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
2438 			radiostat->on_time_hs20) ||
2439 	    nla_put_u32(vendor_event,
2440 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
2441 			radiostat->total_num_tx_power_levels)    ||
2442 	    nla_put_u32(vendor_event,
2443 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
2444 			radiostat->num_channels)) {
2445 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2446 		hdd_llstats_free_radio_stats(radiostat);
2447 
2448 		goto failure;
2449 	}
2450 
2451 	if (radiostat->total_num_tx_power_levels) {
2452 		ret =
2453 		    nla_put(vendor_event,
2454 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
2455 			    sizeof(u32) *
2456 			    radiostat->total_num_tx_power_levels,
2457 			    radiostat->tx_time_per_power_level);
2458 		if (ret) {
2459 			hdd_err("nla_put fail");
2460 			goto failure;
2461 		}
2462 	}
2463 
2464 	if (radiostat->num_channels) {
2465 		ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
2466 						      vendor_event);
2467 		if (ret)
2468 			goto failure;
2469 	}
2470 
2471 	wlan_cfg80211_vendor_cmd_reply(vendor_event);
2472 	hdd_llstats_free_radio_stats(radiostat);
2473 	return;
2474 
2475 failure:
2476 	wlan_cfg80211_vendor_free_skb(vendor_event);
2477 	hdd_llstats_free_radio_stats(radiostat);
2478 }
2479 
2480 /**
2481  * hdd_link_layer_process_radio_stats() - This function is called after
2482  * @adapter: Pointer to device adapter
2483  * @more_data: More data
2484  * @radio_stat: Pointer to stats data
2485  * @num_radio: Number of radios
2486  *
2487  * Receiving Link Layer Radio statistics from FW.This function converts
2488  * the firmware data to the NL data and sends the same to the kernel/upper
2489  * layers.
2490  *
2491  * Return: None
2492  */
2493 static void
2494 hdd_link_layer_process_radio_stats(struct hdd_adapter *adapter,
2495 				   u32 more_data,
2496 				   struct wifi_radio_stats *radio_stat,
2497 				   u32 num_radio)
2498 {
2499 	int i, nr;
2500 	struct wifi_radio_stats *radio_stat_save = radio_stat;
2501 
2502 	/*
2503 	 * There is no need for wlan_hdd_validate_context here. This is a NB
2504 	 * operation that will come with DSC synchronization. This ensures that
2505 	 * no driver transition will take place as long as this operation is
2506 	 * not complete. Thus the need to check validity of hdd_context is not
2507 	 * required.
2508 	 */
2509 
2510 	for (i = 0; i < num_radio; i++) {
2511 		hdd_nofl_debug("LL_STATS_RADIO"
2512 		       " radio: %u on_time: %u tx_time: %u rx_time: %u"
2513 		       " on_time_scan: %u on_time_nbd: %u"
2514 		       " on_time_gscan: %u on_time_roam_scan: %u"
2515 		       " on_time_pno_scan: %u  on_time_hs20: %u"
2516 		       " num_channels: %u total_num_tx_pwr_levels: %u"
2517 		       " on_time_host_scan: %u, on_time_lpi_scan: %u",
2518 		       radio_stat->radio, radio_stat->on_time,
2519 		       radio_stat->tx_time, radio_stat->rx_time,
2520 		       radio_stat->on_time_scan, radio_stat->on_time_nbd,
2521 		       radio_stat->on_time_gscan,
2522 		       radio_stat->on_time_roam_scan,
2523 		       radio_stat->on_time_pno_scan,
2524 		       radio_stat->on_time_hs20,
2525 		       radio_stat->num_channels,
2526 		       radio_stat->total_num_tx_power_levels,
2527 		       radio_stat->on_time_host_scan,
2528 		       radio_stat->on_time_lpi_scan);
2529 		radio_stat++;
2530 	}
2531 
2532 	radio_stat = radio_stat_save;
2533 	for (nr = 0; nr < num_radio; nr++) {
2534 		hdd_llstats_post_radio_stats(adapter, more_data,
2535 					     radio_stat, num_radio);
2536 		radio_stat++;
2537 	}
2538 
2539 	hdd_exit();
2540 }
2541 
2542 static void hdd_process_ll_stats(tSirLLStatsResults *results,
2543 				 struct osif_request *request)
2544 {
2545 	struct hdd_ll_stats_priv *priv = osif_request_priv(request);
2546 	struct hdd_ll_stats *stats = NULL;
2547 	size_t stat_size = 0;
2548 
2549 	qdf_spin_lock(&priv->ll_stats_lock);
2550 
2551 	if (!(priv->request_bitmap & results->paramId)) {
2552 		qdf_spin_unlock(&priv->ll_stats_lock);
2553 		return;
2554 	}
2555 
2556 	if (results->paramId & WMI_LINK_STATS_RADIO) {
2557 		struct wifi_radio_stats *rs_results, *stat_result;
2558 		u64 channel_size = 0, pwr_lvl_size = 0;
2559 		int i;
2560 
2561 		if (!results->num_radio)
2562 			goto exit;
2563 
2564 		stats = qdf_mem_malloc(sizeof(*stats));
2565 		if (!stats)
2566 			goto exit;
2567 
2568 		stat_size = sizeof(struct wifi_radio_stats) *
2569 			    results->num_radio;
2570 		stats->result_param_id = WMI_LINK_STATS_RADIO;
2571 		stat_result = qdf_mem_malloc(stat_size);
2572 		if (!stat_result) {
2573 			qdf_mem_free(stats);
2574 			goto exit;
2575 		}
2576 		stats->result = stat_result;
2577 		rs_results = (struct wifi_radio_stats *)results->results;
2578 		qdf_mem_copy(stats->result, results->results, stat_size);
2579 		for (i = 0; i < results->num_radio; i++) {
2580 			channel_size = rs_results->num_channels *
2581 				       sizeof(struct wifi_channel_stats);
2582 			pwr_lvl_size = sizeof(uint32_t) *
2583 				       rs_results->total_num_tx_power_levels;
2584 
2585 			if (rs_results->total_num_tx_power_levels &&
2586 			    rs_results->tx_time_per_power_level) {
2587 				stat_result->tx_time_per_power_level =
2588 						qdf_mem_malloc(pwr_lvl_size);
2589 				if (!stat_result->tx_time_per_power_level) {
2590 					while (i-- > 0) {
2591 						stat_result--;
2592 						qdf_mem_free(stat_result->
2593 						    tx_time_per_power_level);
2594 						qdf_mem_free(stat_result->
2595 							     channels);
2596 					}
2597 					qdf_mem_free(stat_result);
2598 					qdf_mem_free(stats);
2599 					goto exit;
2600 				}
2601 			      qdf_mem_copy(stat_result->tx_time_per_power_level,
2602 					   rs_results->tx_time_per_power_level,
2603 					   pwr_lvl_size);
2604 			}
2605 			if (channel_size) {
2606 				stat_result->channels =
2607 						qdf_mem_malloc(channel_size);
2608 				if (!stat_result->channels) {
2609 					qdf_mem_free(stat_result->
2610 						     tx_time_per_power_level);
2611 					while (i-- > 0) {
2612 						stat_result--;
2613 						qdf_mem_free(stat_result->
2614 						    tx_time_per_power_level);
2615 						qdf_mem_free(stat_result->
2616 							     channels);
2617 					}
2618 					qdf_mem_free(stats->result);
2619 					qdf_mem_free(stats);
2620 					goto exit;
2621 				}
2622 				qdf_mem_copy(stat_result->channels,
2623 					     rs_results->channels,
2624 					     channel_size);
2625 			}
2626 			rs_results++;
2627 			stat_result++;
2628 		}
2629 		stats->stats_nradio_npeer.no_of_radios = results->num_radio;
2630 		stats->more_data = results->moreResultToFollow;
2631 		if (!results->moreResultToFollow)
2632 			priv->request_bitmap &= ~stats->result_param_id;
2633 	} else if (results->paramId & WMI_LINK_STATS_IFACE) {
2634 		stats = qdf_mem_malloc(sizeof(*stats));
2635 		if (!stats)
2636 			goto exit;
2637 
2638 		stats->result_param_id = WMI_LINK_STATS_IFACE;
2639 		stats->stats_nradio_npeer.no_of_peers = results->num_peers;
2640 		stats->result = qdf_mem_malloc(sizeof(struct
2641 					       wifi_interface_stats));
2642 		if (!stats->result) {
2643 			qdf_mem_free(stats);
2644 			goto exit;
2645 		}
2646 		qdf_mem_copy(stats->result, results->results,
2647 			     sizeof(struct wifi_interface_stats));
2648 
2649 		/* Firmware doesn't send peerstats event if no peers are
2650 		 * connected. HDD should not wait for any peerstats in
2651 		 * this case and return the status to middleware after
2652 		 * receiving iface stats
2653 		 */
2654 		if (!results->num_peers)
2655 			priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
2656 		priv->request_bitmap &= ~stats->result_param_id;
2657 
2658 		/* Firmware sends interface stats based on vdev_id_bitmap
2659 		 * So, clear the mlo_vdev_id_bitmap in the host accordingly
2660 		 */
2661 		if (priv->is_mlo_req)
2662 			priv->mlo_vdev_id_bitmap &= ~(1 << results->ifaceId);
2663 	} else if (results->paramId & WMI_LINK_STATS_ALL_PEER) {
2664 		struct wifi_peer_stat *peer_stat = (struct wifi_peer_stat *)
2665 						   results->results;
2666 		struct wifi_peer_info *peer_info = NULL;
2667 		u64 num_rate = 0, peers, rates;
2668 		int i;
2669 		stats = qdf_mem_malloc(sizeof(*stats));
2670 		if (!stats)
2671 			goto exit;
2672 
2673 		peer_info = (struct wifi_peer_info *)peer_stat->peer_info;
2674 		for (i = 1; i <= peer_stat->num_peers; i++) {
2675 			num_rate += peer_info->num_rate;
2676 			peer_info = (struct wifi_peer_info *)((uint8_t *)
2677 				    peer_info + sizeof(struct wifi_peer_info) +
2678 				    (peer_info->num_rate *
2679 				    sizeof(struct wifi_rate_stat)));
2680 		}
2681 
2682 		peers = sizeof(struct wifi_peer_info) * peer_stat->num_peers;
2683 		rates = sizeof(struct wifi_rate_stat) * num_rate;
2684 		stat_size = sizeof(struct wifi_peer_stat) + peers + rates;
2685 		stats->result_param_id = WMI_LINK_STATS_ALL_PEER;
2686 
2687 		stats->result = qdf_mem_malloc(stat_size);
2688 		if (!stats->result) {
2689 			qdf_mem_free(stats);
2690 			goto exit;
2691 		}
2692 
2693 		qdf_mem_copy(stats->result, results->results, stat_size);
2694 		stats->more_data = results->moreResultToFollow;
2695 		if (!results->moreResultToFollow)
2696 			priv->request_bitmap &= ~stats->result_param_id;
2697 	} else {
2698 		hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
2699 	}
2700 	/* send indication to caller thread */
2701 	if (stats)
2702 		qdf_list_insert_back(&priv->ll_stats_q, &stats->ll_stats_node);
2703 
2704 	if (!priv->request_bitmap) {
2705 		if (priv->is_mlo_req && priv->mlo_vdev_id_bitmap)
2706 			goto out;
2707 exit:
2708 		qdf_spin_unlock(&priv->ll_stats_lock);
2709 
2710 		/* Thread which invokes this function has allocated memory in
2711 		 * WMA for radio stats, that memory should be freed from the
2712 		 * same thread to avoid any race conditions between two threads
2713 		 */
2714 		sme_radio_tx_mem_free();
2715 		osif_request_complete(request);
2716 		return;
2717 	}
2718 out:
2719 	qdf_spin_unlock(&priv->ll_stats_lock);
2720 }
2721 
2722 static void hdd_debugfs_process_ll_stats(struct wlan_hdd_link_info *link_info,
2723 					 tSirLLStatsResults *results,
2724 					 struct osif_request *request)
2725 {
2726 	struct hdd_adapter *adapter = link_info->adapter;
2727 	struct hdd_ll_stats_priv *priv = osif_request_priv(request);
2728 
2729 	if (results->paramId & WMI_LINK_STATS_RADIO) {
2730 		hdd_debugfs_process_radio_stats(adapter,
2731 						results->moreResultToFollow,
2732 						results->results,
2733 						results->num_radio);
2734 		if (!results->moreResultToFollow)
2735 			priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
2736 	} else if (results->paramId & WMI_LINK_STATS_IFACE) {
2737 		hdd_debugfs_process_iface_stats(link_info, results->results,
2738 						results->num_peers);
2739 
2740 		/* Firmware doesn't send peerstats event if no peers are
2741 		 * connected. HDD should not wait for any peerstats in
2742 		 * this case and return the status to middleware after
2743 		 * receiving iface stats
2744 		 */
2745 
2746 		if (!results->num_peers)
2747 			priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
2748 
2749 		priv->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
2750 
2751 		/* Firmware sends interface stats based on vdev_id_bitmap
2752 		 * So, clear the mlo_vdev_id_bitmap in the host accordingly
2753 		 */
2754 		if (priv->is_mlo_req)
2755 			priv->mlo_vdev_id_bitmap &= ~(1 << results->ifaceId);
2756 	} else if (results->paramId & WMI_LINK_STATS_ALL_PEER) {
2757 		hdd_debugfs_process_peer_stats(adapter, results->results);
2758 		if (!results->moreResultToFollow)
2759 			priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
2760 	} else {
2761 		hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
2762 	}
2763 
2764 	if (!priv->request_bitmap) {
2765 		if (priv->is_mlo_req && priv->mlo_vdev_id_bitmap)
2766 			return;
2767 		/* Thread which invokes this function has allocated memory in
2768 		 * WMA for radio stats, that memory should be freed from the
2769 		 * same thread to avoid any race conditions between two threads
2770 		 */
2771 		sme_radio_tx_mem_free();
2772 		osif_request_complete(request);
2773 	}
2774 
2775 }
2776 
2777 static void
2778 wlan_hdd_update_ll_stats_request_bitmap(struct hdd_context *hdd_ctx,
2779 					struct osif_request *request,
2780 					tSirLLStatsResults *results)
2781 {
2782 	struct hdd_ll_stats_priv *priv = osif_request_priv(request);
2783 	bool is_mlo_link;
2784 
2785 	if (!wlan_vdev_mlme_get_is_mlo_vdev(hdd_ctx->psoc, priv->vdev_id)) {
2786 		hdd_nofl_debug("Can't update req_bitmap for non MLO case");
2787 		return;
2788 	}
2789 
2790 	is_mlo_link = wlan_vdev_mlme_get_is_mlo_link(hdd_ctx->psoc,
2791 						     results->ifaceId);
2792 	/* In case of MLO Connection, set the request_bitmap */
2793 	if (is_mlo_link && results->paramId == WMI_LINK_STATS_IFACE) {
2794 		/* Set the request_bitmap for MLO link vdev iface stats */
2795 		if (!(priv->request_bitmap & results->paramId))
2796 			priv->request_bitmap |= results->paramId;
2797 
2798 		hdd_nofl_debug("MLO_LL_STATS set request_bitmap = 0x%x",
2799 			       priv->request_bitmap);
2800 	}
2801 }
2802 
2803 void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
2804 						 int indication_type,
2805 						 tSirLLStatsResults *results,
2806 						 void *cookie)
2807 {
2808 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
2809 	struct hdd_ll_stats_priv *priv;
2810 	struct wlan_hdd_link_info *link_info;
2811 	int status;
2812 	struct osif_request *request;
2813 
2814 	status = wlan_hdd_validate_context(hdd_ctx);
2815 	if (status)
2816 		return;
2817 
2818 	switch (indication_type) {
2819 	case SIR_HAL_LL_STATS_RESULTS_RSP:
2820 	{
2821 		hdd_nofl_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %pK",
2822 			       results->paramId, results->ifaceId,
2823 			       results->rspId, results->moreResultToFollow,
2824 			       results->num_radio, results->results);
2825 
2826 		request = osif_request_get(cookie);
2827 		if (!request) {
2828 			hdd_err("Obsolete request");
2829 			return;
2830 		}
2831 
2832 		priv = osif_request_priv(request);
2833 
2834 		/* validate response received from target */
2835 		if (priv->request_id != results->rspId) {
2836 			hdd_err("Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
2837 				priv->request_id, results->rspId,
2838 				priv->request_bitmap, results->paramId);
2839 			osif_request_put(request);
2840 			return;
2841 		}
2842 
2843 		link_info =
2844 			hdd_get_link_info_by_vdev(hdd_ctx, results->ifaceId);
2845 		if (!link_info) {
2846 			hdd_debug_rl("invalid vdev_id %d sent by FW",
2847 				     results->ifaceId);
2848 			/* for peer stats FW doesn't update the vdev_id info*/
2849 			link_info = hdd_get_link_info_by_vdev(hdd_ctx,
2850 							      priv->vdev_id);
2851 			if (!link_info) {
2852 				hdd_err("invalid vdev %d", priv->vdev_id);
2853 				osif_request_put(request);
2854 				return;
2855 			}
2856 		}
2857 		wlan_hdd_update_ll_stats_request_bitmap(hdd_ctx, request,
2858 							results);
2859 		if (results->rspId == DEBUGFS_LLSTATS_REQID) {
2860 			hdd_debugfs_process_ll_stats(link_info,
2861 						     results, request);
2862 		 } else {
2863 			hdd_process_ll_stats(results, request);
2864 		}
2865 
2866 		osif_request_put(request);
2867 		break;
2868 	}
2869 	default:
2870 		hdd_warn("invalid event type %d", indication_type);
2871 		break;
2872 	}
2873 }
2874 
2875 void hdd_lost_link_info_cb(hdd_handle_t hdd_handle,
2876 			   struct sir_lost_link_info *lost_link_info)
2877 {
2878 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
2879 	int status;
2880 	struct wlan_hdd_link_info *link_info;
2881 	struct hdd_station_ctx *sta_ctx;
2882 
2883 	status = wlan_hdd_validate_context(hdd_ctx);
2884 	if (status)
2885 		return;
2886 
2887 	if (!lost_link_info) {
2888 		hdd_err("lost_link_info is NULL");
2889 		return;
2890 	}
2891 
2892 	if (lost_link_info->rssi == 0) {
2893 		hdd_debug_rl("Invalid rssi on disconnect sent by FW");
2894 		return;
2895 	}
2896 
2897 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, lost_link_info->vdev_id);
2898 	if (!link_info) {
2899 		hdd_err("invalid vdev");
2900 		return;
2901 	}
2902 
2903 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
2904 
2905 	link_info->rssi_on_disconnect = lost_link_info->rssi;
2906 	hdd_debug("rssi on disconnect %d", link_info->rssi_on_disconnect);
2907 
2908 	sta_ctx->cache_conn_info.signal = lost_link_info->rssi;
2909 }
2910 
2911 const struct nla_policy qca_wlan_vendor_ll_set_policy[
2912 			QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
2913 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]
2914 						= { .type = NLA_U32 },
2915 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]
2916 						= { .type = NLA_U32 },
2917 };
2918 
2919 /**
2920  * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
2921  * @wiphy: Pointer to wiphy
2922  * @wdev: Pointer to wdev
2923  * @data: Pointer to data
2924  * @data_len: Data length
2925  *
2926  * Return: int
2927  */
2928 static int
2929 __wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
2930 				   struct wireless_dev *wdev,
2931 				   const void *data,
2932 				   int data_len)
2933 {
2934 	int status;
2935 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
2936 	tSirLLStatsSetReq req;
2937 	struct net_device *dev = wdev->netdev;
2938 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2939 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2940 
2941 	hdd_enter_dev(dev);
2942 
2943 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2944 		hdd_err("Command not allowed in FTM mode");
2945 		return -EPERM;
2946 	}
2947 
2948 	status = wlan_hdd_validate_context(hdd_ctx);
2949 	if (0 != status)
2950 		return -EINVAL;
2951 
2952 	if (hdd_validate_adapter(adapter))
2953 		return -EINVAL;
2954 
2955 	if (adapter->device_mode != QDF_STA_MODE &&
2956 	    adapter->device_mode != QDF_SAP_MODE &&
2957 	    adapter->device_mode != QDF_P2P_CLIENT_MODE &&
2958 	    adapter->device_mode != QDF_P2P_GO_MODE) {
2959 		hdd_debug("Cannot set LL_STATS for device mode %d",
2960 			  adapter->device_mode);
2961 		return -EINVAL;
2962 	}
2963 
2964 	if (wlan_cfg80211_nla_parse(tb_vendor,
2965 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
2966 				    (struct nlattr *)data, data_len,
2967 				    qca_wlan_vendor_ll_set_policy)) {
2968 		hdd_err("maximum attribute not present");
2969 		return -EINVAL;
2970 	}
2971 
2972 	if (!tb_vendor
2973 	    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
2974 		hdd_err("MPDU size Not present");
2975 		return -EINVAL;
2976 	}
2977 
2978 	if (!tb_vendor
2979 	    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
2980 		hdd_err("Stats Gathering Not Present");
2981 		return -EINVAL;
2982 	}
2983 
2984 	/* Shall take the request Id if the Upper layers pass. 1 For now. */
2985 	req.reqId = 1;
2986 
2987 	req.mpduSizeThreshold =
2988 		nla_get_u32(tb_vendor
2989 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
2990 
2991 	req.aggressiveStatisticsGathering =
2992 		nla_get_u32(tb_vendor
2993 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
2994 
2995 	req.staId = adapter->deflink->vdev_id;
2996 
2997 	hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
2998 		req.reqId, req.staId,
2999 		req.mpduSizeThreshold,
3000 		req.aggressiveStatisticsGathering);
3001 
3002 	if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(hdd_ctx->mac_handle,
3003 						       &req)) {
3004 		hdd_err("sme_ll_stats_set_req Failed");
3005 		return -EINVAL;
3006 	}
3007 
3008 	adapter->is_link_layer_stats_set = true;
3009 	hdd_exit();
3010 	return 0;
3011 }
3012 
3013 /**
3014  * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
3015  * @wiphy: Pointer to wiphy
3016  * @wdev: Pointer to wdev
3017  * @data: Pointer to data
3018  * @data_len: Data length
3019  *
3020  * Return: 0 if success, non-zero for failure
3021  */
3022 int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
3023 					struct wireless_dev *wdev,
3024 					const void *data,
3025 					int data_len)
3026 {
3027 	int errno;
3028 	struct osif_vdev_sync *vdev_sync;
3029 
3030 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3031 	if (errno)
3032 		return errno;
3033 
3034 	errno = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
3035 
3036 	osif_vdev_sync_op_stop(vdev_sync);
3037 
3038 	return errno;
3039 }
3040 
3041 const struct nla_policy qca_wlan_vendor_ll_get_policy[
3042 			QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
3043 	/* Unsigned 32bit value provided by the caller issuing the GET stats
3044 	 * command. When reporting
3045 	 * the stats results, the driver uses the same value to indicate
3046 	 * which GET request the results
3047 	 * correspond to.
3048 	 */
3049 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
3050 
3051 	/* Unsigned 32bit value . bit mask to identify what statistics are
3052 	 * requested for retrieval
3053 	 */
3054 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
3055 };
3056 
3057 static void wlan_hdd_handle_ll_stats(struct wlan_hdd_link_info *link_info,
3058 				     struct hdd_ll_stats *stats, int ret)
3059 {
3060 	struct hdd_adapter *adapter = link_info->adapter;
3061 
3062 	switch (stats->result_param_id) {
3063 	case WMI_LINK_STATS_RADIO:
3064 	{
3065 		struct wifi_radio_stats *radio_stat = stats->result;
3066 		int i, num_radio = stats->stats_nradio_npeer.no_of_radios;
3067 
3068 		if (ret == -ETIMEDOUT) {
3069 			for (i = 0; i < num_radio; i++) {
3070 				if (radio_stat->num_channels)
3071 					qdf_mem_free(radio_stat->channels);
3072 				if (radio_stat->total_num_tx_power_levels)
3073 					qdf_mem_free(radio_stat->
3074 						     tx_time_per_power_level);
3075 				radio_stat++;
3076 			}
3077 			return;
3078 		}
3079 		hdd_link_layer_process_radio_stats(adapter, stats->more_data,
3080 						   radio_stat, num_radio);
3081 	}
3082 		break;
3083 	case WMI_LINK_STATS_IFACE:
3084 		hdd_link_layer_process_iface_stats(link_info,
3085 						   stats->result,
3086 						   stats->stats_nradio_npeer.
3087 						   no_of_peers);
3088 		break;
3089 	case WMI_LINK_STATS_ALL_PEER:
3090 		hdd_link_layer_process_peer_stats(adapter,
3091 						  stats->more_data,
3092 						  stats->result);
3093 		break;
3094 	default:
3095 		hdd_err("not requested event");
3096 	}
3097 }
3098 
3099 static void wlan_hdd_dealloc_ll_stats(void *priv)
3100 {
3101 	struct hdd_ll_stats_priv *ll_stats_priv = priv;
3102 	struct hdd_ll_stats *stats = NULL;
3103 	QDF_STATUS status;
3104 	qdf_list_node_t *ll_node;
3105 
3106 	if (!ll_stats_priv)
3107 		return;
3108 
3109 	qdf_spin_lock(&ll_stats_priv->ll_stats_lock);
3110 	status = qdf_list_remove_front(&ll_stats_priv->ll_stats_q, &ll_node);
3111 	qdf_spin_unlock(&ll_stats_priv->ll_stats_lock);
3112 	while (QDF_IS_STATUS_SUCCESS(status)) {
3113 		stats =  qdf_container_of(ll_node, struct hdd_ll_stats,
3114 					  ll_stats_node);
3115 
3116 		if (stats->result_param_id == WMI_LINK_STATS_RADIO) {
3117 			struct wifi_radio_stats *radio_stat = stats->result;
3118 			int i;
3119 			int num_radio = stats->stats_nradio_npeer.no_of_radios;
3120 
3121 			for (i = 0; i < num_radio; i++) {
3122 				if (radio_stat->num_channels)
3123 					qdf_mem_free(radio_stat->channels);
3124 				if (radio_stat->total_num_tx_power_levels)
3125 					qdf_mem_free(radio_stat->
3126 						tx_time_per_power_level);
3127 				radio_stat++;
3128 			}
3129 		}
3130 
3131 		qdf_mem_free(stats->result);
3132 		qdf_mem_free(stats);
3133 		qdf_spin_lock(&ll_stats_priv->ll_stats_lock);
3134 		status = qdf_list_remove_front(&ll_stats_priv->ll_stats_q,
3135 					       &ll_node);
3136 		qdf_spin_unlock(&ll_stats_priv->ll_stats_lock);
3137 	}
3138 	qdf_list_destroy(&ll_stats_priv->ll_stats_q);
3139 }
3140 
3141 static QDF_STATUS
3142 wlan_hdd_set_ll_stats_request_pending(struct hdd_adapter *adapter)
3143 {
3144 	if (qdf_atomic_read(&adapter->is_ll_stats_req_pending)) {
3145 		hdd_nofl_debug("Previous ll_stats request is in progress");
3146 		return QDF_STATUS_E_ALREADY;
3147 	}
3148 
3149 	qdf_atomic_set(&adapter->is_ll_stats_req_pending, 1);
3150 	return QDF_STATUS_SUCCESS;
3151 }
3152 
3153 #ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
3154 /**
3155  * cache_station_stats_cb() - cache_station_stats_cb callback function
3156  * @ev: station stats buffer
3157  * @cookie: cookie that contains the address of the adapter corresponding to
3158  *          the request
3159  *
3160  * Return: None
3161  */
3162 static void cache_station_stats_cb(struct stats_event *ev, void *cookie)
3163 {
3164 	struct hdd_adapter *adapter = cookie, *next_adapter = NULL;
3165 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
3166 	uint8_t vdev_id;
3167 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_DISPLAY_TXRX_STATS;
3168 	struct wlan_hdd_link_info *link_info;
3169 
3170 	if (!ev->vdev_summary_stats || !ev->vdev_chain_rssi ||
3171 	    !ev->peer_adv_stats || !ev->pdev_stats) {
3172 		hdd_debug("Invalid stats");
3173 		return;
3174 	}
3175 
3176 	vdev_id = ev->vdev_summary_stats->vdev_id;
3177 
3178 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
3179 					   dbgid) {
3180 		hdd_adapter_for_each_active_link_info(adapter, link_info) {
3181 			if (link_info->vdev_id != vdev_id)
3182 				continue;
3183 
3184 			copy_station_stats_to_adapter(link_info, ev);
3185 			wlan_hdd_get_peer_rx_rate_stats(link_info);
3186 
3187 			/* dev_put has to be done here */
3188 			hdd_adapter_dev_put_debug(adapter, dbgid);
3189 			if (next_adapter)
3190 				hdd_adapter_dev_put_debug(next_adapter, dbgid);
3191 			return;
3192 		}
3193 		hdd_adapter_dev_put_debug(adapter, dbgid);
3194 	}
3195 }
3196 
3197 #ifdef WLAN_FEATURE_11BE_MLO
3198 static QDF_STATUS
3199 wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter,
3200 			     struct request_info *req_info,
3201 			     tSirLLStatsGetReq *req)
3202 {
3203 	struct wlan_objmgr_peer *peer;
3204 	struct wlan_objmgr_vdev *vdev;
3205 	struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
3206 	struct mlo_stats_vdev_params *info = &req_info->ml_vdev_info;
3207 	int i;
3208 	uint32_t bmap = 0;
3209 	QDF_STATUS status;
3210 
3211 	req->is_mlo_req = wlan_vdev_mlme_get_is_mlo_vdev(
3212 					psoc, adapter->deflink->vdev_id);
3213 	status = mlo_get_mlstats_vdev_params(psoc, info,
3214 					     adapter->deflink->vdev_id);
3215 	if (QDF_IS_STATUS_ERROR(status))
3216 		return status;
3217 	for (i = 0; i < info->ml_vdev_count; i++) {
3218 		bmap |= (1 << info->ml_vdev_id[i]);
3219 
3220 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
3221 							    info->ml_vdev_id[i],
3222 							    WLAN_OSIF_STATS_ID);
3223 		if (!vdev) {
3224 			hdd_err("vdev object is NULL for vdev %d",
3225 				info->ml_vdev_id[i]);
3226 			return QDF_STATUS_E_INVAL;
3227 		}
3228 
3229 		peer = wlan_objmgr_vdev_try_get_bsspeer(vdev,
3230 							WLAN_OSIF_STATS_ID);
3231 		if (!peer) {
3232 			hdd_err("peer is null");
3233 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3234 			return QDF_STATUS_E_INVAL;
3235 		}
3236 
3237 		qdf_mem_copy(&(req_info->ml_peer_mac_addr[i][0]), peer->macaddr,
3238 			     QDF_MAC_ADDR_SIZE);
3239 
3240 		wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_STATS_ID);
3241 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3242 	}
3243 	req->mlo_vdev_id_bitmap = bmap;
3244 	return QDF_STATUS_SUCCESS;
3245 }
3246 #else
3247 static QDF_STATUS
3248 wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter,
3249 			     struct request_info *req_info,
3250 			     tSirLLStatsGetReq *req)
3251 {
3252 	return QDF_STATUS_SUCCESS;
3253 }
3254 #endif
3255 
3256 static QDF_STATUS
3257 wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info *link_info,
3258 					   tSirLLStatsGetReq *req)
3259 {
3260 	struct wlan_objmgr_peer *peer;
3261 	struct request_info info = {0};
3262 	struct wlan_objmgr_vdev *vdev;
3263 	struct hdd_adapter *adapter = link_info->adapter;
3264 	struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
3265 	bool is_mlo_vdev = false;
3266 	QDF_STATUS status;
3267 
3268 	if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req)
3269 		return QDF_STATUS_E_INVAL;
3270 
3271 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
3272 	if (!vdev)
3273 		return QDF_STATUS_E_INVAL;
3274 
3275 	info.cookie = adapter;
3276 	info.u.get_station_stats_cb = cache_station_stats_cb;
3277 	info.vdev_id = link_info->vdev_id;
3278 	is_mlo_vdev = wlan_vdev_mlme_get_is_mlo_vdev(psoc, link_info->vdev_id);
3279 	if (is_mlo_vdev) {
3280 		status = wlan_hdd_get_mlo_vdev_params(adapter, &info, req);
3281 		if (QDF_IS_STATUS_ERROR(status)) {
3282 			hdd_err("unable to get vdev params for mlo stats");
3283 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3284 			return status;
3285 		}
3286 	}
3287 
3288 	info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
3289 
3290 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_STATS_ID);
3291 	if (!peer) {
3292 		osif_err("peer is null");
3293 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3294 		return QDF_STATUS_E_INVAL;
3295 	}
3296 
3297 	qdf_mem_copy(info.peer_mac_addr, peer->macaddr, QDF_MAC_ADDR_SIZE);
3298 
3299 	wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_STATS_ID);
3300 
3301 	ucfg_mc_cp_stats_set_pending_req(psoc, TYPE_STATION_STATS, &info);
3302 
3303 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3304 	return QDF_STATUS_SUCCESS;
3305 }
3306 
3307 static void
3308 wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc,
3309 					     struct hdd_adapter *adapter)
3310 {
3311 	QDF_STATUS status;
3312 	struct request_info last_req = {0};
3313 	bool pending = false;
3314 
3315 	if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req)
3316 		return;
3317 
3318 	status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS,
3319 						  &last_req);
3320 	if (QDF_IS_STATUS_ERROR(status)) {
3321 		hdd_err("ucfg_mc_cp_stats_get_pending_req failed");
3322 		return;
3323 	}
3324 
3325 	ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_STATION_STATS,
3326 					   &last_req, &pending);
3327 }
3328 
3329 static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
3330 {
3331 	if (adapter->device_mode != QDF_STA_MODE)
3332 		return QDF_STATUS_SUCCESS;
3333 
3334 	if (!adapter->hdd_ctx->config) {
3335 		hdd_err("Invalid hdd config");
3336 		return QDF_STATUS_E_INVAL;
3337 	}
3338 
3339 	if (adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req) {
3340 		uint32_t stats_cached_duration;
3341 
3342 		stats_cached_duration =
3343 				qdf_system_ticks_to_msecs(qdf_system_ticks()) -
3344 				adapter->sta_stats_cached_timestamp;
3345 		if (qdf_atomic_read(&adapter->is_ll_stats_req_pending) ||
3346 		    (stats_cached_duration <=
3347 			adapter->hdd_ctx->config->sta_stats_cache_expiry_time))
3348 			return QDF_STATUS_E_ALREADY;
3349 	}
3350 
3351 	return QDF_STATUS_SUCCESS;
3352 }
3353 
3354 #else
3355 static inline QDF_STATUS
3356 wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info *link_info,
3357 					   tSirLLStatsGetReq *req)
3358 {
3359 	return QDF_STATUS_SUCCESS;
3360 }
3361 
3362 static void
3363 wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc,
3364 					     struct hdd_adapter *adapter)
3365 {
3366 }
3367 
3368 static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
3369 {
3370 	return QDF_STATUS_SUCCESS;
3371 }
3372 #endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
3373 
3374 static void wlan_hdd_send_mlo_ll_stats_to_user(struct hdd_adapter *adapter)
3375 {
3376 	if (!wlan_hdd_is_mlo_connection(adapter->deflink))
3377 		return;
3378 
3379 	wlan_hdd_send_mlo_ll_iface_stats_to_user(adapter);
3380 	wlan_hdd_send_mlo_ll_peer_stats_to_user(adapter);
3381 }
3382 
3383 static int wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info *link_info,
3384 				      tSirLLStatsGetReq *req)
3385 {
3386 	int ret = 0;
3387 	struct hdd_ll_stats_priv *priv;
3388 	struct hdd_ll_stats *stats = NULL;
3389 	struct osif_request *request;
3390 	qdf_list_node_t *ll_node;
3391 	QDF_STATUS status, vdev_req_status;
3392 	struct hdd_adapter *adapter = link_info->adapter;
3393 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3394 	void *cookie;
3395 	static const struct osif_request_params params = {
3396 		.priv_size = sizeof(*priv),
3397 		.timeout_ms = WLAN_WAIT_TIME_LL_STATS,
3398 		.dealloc = wlan_hdd_dealloc_ll_stats,
3399 	};
3400 
3401 	hdd_enter_dev(adapter->dev);
3402 
3403 	status = wlan_hdd_set_ll_stats_request_pending(adapter);
3404 	if (QDF_IS_STATUS_ERROR(status))
3405 		return qdf_status_to_os_return(status);
3406 
3407 	vdev_req_status = wlan_hdd_set_station_stats_request_pending(link_info,
3408 								     req);
3409 	if (QDF_IS_STATUS_ERROR(vdev_req_status))
3410 		hdd_nofl_debug("Requesting LL_STATS only");
3411 
3412 	/*
3413 	 * FW can send radio stats with multiple events and for the first event
3414 	 * host allocates memory in wma and processes the events, there is a
3415 	 * possibility that host receives first event and gets timed out, on
3416 	 * time out host frees the allocated memory. now if host receives
3417 	 * remaining events it will again allocate memory and processes the
3418 	 * stats, since this is not an allocation for new command, this will
3419 	 * lead to out of order processing of the next event and this memory
3420 	 * might not be freed, so free the already allocated memory from WMA
3421 	 * before issuing any new ll stats request free memory allocated for
3422 	 * previous command
3423 	 */
3424 	sme_radio_tx_mem_free();
3425 
3426 	request = osif_request_alloc(&params);
3427 	if (!request) {
3428 		hdd_err("Request Allocation Failure");
3429 		wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc,
3430 							     adapter);
3431 		return -ENOMEM;
3432 	}
3433 
3434 	cookie = osif_request_cookie(request);
3435 
3436 	priv = osif_request_priv(request);
3437 
3438 	priv->request_id = req->reqId;
3439 	priv->request_bitmap = req->paramIdMask;
3440 	priv->vdev_id = link_info->vdev_id;
3441 	priv->is_mlo_req = wlan_vdev_mlme_get_is_mlo_vdev(hdd_ctx->psoc,
3442 							  link_info->vdev_id);
3443 	if (priv->is_mlo_req)
3444 		priv->mlo_vdev_id_bitmap = req->mlo_vdev_id_bitmap;
3445 
3446 	qdf_spinlock_create(&priv->ll_stats_lock);
3447 	qdf_list_create(&priv->ll_stats_q, HDD_LINK_STATS_MAX);
3448 
3449 	status = sme_ll_stats_get_req(hdd_ctx->mac_handle, req, cookie);
3450 	if (QDF_IS_STATUS_ERROR(status)) {
3451 		hdd_err("sme_ll_stats_get_req Failed");
3452 		ret = qdf_status_to_os_return(status);
3453 		goto exit;
3454 	}
3455 	ret = osif_request_wait_for_response(request);
3456 	if (ret) {
3457 		adapter->ll_stats_failure_count++;
3458 		hdd_err("Target response timed out request id %d request bitmap 0x%x ll_stats failure count %d",
3459 			priv->request_id, priv->request_bitmap,
3460 			adapter->ll_stats_failure_count);
3461 		qdf_spin_lock(&priv->ll_stats_lock);
3462 		priv->request_bitmap = 0;
3463 		qdf_spin_unlock(&priv->ll_stats_lock);
3464 		sme_radio_tx_mem_free();
3465 		ret = -ETIMEDOUT;
3466 	} else {
3467 		if (QDF_IS_STATUS_SUCCESS(vdev_req_status)) {
3468 			hdd_update_station_stats_cached_timestamp(adapter);
3469 			hdd_update_link_state_cached_timestamp(adapter);
3470 		}
3471 
3472 		adapter->ll_stats_failure_count = 0;
3473 	}
3474 
3475 	qdf_spin_lock(&priv->ll_stats_lock);
3476 	status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node);
3477 	qdf_spin_unlock(&priv->ll_stats_lock);
3478 	while (QDF_IS_STATUS_SUCCESS(status)) {
3479 		stats =  qdf_container_of(ll_node, struct hdd_ll_stats,
3480 					  ll_stats_node);
3481 		wlan_hdd_handle_ll_stats(link_info, stats, ret);
3482 		qdf_mem_free(stats->result);
3483 		qdf_mem_free(stats);
3484 		qdf_spin_lock(&priv->ll_stats_lock);
3485 		status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node);
3486 		qdf_spin_unlock(&priv->ll_stats_lock);
3487 	}
3488 	qdf_list_destroy(&priv->ll_stats_q);
3489 
3490 	if (!ret && req->reqId != DEBUGFS_LLSTATS_REQID)
3491 		wlan_hdd_send_mlo_ll_stats_to_user(adapter);
3492 
3493 exit:
3494 	qdf_atomic_set(&adapter->is_ll_stats_req_pending, 0);
3495 	wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc, adapter);
3496 	hdd_exit();
3497 	osif_request_put(request);
3498 
3499 	if (adapter->ll_stats_failure_count >=
3500 					HDD_MAX_ALLOWED_LL_STATS_FAILURE) {
3501 		cds_trigger_recovery(QDF_STATS_REQ_TIMEDOUT);
3502 		adapter->ll_stats_failure_count = 0;
3503 	}
3504 
3505 	return ret;
3506 }
3507 
3508 int wlan_hdd_ll_stats_get(struct wlan_hdd_link_info *link_info,
3509 			  uint32_t req_id, uint32_t req_mask)
3510 {
3511 	int errno;
3512 	tSirLLStatsGetReq get_req;
3513 	struct hdd_adapter *adapter = link_info->adapter;
3514 
3515 	hdd_enter_dev(adapter->dev);
3516 
3517 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3518 		hdd_warn("Command not allowed in FTM mode");
3519 		return -EPERM;
3520 	}
3521 
3522 	if (hdd_cm_is_vdev_roaming(link_info)) {
3523 		hdd_debug("Roaming in progress, cannot process the request");
3524 		return -EBUSY;
3525 	}
3526 
3527 	if (!adapter->is_link_layer_stats_set) {
3528 		hdd_info("LL_STATs not set");
3529 		return -EINVAL;
3530 	}
3531 
3532 	get_req.reqId = req_id;
3533 	get_req.paramIdMask = req_mask;
3534 	get_req.staId = link_info->vdev_id;
3535 
3536 	rtnl_lock();
3537 	errno = wlan_hdd_send_ll_stats_req(link_info, &get_req);
3538 	rtnl_unlock();
3539 	if (errno)
3540 		hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
3541 			req_id, req_mask, link_info->vdev_id);
3542 
3543 	hdd_exit();
3544 
3545 	return errno;
3546 }
3547 
3548 /**
3549  * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
3550  * @wiphy: Pointer to wiphy
3551  * @wdev: Pointer to wdev
3552  * @data: Pointer to data
3553  * @data_len: Data length
3554  *
3555  * Return: int
3556  */
3557 static int
3558 __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
3559 				   struct wireless_dev *wdev,
3560 				   const void *data,
3561 				   int data_len)
3562 {
3563 	int ret;
3564 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3565 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
3566 	tSirLLStatsGetReq LinkLayerStatsGetReq;
3567 	struct net_device *dev = wdev->netdev;
3568 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3569 	struct wlan_hdd_link_info *link_info = adapter->deflink;
3570 
3571 	hdd_enter_dev(dev);
3572 
3573 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3574 		hdd_err("Command not allowed in FTM mode");
3575 		return -EPERM;
3576 	}
3577 
3578 	ret = wlan_hdd_validate_context(hdd_ctx);
3579 	if (0 != ret)
3580 		return -EINVAL;
3581 
3582 	if (!adapter->is_link_layer_stats_set) {
3583 		hdd_nofl_debug("is_link_layer_stats_set: %d",
3584 			       adapter->is_link_layer_stats_set);
3585 		return -EINVAL;
3586 	}
3587 
3588 	if (hdd_cm_is_vdev_roaming(link_info)) {
3589 		hdd_debug("Roaming in progress, cannot process the request");
3590 		return -EBUSY;
3591 	}
3592 
3593 	if (wlan_hdd_is_link_switch_in_progress(link_info)) {
3594 		hdd_debug("Link Switch in progress, can't process the request");
3595 		return -EBUSY;
3596 	}
3597 
3598 	if (wlan_cfg80211_nla_parse(tb_vendor,
3599 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
3600 				    (struct nlattr *)data, data_len,
3601 				    qca_wlan_vendor_ll_get_policy)) {
3602 		hdd_err("max attribute not present");
3603 		return -EINVAL;
3604 	}
3605 
3606 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
3607 		hdd_err("Request Id Not present");
3608 		return -EINVAL;
3609 	}
3610 
3611 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
3612 		hdd_err("Req Mask Not present");
3613 		return -EINVAL;
3614 	}
3615 
3616 	LinkLayerStatsGetReq.reqId =
3617 		nla_get_u32(tb_vendor
3618 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
3619 	LinkLayerStatsGetReq.paramIdMask =
3620 		nla_get_u32(tb_vendor
3621 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
3622 
3623 	LinkLayerStatsGetReq.staId = link_info->vdev_id;
3624 
3625 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
3626 		return -EINVAL;
3627 
3628 	ret = wlan_hdd_send_ll_stats_req(link_info, &LinkLayerStatsGetReq);
3629 	if (0 != ret) {
3630 		hdd_err("Failed to send LL stats request (id:%u)",
3631 			LinkLayerStatsGetReq.reqId);
3632 		return ret;
3633 	}
3634 
3635 	hdd_exit();
3636 	return 0;
3637 }
3638 
3639 /**
3640  * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
3641  * @wiphy: Pointer to wiphy
3642  * @wdev: Pointer to wdev
3643  * @data: Pointer to data
3644  * @data_len: Data length
3645  *
3646  * Return: 0 if success, non-zero for failure
3647  */
3648 int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
3649 				   struct wireless_dev *wdev,
3650 				   const void *data,
3651 				   int data_len)
3652 {
3653 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3654 	struct osif_vdev_sync *vdev_sync;
3655 	int errno;
3656 
3657 	errno = wlan_hdd_validate_context(hdd_ctx);
3658 	if (0 != errno)
3659 		return -EINVAL;
3660 
3661 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3662 	if (errno)
3663 		return errno;
3664 
3665 	errno = wlan_hdd_qmi_get_sync_resume();
3666 	if (errno) {
3667 		hdd_err("qmi sync resume failed: %d", errno);
3668 		goto end;
3669 	}
3670 
3671 	errno = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
3672 
3673 	wlan_hdd_qmi_put_suspend();
3674 
3675 end:
3676 	osif_vdev_sync_op_stop(vdev_sync);
3677 
3678 	return errno;
3679 }
3680 
3681 const struct
3682 nla_policy
3683 	qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
3684 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
3685 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
3686 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
3687 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
3688 };
3689 
3690 /**
3691  * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
3692  * @wiphy: Pointer to wiphy
3693  * @wdev: Pointer to wdev
3694  * @data: Pointer to data
3695  * @data_len: Data length
3696  *
3697  * Return: int
3698  */
3699 static int
3700 __wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
3701 				    struct wireless_dev *wdev,
3702 				    const void *data,
3703 				    int data_len)
3704 {
3705 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3706 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
3707 	tSirLLStatsClearReq LinkLayerStatsClearReq;
3708 	struct net_device *dev = wdev->netdev;
3709 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3710 	u32 statsClearReqMask;
3711 	u8 stopReq;
3712 	int errno;
3713 	QDF_STATUS status;
3714 	struct sk_buff *skb;
3715 
3716 	hdd_enter_dev(dev);
3717 
3718 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3719 		hdd_err("Command not allowed in FTM mode");
3720 		return -EPERM;
3721 	}
3722 
3723 	errno = wlan_hdd_validate_context(hdd_ctx);
3724 	if (errno)
3725 		return -EINVAL;
3726 
3727 	if (!adapter->is_link_layer_stats_set) {
3728 		hdd_warn("is_link_layer_stats_set : %d",
3729 			  adapter->is_link_layer_stats_set);
3730 		return -EINVAL;
3731 	}
3732 
3733 	if (wlan_cfg80211_nla_parse(tb_vendor,
3734 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
3735 				    (struct nlattr *)data, data_len,
3736 				    qca_wlan_vendor_ll_clr_policy)) {
3737 		hdd_err("STATS_CLR_MAX is not present");
3738 		return -EINVAL;
3739 	}
3740 
3741 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
3742 	    !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
3743 		hdd_err("Error in LL_STATS CLR CONFIG PARA");
3744 		return -EINVAL;
3745 	}
3746 
3747 	statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
3748 				    nla_get_u32(tb_vendor
3749 						[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
3750 
3751 	stopReq = LinkLayerStatsClearReq.stopReq =
3752 			  nla_get_u8(tb_vendor
3753 				     [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
3754 
3755 	/*
3756 	 * Shall take the request Id if the Upper layers pass. 1 For now.
3757 	 */
3758 	LinkLayerStatsClearReq.reqId = 1;
3759 
3760 	LinkLayerStatsClearReq.staId = adapter->deflink->vdev_id;
3761 
3762 	hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
3763 		LinkLayerStatsClearReq.reqId,
3764 		LinkLayerStatsClearReq.staId,
3765 		LinkLayerStatsClearReq.statsClearReqMask,
3766 		LinkLayerStatsClearReq.stopReq);
3767 
3768 	status = sme_ll_stats_clear_req(hdd_ctx->mac_handle,
3769 					&LinkLayerStatsClearReq);
3770 	if (QDF_IS_STATUS_ERROR(status)) {
3771 		hdd_err("stats clear request failed, %d", status);
3772 		return -EINVAL;
3773 	}
3774 
3775 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
3776 						       2 * sizeof(u32) +
3777 						       2 * NLMSG_HDRLEN);
3778 	if (!skb) {
3779 		hdd_err("skb allocation failed");
3780 		return -ENOMEM;
3781 	}
3782 
3783 	if (nla_put_u32(skb,
3784 			QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
3785 			statsClearReqMask) ||
3786 	    nla_put_u32(skb,
3787 			QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
3788 			stopReq)) {
3789 		hdd_err("LL_STATS_CLR put fail");
3790 		wlan_cfg80211_vendor_free_skb(skb);
3791 		return -EINVAL;
3792 	}
3793 
3794 	/* If the ask is to stop the stats collection
3795 	 * as part of clear (stopReq = 1), ensure
3796 	 * that no further requests of get go to the
3797 	 * firmware by having is_link_layer_stats_set set
3798 	 * to 0.  However it the stopReq as part of
3799 	 * the clear request is 0, the request to get
3800 	 * the statistics are honoured as in this case
3801 	 * the firmware is just asked to clear the
3802 	 * statistics.
3803 	 */
3804 	if (stopReq == 1)
3805 		adapter->is_link_layer_stats_set = false;
3806 
3807 	hdd_exit();
3808 
3809 	return wlan_cfg80211_vendor_cmd_reply(skb);
3810 }
3811 
3812 /**
3813  * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
3814  * @wiphy: Pointer to wiphy
3815  * @wdev: Pointer to wdev
3816  * @data: Pointer to data
3817  * @data_len: Data length
3818  *
3819  * Return: 0 if success, non-zero for failure
3820  */
3821 int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
3822 					struct wireless_dev *wdev,
3823 					const void *data,
3824 					int data_len)
3825 {
3826 	int errno;
3827 	struct osif_vdev_sync *vdev_sync;
3828 
3829 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3830 	if (errno)
3831 		return errno;
3832 
3833 	errno = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
3834 
3835 	osif_vdev_sync_op_stop(vdev_sync);
3836 
3837 	return errno;
3838 }
3839 
3840 /**
3841  * wlan_hdd_clear_link_layer_stats() - clear link layer stats
3842  * @adapter: pointer to adapter
3843  *
3844  * Wrapper function to clear link layer stats.
3845  * return - void
3846  */
3847 void wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter)
3848 {
3849 	tSirLLStatsClearReq link_layer_stats_clear_req;
3850 	mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle;
3851 
3852 	link_layer_stats_clear_req.statsClearReqMask = WIFI_STATS_IFACE_AC |
3853 		WIFI_STATS_IFACE_ALL_PEER | WIFI_STATS_IFACE_CONTENTION;
3854 	link_layer_stats_clear_req.stopReq = 0;
3855 	link_layer_stats_clear_req.reqId = 1;
3856 	link_layer_stats_clear_req.staId = adapter->deflink->vdev_id;
3857 	sme_ll_stats_clear_req(mac_handle, &link_layer_stats_clear_req);
3858 }
3859 
3860 /**
3861  * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
3862  * @wifi_peer_info: peer information
3863  * @vendor_event: buffer for vendor event
3864  *
3865  * Return: 0 success
3866  */
3867 static inline int
3868 hdd_populate_per_peer_ps_info(struct wifi_peer_info *wifi_peer_info,
3869 			      struct sk_buff *vendor_event)
3870 {
3871 	if (!wifi_peer_info) {
3872 		hdd_err("Invalid pointer to peer info.");
3873 		return -EINVAL;
3874 	}
3875 
3876 	if (nla_put_u32(vendor_event,
3877 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
3878 			wifi_peer_info->power_saving) ||
3879 	    nla_put(vendor_event,
3880 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
3881 		    QDF_MAC_ADDR_SIZE, &wifi_peer_info->peer_macaddr)) {
3882 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
3883 		return -EINVAL;
3884 	}
3885 	return 0;
3886 }
3887 
3888 /**
3889  * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
3890  * @data: stats for peer STA
3891  * @vendor_event: buffer for vendor event
3892  *
3893  * Return: 0 success
3894  */
3895 static int hdd_populate_wifi_peer_ps_info(struct wifi_peer_stat *data,
3896 					  struct sk_buff *vendor_event)
3897 {
3898 	uint32_t peer_num, i;
3899 	struct wifi_peer_info *wifi_peer_info;
3900 	struct nlattr *peer_info, *peers;
3901 
3902 	if (!data) {
3903 		hdd_err("Invalid pointer to Wifi peer stat.");
3904 		return -EINVAL;
3905 	}
3906 
3907 	peer_num = data->num_peers;
3908 	if (peer_num == 0) {
3909 		hdd_err("Peer number is zero.");
3910 		return -EINVAL;
3911 	}
3912 
3913 	if (nla_put_u32(vendor_event,
3914 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
3915 			peer_num)) {
3916 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
3917 		return -EINVAL;
3918 	}
3919 
3920 	peer_info = nla_nest_start(vendor_event,
3921 			       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
3922 	if (!peer_info) {
3923 		hdd_err("nla_nest_start failed");
3924 		return -EINVAL;
3925 	}
3926 
3927 	for (i = 0; i < peer_num; i++) {
3928 		wifi_peer_info = &data->peer_info[i];
3929 		peers = nla_nest_start(vendor_event, i);
3930 
3931 		if (!peers) {
3932 			hdd_err("nla_nest_start failed");
3933 			return -EINVAL;
3934 		}
3935 
3936 		if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
3937 			return -EINVAL;
3938 
3939 		nla_nest_end(vendor_event, peers);
3940 	}
3941 	nla_nest_end(vendor_event, peer_info);
3942 
3943 	return 0;
3944 }
3945 
3946 /**
3947  * hdd_populate_tx_failure_info() - populate TX failure info
3948  * @tx_fail: TX failure info
3949  * @skb: buffer for vendor event
3950  *
3951  * Return: 0 Success
3952  */
3953 static inline int
3954 hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
3955 			     struct sk_buff *skb)
3956 {
3957 	int status = 0;
3958 
3959 	if (!tx_fail || !skb)
3960 		return -EINVAL;
3961 
3962 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
3963 			tx_fail->tid) ||
3964 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
3965 			tx_fail->msdu_num) ||
3966 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
3967 			tx_fail->status)) {
3968 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
3969 		status = -EINVAL;
3970 	}
3971 
3972 	return status;
3973 }
3974 
3975 /**
3976  * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event
3977  * @cca: cca info array for all channels
3978  * @vendor_event: vendor event buffer
3979  *
3980  * Return: 0 Success, EINVAL failure
3981  */
3982 static int
3983 hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca,
3984 				   struct sk_buff *vendor_event)
3985 {
3986 	/* There might be no CCA info for a channel */
3987 	if (!cca)
3988 		return 0;
3989 
3990 	if (nla_put_u32(vendor_event,
3991 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
3992 			cca->idle_time) ||
3993 	    nla_put_u32(vendor_event,
3994 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
3995 			cca->tx_time) ||
3996 	    nla_put_u32(vendor_event,
3997 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
3998 			cca->rx_in_bss_time) ||
3999 	    nla_put_u32(vendor_event,
4000 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
4001 			cca->rx_out_bss_time) ||
4002 	    nla_put_u32(vendor_event,
4003 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
4004 			cca->rx_busy_time) ||
4005 	    nla_put_u32(vendor_event,
4006 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
4007 			cca->rx_in_bad_cond_time) ||
4008 	    nla_put_u32(vendor_event,
4009 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
4010 			cca->tx_in_bad_cond_time) ||
4011 	    nla_put_u32(vendor_event,
4012 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
4013 			cca->wlan_not_avail_time) ||
4014 	    nla_put_u32(vendor_event,
4015 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
4016 			cca->vdev_id)) {
4017 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4018 		return -EINVAL;
4019 	}
4020 	return 0;
4021 }
4022 
4023 /**
4024  * hdd_populate_wifi_signal_info - put chain signal info
4025  * @peer_signal: RF chain signal info
4026  * @skb: vendor event buffer
4027  *
4028  * Return: 0 Success, EINVAL failure
4029  */
4030 static int
4031 hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal,
4032 			      struct sk_buff *skb)
4033 {
4034 	uint32_t i, chain_count;
4035 	struct nlattr *chains, *att;
4036 
4037 	/* There might be no signal info for a peer */
4038 	if (!peer_signal)
4039 		return 0;
4040 
4041 	chain_count = peer_signal->num_chain < WIFI_MAX_CHAINS ?
4042 		      peer_signal->num_chain : WIFI_MAX_CHAINS;
4043 	if (nla_put_u32(skb,
4044 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
4045 			chain_count)) {
4046 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4047 		return -EINVAL;
4048 	}
4049 
4050 	att = nla_nest_start(skb,
4051 			     QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL);
4052 	if (!att) {
4053 		hdd_err("nla_nest_start failed");
4054 		return -EINVAL;
4055 	}
4056 
4057 	for (i = 0; i < chain_count; i++) {
4058 		chains = nla_nest_start(skb, i);
4059 
4060 		if (!chains) {
4061 			hdd_err("nla_nest_start failed");
4062 			return -EINVAL;
4063 		}
4064 
4065 		hdd_debug("SNR=%d, NF=%d, Rx=%d, Tx=%d",
4066 			  peer_signal->per_ant_snr[i],
4067 			  peer_signal->nf[i],
4068 			  peer_signal->per_ant_rx_mpdus[i],
4069 			  peer_signal->per_ant_tx_mpdus[i]);
4070 		if (nla_put_u32(skb,
4071 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
4072 				peer_signal->per_ant_snr[i]) ||
4073 		    nla_put_u32(skb,
4074 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
4075 				peer_signal->nf[i]) ||
4076 		    nla_put_u32(skb,
4077 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
4078 				peer_signal->per_ant_rx_mpdus[i]) ||
4079 		    nla_put_u32(skb,
4080 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
4081 				peer_signal->per_ant_tx_mpdus[i])) {
4082 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4083 			return -EINVAL;
4084 		}
4085 		nla_nest_end(skb, chains);
4086 	}
4087 	nla_nest_end(skb, att);
4088 
4089 	return 0;
4090 }
4091 
4092 /**
4093  * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info
4094  * @tx_stats: tx info
4095  * @skb: vendor event buffer
4096  *
4097  * Return: 0 Success, EINVAL failure
4098  */
4099 static int
4100 hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats,
4101 				 struct sk_buff *skb)
4102 {
4103 	uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay;
4104 
4105 	/* There might be no TX info for a peer */
4106 	if (!tx_stats)
4107 		return 0;
4108 
4109 	agg_size = tx_stats->mpdu_aggr_size;
4110 	succ_mcs = tx_stats->success_mcs;
4111 	fail_mcs = tx_stats->fail_mcs;
4112 	delay = tx_stats->delay;
4113 
4114 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
4115 			tx_stats->msdus) ||
4116 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
4117 			tx_stats->mpdus) ||
4118 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
4119 			tx_stats->ppdus) ||
4120 	    nla_put_u32(skb,
4121 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
4122 			tx_stats->bytes) ||
4123 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
4124 			tx_stats->drops) ||
4125 	    nla_put_u32(skb,
4126 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
4127 			tx_stats->drop_bytes) ||
4128 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
4129 			tx_stats->retries) ||
4130 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
4131 			tx_stats->failed) ||
4132 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
4133 			tx_stats->aggr_len) ||
4134 	    nla_put_u32(skb,
4135 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
4136 			tx_stats->success_mcs_len) ||
4137 	    nla_put_u32(skb,
4138 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
4139 			tx_stats->fail_mcs_len) ||
4140 	    nla_put_u32(skb,
4141 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
4142 			tx_stats->delay_len))
4143 		goto put_attr_fail;
4144 
4145 	if (agg_size) {
4146 		if (nla_put(skb,
4147 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
4148 			    tx_stats->aggr_len, agg_size))
4149 			goto put_attr_fail;
4150 	}
4151 
4152 	if (succ_mcs) {
4153 		if (nla_put(skb,
4154 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
4155 			    tx_stats->success_mcs_len, succ_mcs))
4156 			goto put_attr_fail;
4157 	}
4158 
4159 	if (fail_mcs) {
4160 		if (nla_put(skb,
4161 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
4162 			    tx_stats->fail_mcs_len, fail_mcs))
4163 			goto put_attr_fail;
4164 	}
4165 
4166 	if (delay) {
4167 		if (nla_put(skb,
4168 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
4169 			    tx_stats->delay_len, delay))
4170 			goto put_attr_fail;
4171 	}
4172 	return 0;
4173 
4174 put_attr_fail:
4175 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4176 	return -EINVAL;
4177 }
4178 
4179 /**
4180  * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info
4181  * @rx_stats: rx info
4182  * @skb: vendor event buffer
4183  *
4184  * Return: 0 Success, EINVAL failure
4185  */
4186 static int
4187 hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats,
4188 				 struct sk_buff *skb)
4189 {
4190 	uint32_t *mcs, *aggr;
4191 
4192 	/* There might be no RX info for a peer */
4193 	if (!rx_stats)
4194 		return 0;
4195 
4196 	aggr = rx_stats->mpdu_aggr;
4197 	mcs = rx_stats->mcs;
4198 
4199 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
4200 			rx_stats->mpdus) ||
4201 	    nla_put_u32(skb,
4202 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
4203 			rx_stats->bytes) ||
4204 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
4205 			rx_stats->ppdus) ||
4206 	    nla_put_u32(skb,
4207 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
4208 			rx_stats->ppdu_bytes) ||
4209 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
4210 			rx_stats->mpdu_lost) ||
4211 	    nla_put_u32(skb,
4212 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
4213 			rx_stats->mpdu_retry) ||
4214 	    nla_put_u32(skb,
4215 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
4216 			rx_stats->mpdu_dup) ||
4217 	    nla_put_u32(skb,
4218 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
4219 			rx_stats->mpdu_discard) ||
4220 	    nla_put_u32(skb,
4221 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
4222 			rx_stats->aggr_len) ||
4223 	    nla_put_u32(skb,
4224 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
4225 			rx_stats->mcs_len))
4226 		goto put_attr_fail;
4227 
4228 	if (aggr) {
4229 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
4230 			    rx_stats->aggr_len, aggr))
4231 			goto put_attr_fail;
4232 	}
4233 
4234 	if (mcs) {
4235 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
4236 			    rx_stats->mcs_len, mcs))
4237 			goto put_attr_fail;
4238 	}
4239 
4240 	return 0;
4241 
4242 put_attr_fail:
4243 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4244 	return -EINVAL;
4245 }
4246 
4247 /**
4248  * hdd_populate_wifi_wmm_ac_info() - put WMM AC info
4249  * @ac_stats: per AC stats
4250  * @skb: vendor event buffer
4251  *
4252  * Return: 0 Success, EINVAL failure
4253  */
4254 static int
4255 hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats,
4256 			      struct sk_buff *skb)
4257 {
4258 	struct nlattr *wmm;
4259 
4260 	wmm = nla_nest_start(skb, ac_stats->type);
4261 	if (!wmm)
4262 		goto nest_start_fail;
4263 
4264 	if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) ||
4265 	    hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb))
4266 		goto put_attr_fail;
4267 
4268 	nla_nest_end(skb, wmm);
4269 	return 0;
4270 
4271 nest_start_fail:
4272 	hdd_err("nla_nest_start failed");
4273 	return -EINVAL;
4274 
4275 put_attr_fail:
4276 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4277 	return -EINVAL;
4278 }
4279 
4280 /**
4281  * hdd_populate_wifi_ll_ext_peer_info() - put per peer info
4282  * @peers: peer stats
4283  * @skb: vendor event buffer
4284  *
4285  * Return: 0 Success, EINVAL failure
4286  */
4287 static int
4288 hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers,
4289 				   struct sk_buff *skb)
4290 {
4291 	uint32_t i;
4292 	struct nlattr *wmm_ac;
4293 
4294 	if (nla_put_u32(skb,
4295 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
4296 			peers->peer_id) ||
4297 	    nla_put_u32(skb,
4298 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
4299 			peers->vdev_id) ||
4300 	    nla_put_u32(skb,
4301 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
4302 			peers->sta_ps_inds) ||
4303 	    nla_put_u32(skb,
4304 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
4305 			peers->sta_ps_durs) ||
4306 	    nla_put_u32(skb,
4307 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
4308 			peers->rx_probe_reqs) ||
4309 	    nla_put_u32(skb,
4310 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
4311 			peers->rx_oth_mgmts) ||
4312 	    nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
4313 		    QDF_MAC_ADDR_SIZE, peers->mac_address) ||
4314 	    hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) {
4315 		hdd_err("put peer signal attr failed");
4316 		return -EINVAL;
4317 	}
4318 
4319 	wmm_ac = nla_nest_start(skb,
4320 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS);
4321 	if (!wmm_ac) {
4322 		hdd_err("nla_nest_start failed");
4323 		return -EINVAL;
4324 	}
4325 
4326 	for (i = 0; i < WLAN_MAX_AC; i++) {
4327 		if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) {
4328 			hdd_err("put WMM AC attr failed");
4329 			return -EINVAL;
4330 		}
4331 	}
4332 
4333 	nla_nest_end(skb, wmm_ac);
4334 	return 0;
4335 }
4336 
4337 /**
4338  * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats
4339  * @stats: link layer stats
4340  * @skb: vendor event buffer
4341  *
4342  * Return: 0 Success, EINVAL failure
4343  */
4344 static int
4345 hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats,
4346 			       struct sk_buff *skb)
4347 {
4348 	uint32_t i;
4349 	struct nlattr *peer, *peer_info, *channels, *channel_info;
4350 
4351 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
4352 			stats->trigger_cond_id) ||
4353 	    nla_put_u32(skb,
4354 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
4355 			stats->cca_chgd_bitmap) ||
4356 	    nla_put_u32(skb,
4357 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
4358 			stats->sig_chgd_bitmap) ||
4359 	    nla_put_u32(skb,
4360 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
4361 			stats->tx_chgd_bitmap) ||
4362 	    nla_put_u32(skb,
4363 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
4364 			stats->rx_chgd_bitmap) ||
4365 	    nla_put_u32(skb,
4366 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
4367 			stats->channel_num) ||
4368 	    nla_put_u32(skb,
4369 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
4370 			stats->peer_num)) {
4371 		goto put_attr_fail;
4372 	}
4373 
4374 	channels = nla_nest_start(skb,
4375 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS);
4376 	if (!channels) {
4377 		hdd_err("nla_nest_start failed");
4378 		return -EINVAL;
4379 	}
4380 
4381 	for (i = 0; i < stats->channel_num; i++) {
4382 		channel_info = nla_nest_start(skb, i);
4383 		if (!channel_info) {
4384 			hdd_err("nla_nest_start failed");
4385 			return -EINVAL;
4386 		}
4387 
4388 		if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb))
4389 			goto put_attr_fail;
4390 		nla_nest_end(skb, channel_info);
4391 	}
4392 	nla_nest_end(skb, channels);
4393 
4394 	peer_info = nla_nest_start(skb,
4395 				   QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER);
4396 	if (!peer_info) {
4397 		hdd_err("nla_nest_start failed");
4398 		return -EINVAL;
4399 	}
4400 
4401 	for (i = 0; i < stats->peer_num; i++) {
4402 		peer = nla_nest_start(skb, i);
4403 		if (!peer) {
4404 			hdd_err("nla_nest_start failed");
4405 			return -EINVAL;
4406 		}
4407 
4408 		if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i],
4409 						       skb))
4410 			goto put_attr_fail;
4411 		nla_nest_end(skb, peer);
4412 	}
4413 
4414 	nla_nest_end(skb, peer_info);
4415 	return 0;
4416 
4417 put_attr_fail:
4418 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4419 	return -EINVAL;
4420 }
4421 
4422 /**
4423  * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
4424  * @ctx: HDD context
4425  * @rsp: msg from FW
4426  *
4427  * This function is an extension of
4428  * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
4429  * monitoring parameters offloaded to NL data and send the same to the
4430  * kernel/upper layers.
4431  *
4432  * Return: None
4433  */
4434 void wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx,
4435 						     tSirLLStatsResults *rsp)
4436 {
4437 	struct hdd_context *hdd_ctx;
4438 	struct sk_buff *skb;
4439 	uint32_t param_id, index;
4440 	struct wlan_hdd_link_info *link_info;
4441 	struct wifi_peer_stat *peer_stats;
4442 	uint8_t *results;
4443 	int status;
4444 
4445 	hdd_enter();
4446 
4447 	if (!rsp) {
4448 		hdd_err("Invalid result.");
4449 		return;
4450 	}
4451 
4452 	hdd_ctx = hdd_handle_to_context(ctx);
4453 	status = wlan_hdd_validate_context(hdd_ctx);
4454 	if (0 != status)
4455 		return;
4456 
4457 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, rsp->ifaceId);
4458 	if (!link_info) {
4459 		hdd_err("vdev_id %d does not exist with host.", rsp->ifaceId);
4460 		return;
4461 	}
4462 
4463 	index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
4464 	skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
4465 					       LL_STATS_EVENT_BUF_SIZE +
4466 					       NLMSG_HDRLEN,
4467 					       index, GFP_KERNEL);
4468 	if (!skb) {
4469 		hdd_err("wlan_cfg80211_vendor_event_alloc failed.");
4470 		return;
4471 	}
4472 
4473 	results = rsp->results;
4474 	param_id = rsp->paramId;
4475 	hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %pK",
4476 		 rsp->paramId, rsp->ifaceId, rsp->results);
4477 	if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
4478 		peer_stats = (struct wifi_peer_stat *)results;
4479 		status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
4480 	} else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
4481 		struct sir_wifi_iface_tx_fail *tx_fail;
4482 
4483 		tx_fail = (struct sir_wifi_iface_tx_fail *)results;
4484 		status = hdd_populate_tx_failure_info(tx_fail, skb);
4485 	} else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
4486 		hdd_info("MAC counters stats");
4487 		status = hdd_populate_wifi_ll_ext_stats(
4488 				(struct sir_wifi_ll_ext_stats *)
4489 				rsp->results, skb);
4490 	} else {
4491 		hdd_info("Unknown link layer stats");
4492 		status = -EINVAL;
4493 	}
4494 
4495 	if (status == 0)
4496 		wlan_cfg80211_vendor_event(skb, GFP_KERNEL);
4497 	else
4498 		wlan_cfg80211_vendor_free_skb(skb);
4499 	hdd_exit();
4500 }
4501 
4502 const struct nla_policy
4503 qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = {
4504 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = {
4505 		.type = NLA_U32
4506 	},
4507 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = {
4508 		.type = NLA_U32
4509 	},
4510 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG] = {
4511 		.type = NLA_U32
4512 	},
4513 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID] = {
4514 		.type = NLA_U32
4515 	},
4516 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU] = {
4517 		.type = NLA_U32
4518 	},
4519 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS] = {
4520 		.type = NLA_U32
4521 	},
4522 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE] = {
4523 		.type = NLA_U32
4524 	},
4525 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS] = {
4526 		.type = NLA_U32
4527 	},
4528 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = {
4529 		.type = NLA_U32
4530 	},
4531 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE] = {
4532 		.type = NLA_U32
4533 	},
4534 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID] = {
4535 		.type = NLA_U32
4536 	},
4537 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID] = {
4538 		.type = NLA_U32
4539 	},
4540 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = {
4541 		.type = NLA_U32
4542 	},
4543 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = {
4544 		.type = NLA_U32
4545 	},
4546 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = {
4547 		.type = NLA_U32
4548 	},
4549 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = {
4550 		.type = NLA_U32
4551 	},
4552 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM] = {
4553 		.type = NLA_U32
4554 	},
4555 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM] = {
4556 		.type = NLA_U32
4557 	},
4558 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS] = {
4559 		.type = NLA_U32
4560 	},
4561 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER] = {
4562 		.type = NLA_U32
4563 	},
4564 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = {
4565 		.type = NLA_U32
4566 	},
4567 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = {
4568 		.type = NLA_U32
4569 	},
4570 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = {
4571 		.type = NLA_U32
4572 	},
4573 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = {
4574 		.type = NLA_U32
4575 	},
4576 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = {
4577 		.type = NLA_U32
4578 	},
4579 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = {
4580 		.type = NLA_U32
4581 	},
4582 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = {
4583 		.type = NLA_U32
4584 	},
4585 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = {
4586 		.type = NLA_U32
4587 	},
4588 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = {
4589 		.type = NLA_U32
4590 	},
4591 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM] = {
4592 		.type = NLA_U32
4593 	},
4594 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM] = {
4595 		.type = NLA_U32
4596 	},
4597 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM] = {
4598 		.type = NLA_U32
4599 	},
4600 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = {
4601 		.type = NLA_U32
4602 	},
4603 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = {
4604 		.type = NLA_U32
4605 	},
4606 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = {
4607 		.type = NLA_U32
4608 	},
4609 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE] = {
4610 		.type = NLA_U32
4611 	},
4612 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = {
4613 		.type = NLA_U32
4614 	},
4615 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = {
4616 		.type = NLA_U32
4617 	},
4618 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = {
4619 		.type = NLA_U32
4620 	},
4621 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = {
4622 		.type = NLA_U32
4623 	},
4624 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = {
4625 		.type = NLA_U32
4626 	},
4627 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = {
4628 		.type = NLA_U32
4629 	},
4630 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = {
4631 		.type = NLA_U32
4632 	},
4633 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = {
4634 		.type = NLA_U32
4635 	},
4636 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = {
4637 		.type = NLA_U32
4638 	},
4639 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM] = {
4640 		.type = NLA_U32
4641 	},
4642 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM] = {
4643 		.type = NLA_U32
4644 	},
4645 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = {
4646 		.type = NLA_U32
4647 	},
4648 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = {
4649 		.type = NLA_U32
4650 	},
4651 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = {
4652 		.type = NLA_U32
4653 	},
4654 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = {
4655 		.type = NLA_U32
4656 	},
4657 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = {
4658 		.type = NLA_U32
4659 	},
4660 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = {
4661 		.type = NLA_U32
4662 	},
4663 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = {
4664 		.type = NLA_U32
4665 	},
4666 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = {
4667 		.type = NLA_U32
4668 	},
4669 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME] = {
4670 		.type = NLA_U32
4671 	},
4672 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = {
4673 		.type = NLA_U32
4674 	},
4675 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = {
4676 		.type = NLA_U32
4677 	},
4678 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = {
4679 		.type = NLA_U32
4680 	},
4681 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = {
4682 		.type = NLA_U32
4683 	},
4684 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = {
4685 		.type = NLA_U32
4686 	},
4687 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = {
4688 		.type = NLA_U32
4689 	},
4690 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM] = {
4691 		.type = NLA_U32
4692 	},
4693 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL] = {
4694 		.type = NLA_U32
4695 	},
4696 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = {
4697 		.type = NLA_U32
4698 	},
4699 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = {
4700 		.type = NLA_U32
4701 	},
4702 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON] = {
4703 		.type = NLA_U32
4704 	},
4705 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON] = {
4706 		.type = NLA_U32
4707 	},
4708 };
4709 
4710 /**
4711  * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
4712  * @wiphy: wiphy handle
4713  * @wdev: wdev handle
4714  * @data: user layer input
4715  * @data_len: length of user layer input
4716  *
4717  * this function is called in ssr protected environment.
4718  *
4719  * return: 0 success, none zero for failure
4720  */
4721 static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
4722 						      struct wireless_dev *wdev,
4723 						      const void *data,
4724 						      int data_len)
4725 {
4726 	QDF_STATUS status;
4727 	int errno;
4728 	uint32_t period;
4729 	struct net_device *dev = wdev->netdev;
4730 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4731 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
4732 	struct sir_ll_ext_stats_threshold thresh = {0,};
4733 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1];
4734 
4735 	hdd_enter_dev(dev);
4736 
4737 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
4738 		hdd_warn("command not allowed in ftm mode");
4739 		return -EPERM;
4740 	}
4741 
4742 	errno = wlan_hdd_validate_context(hdd_ctx);
4743 	if (errno)
4744 		return -EPERM;
4745 
4746 	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX,
4747 				    (struct nlattr *)data, data_len,
4748 				    qca_wlan_vendor_ll_ext_policy)) {
4749 		hdd_err("maximum attribute not present");
4750 		return -EPERM;
4751 	}
4752 
4753 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) {
4754 		period = nla_get_u32(tb[
4755 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]);
4756 
4757 		if (period != 0 && period < LL_STATS_MIN_PERIOD)
4758 			period = LL_STATS_MIN_PERIOD;
4759 
4760 		/*
4761 		 * Only enable/disable counters.
4762 		 * Keep the last threshold settings.
4763 		 */
4764 		goto set_period;
4765 	}
4766 
4767 	/* global thresh is not enabled */
4768 	if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) {
4769 		thresh.global = false;
4770 		hdd_warn("global thresh is not set");
4771 	} else {
4772 		thresh.global_threshold = nla_get_u32(tb[
4773 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]);
4774 		thresh.global = true;
4775 		hdd_debug("globle thresh is %d", thresh.global_threshold);
4776 	}
4777 
4778 	if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) {
4779 		thresh.global = false;
4780 		hdd_warn("global thresh is not enabled");
4781 	} else {
4782 		thresh.global = nla_get_u32(tb[
4783 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]);
4784 		hdd_debug("global is %d", thresh.global);
4785 	}
4786 
4787 	thresh.enable_bitmap = false;
4788 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) {
4789 		thresh.tx_bitmap = nla_get_u32(tb[
4790 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]);
4791 		thresh.enable_bitmap = true;
4792 	}
4793 
4794 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) {
4795 		thresh.rx_bitmap = nla_get_u32(tb[
4796 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]);
4797 		thresh.enable_bitmap = true;
4798 	}
4799 
4800 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) {
4801 		thresh.cca_bitmap = nla_get_u32(tb[
4802 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]);
4803 		thresh.enable_bitmap = true;
4804 	}
4805 
4806 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) {
4807 		thresh.signal_bitmap = nla_get_u32(tb[
4808 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]);
4809 		thresh.enable_bitmap = true;
4810 	}
4811 
4812 	if (!thresh.global && !thresh.enable_bitmap) {
4813 		hdd_warn("threshold will be disabled.");
4814 		thresh.enable = false;
4815 
4816 		/* Just disable threshold */
4817 		goto set_thresh;
4818 	} else {
4819 		thresh.enable = true;
4820 	}
4821 
4822 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) {
4823 		thresh.tx.msdu = nla_get_u32(tb[
4824 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]);
4825 	}
4826 
4827 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) {
4828 		thresh.tx.mpdu = nla_get_u32(tb[
4829 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]);
4830 	}
4831 
4832 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) {
4833 		thresh.tx.ppdu = nla_get_u32(tb[
4834 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]);
4835 	}
4836 
4837 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) {
4838 		thresh.tx.bytes = nla_get_u32(tb[
4839 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]);
4840 	}
4841 
4842 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) {
4843 		thresh.tx.msdu_drop = nla_get_u32(
4844 			tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]);
4845 	}
4846 
4847 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) {
4848 		thresh.tx.byte_drop = nla_get_u32(tb[
4849 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]);
4850 	}
4851 
4852 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) {
4853 		thresh.tx.mpdu_retry = nla_get_u32(tb[
4854 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]);
4855 	}
4856 
4857 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) {
4858 		thresh.tx.mpdu_fail = nla_get_u32(tb[
4859 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]);
4860 	}
4861 
4862 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) {
4863 		thresh.tx.ppdu_fail = nla_get_u32(tb[
4864 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]);
4865 	}
4866 
4867 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) {
4868 		thresh.tx.aggregation = nla_get_u32(tb[
4869 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]);
4870 	}
4871 
4872 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) {
4873 		thresh.tx.succ_mcs = nla_get_u32(tb[
4874 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]);
4875 	}
4876 
4877 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) {
4878 		thresh.tx.fail_mcs = nla_get_u32(tb[
4879 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]);
4880 	}
4881 
4882 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) {
4883 		thresh.tx.delay = nla_get_u32(tb[
4884 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]);
4885 	}
4886 
4887 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) {
4888 		thresh.rx.mpdu = nla_get_u32(tb[
4889 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]);
4890 	}
4891 
4892 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) {
4893 		thresh.rx.bytes = nla_get_u32(tb[
4894 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]);
4895 	}
4896 
4897 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) {
4898 		thresh.rx.ppdu = nla_get_u32(tb[
4899 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]);
4900 	}
4901 
4902 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) {
4903 		thresh.rx.ppdu_bytes = nla_get_u32(tb[
4904 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]);
4905 	}
4906 
4907 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) {
4908 		thresh.rx.mpdu_lost = nla_get_u32(tb[
4909 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]);
4910 	}
4911 
4912 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) {
4913 		thresh.rx.mpdu_retry = nla_get_u32(tb[
4914 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]);
4915 	}
4916 
4917 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) {
4918 		thresh.rx.mpdu_dup = nla_get_u32(tb[
4919 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]);
4920 	}
4921 
4922 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) {
4923 		thresh.rx.mpdu_discard = nla_get_u32(tb[
4924 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]);
4925 	}
4926 
4927 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) {
4928 		thresh.rx.aggregation = nla_get_u32(tb[
4929 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]);
4930 	}
4931 
4932 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) {
4933 		thresh.rx.mcs = nla_get_u32(tb[
4934 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]);
4935 	}
4936 
4937 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) {
4938 		thresh.rx.ps_inds = nla_get_u32(tb[
4939 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]);
4940 	}
4941 
4942 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) {
4943 		thresh.rx.ps_durs = nla_get_u32(tb[
4944 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]);
4945 	}
4946 
4947 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) {
4948 		thresh.rx.probe_reqs = nla_get_u32(tb[
4949 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]);
4950 	}
4951 
4952 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) {
4953 		thresh.rx.other_mgmt = nla_get_u32(tb[
4954 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]);
4955 	}
4956 
4957 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) {
4958 		thresh.cca.idle_time = nla_get_u32(tb[
4959 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]);
4960 	}
4961 
4962 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) {
4963 		thresh.cca.tx_time = nla_get_u32(tb[
4964 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]);
4965 	}
4966 
4967 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) {
4968 		thresh.cca.rx_in_bss_time = nla_get_u32(tb[
4969 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]);
4970 	}
4971 
4972 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) {
4973 		thresh.cca.rx_out_bss_time = nla_get_u32(tb[
4974 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]);
4975 	}
4976 
4977 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) {
4978 		thresh.cca.rx_busy_time = nla_get_u32(tb[
4979 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]);
4980 	}
4981 
4982 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) {
4983 		thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[
4984 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]);
4985 	}
4986 
4987 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) {
4988 		thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[
4989 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]);
4990 	}
4991 
4992 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) {
4993 		thresh.cca.wlan_not_avail_time = nla_get_u32(tb[
4994 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]);
4995 	}
4996 
4997 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) {
4998 		thresh.signal.snr = nla_get_u32(tb[
4999 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]);
5000 	}
5001 
5002 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) {
5003 		thresh.signal.nf = nla_get_u32(tb[
5004 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]);
5005 	}
5006 
5007 set_thresh:
5008 	hdd_info("send thresh settings to target");
5009 	status = sme_ll_stats_set_thresh(hdd_ctx->mac_handle, &thresh);
5010 	if (QDF_IS_STATUS_ERROR(status)) {
5011 		hdd_err("sme_ll_stats_set_thresh failed.");
5012 		return -EINVAL;
5013 	}
5014 	return 0;
5015 
5016 set_period:
5017 	hdd_info("send period to target");
5018 	errno = wma_cli_set_command(adapter->deflink->vdev_id,
5019 				    wmi_pdev_param_stats_observation_period,
5020 				    period, PDEV_CMD);
5021 	if (errno) {
5022 		hdd_err("wma_cli_set_command set_period failed.");
5023 		return -EINVAL;
5024 	}
5025 	return 0;
5026 }
5027 
5028 /**
5029  * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
5030  * @wiphy: wiphy handle
5031  * @wdev: wdev handle
5032  * @data: user layer input
5033  * @data_len: length of user layer input
5034  *
5035  * return: 0 success, einval failure
5036  */
5037 int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
5038 					     struct wireless_dev *wdev,
5039 					     const void *data,
5040 					     int data_len)
5041 {
5042 	int errno;
5043 	struct osif_vdev_sync *vdev_sync;
5044 
5045 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5046 	if (errno)
5047 		return errno;
5048 
5049 	errno = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev,
5050 							   data, data_len);
5051 
5052 	osif_vdev_sync_op_stop(vdev_sync);
5053 
5054 	return errno;
5055 }
5056 
5057 #else
5058 static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
5059 {
5060 	return QDF_STATUS_SUCCESS;
5061 }
5062 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
5063 
5064 /**
5065  * __wlan_hdd_cfg80211_connected_chan_stats_request() - stats request for
5066  * currently connected channel
5067  * @wiphy: Pointer to wiphy
5068  * @wdev: Pointer to wdev
5069  * @data: Pointer to data
5070  * @data_len: Data length
5071  *
5072  * Return: int
5073  */
5074 static int
5075 __wlan_hdd_cfg80211_connected_chan_stats_request(struct wiphy *wiphy,
5076 						 struct wireless_dev *wdev,
5077 						 const void *data,
5078 						 int data_len)
5079 {
5080 	struct net_device *dev = wdev->netdev;
5081 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
5082 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
5083 	bool is_vdev_connected;
5084 	enum QDF_OPMODE mode;
5085 	QDF_STATUS status;
5086 
5087 	is_vdev_connected = hdd_cm_is_vdev_connected(adapter->deflink);
5088 	mode = adapter->device_mode;
5089 
5090 	if (mode != QDF_STA_MODE || !is_vdev_connected) {
5091 		hdd_debug("vdev %d: reject chan stats req, mode:%d, conn:%d",
5092 			  adapter->deflink->vdev_id, mode, is_vdev_connected);
5093 		return -EPERM;
5094 	}
5095 
5096 	status = ucfg_mlme_connected_chan_stats_request(hdd_ctx->psoc,
5097 					adapter->deflink->vdev_id);
5098 	return qdf_status_to_os_return(status);
5099 }
5100 
5101 int wlan_hdd_cfg80211_connected_chan_stats_req(struct wiphy *wiphy,
5102 					       struct wireless_dev *wdev,
5103 					       const void *data,
5104 					       int data_len)
5105 {
5106 	int errno;
5107 	struct osif_vdev_sync *vdev_sync;
5108 
5109 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5110 	if (errno)
5111 		return errno;
5112 
5113 	errno = __wlan_hdd_cfg80211_connected_chan_stats_request(wiphy, wdev,
5114 								 data,
5115 								 data_len);
5116 
5117 	osif_vdev_sync_op_stop(vdev_sync);
5118 
5119 	return errno;
5120 }
5121 
5122 #ifdef WLAN_FEATURE_STATS_EXT
5123 /**
5124  * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
5125  * @wiphy: Pointer to wiphy
5126  * @wdev: Pointer to wdev
5127  * @data: Pointer to data
5128  * @data_len: Data length
5129  *
5130  * Return: int
5131  */
5132 static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
5133 						 struct wireless_dev *wdev,
5134 						 const void *data,
5135 						 int data_len)
5136 {
5137 	tStatsExtRequestReq stats_ext_req;
5138 	struct net_device *dev = wdev->netdev;
5139 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
5140 	int ret_val;
5141 	QDF_STATUS status;
5142 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
5143 	ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC);
5144 	struct cdp_txrx_stats_req txrx_req = {0};
5145 
5146 	hdd_enter_dev(dev);
5147 
5148 	ret_val = wlan_hdd_validate_context(hdd_ctx);
5149 	if (ret_val)
5150 		return ret_val;
5151 
5152 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
5153 		hdd_err("Command not allowed in FTM mode");
5154 		return -EPERM;
5155 	}
5156 
5157 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
5158 		return -EINVAL;
5159 	/**
5160 	 * HTT_DBG_EXT_STATS_PDEV_RX
5161 	 */
5162 	txrx_req.stats = 2;
5163 	/* default value of secondary parameter is 0(mac_id) */
5164 	txrx_req.mac_id = 0;
5165 	status = cdp_txrx_stats_request(soc, adapter->deflink->vdev_id,
5166 					&txrx_req);
5167 	if (QDF_STATUS_SUCCESS != status) {
5168 		hdd_err_rl("Failed to get hw stats: %u", status);
5169 		ret_val = -EINVAL;
5170 	}
5171 
5172 	stats_ext_req.request_data_len = data_len;
5173 	stats_ext_req.request_data = (void *)data;
5174 
5175 	status = cdp_request_rx_hw_stats(soc, adapter->deflink->vdev_id);
5176 
5177 	if (QDF_STATUS_SUCCESS != status) {
5178 		hdd_err_rl("Failed to get hw stats: %u", status);
5179 		ret_val = -EINVAL;
5180 	}
5181 
5182 	status = sme_stats_ext_request(adapter->deflink->vdev_id,
5183 				       &stats_ext_req);
5184 
5185 	if (QDF_STATUS_SUCCESS != status) {
5186 		hdd_err_rl("Failed to get fw stats: %u", status);
5187 		ret_val = -EINVAL;
5188 	}
5189 
5190 	return ret_val;
5191 }
5192 
5193 /**
5194  * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
5195  * @wiphy: Pointer to wiphy
5196  * @wdev: Pointer to wdev
5197  * @data: Pointer to data
5198  * @data_len: Data length
5199  *
5200  * Return: int
5201  */
5202 int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
5203 					struct wireless_dev *wdev,
5204 					const void *data,
5205 					int data_len)
5206 {
5207 	int errno;
5208 	struct osif_vdev_sync *vdev_sync;
5209 
5210 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5211 	if (errno)
5212 		return errno;
5213 
5214 	errno = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
5215 						      data, data_len);
5216 
5217 	osif_vdev_sync_op_stop(vdev_sync);
5218 
5219 	return errno;
5220 }
5221 
5222 void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,
5223 					  struct stats_ext_event *data)
5224 {
5225 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
5226 	struct sk_buff *vendor_event;
5227 	int status;
5228 	int ret_val;
5229 	struct wlan_hdd_link_info *link_info;
5230 	enum qca_nl80211_vendor_subcmds_index index =
5231 		QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX;
5232 
5233 	status = wlan_hdd_validate_context(hdd_ctx);
5234 	if (status)
5235 		return;
5236 
5237 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, data->vdev_id);
5238 	if (!link_info) {
5239 		hdd_err("vdev_id %d does not exist with host", data->vdev_id);
5240 		return;
5241 	}
5242 
5243 	vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
5244 							data->event_data_len +
5245 							sizeof(uint32_t) +
5246 							NLMSG_HDRLEN +
5247 							NLMSG_HDRLEN,
5248 							index, GFP_KERNEL);
5249 	if (!vendor_event) {
5250 		hdd_err("wlan_cfg80211_vendor_event_alloc failed");
5251 		return;
5252 	}
5253 
5254 	ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
5255 			      link_info->adapter->dev->ifindex);
5256 	if (ret_val) {
5257 		hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
5258 		wlan_cfg80211_vendor_free_skb(vendor_event);
5259 
5260 		return;
5261 	}
5262 
5263 	ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
5264 			  data->event_data_len, data->event_data);
5265 
5266 	if (ret_val) {
5267 		hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
5268 		wlan_cfg80211_vendor_free_skb(vendor_event);
5269 
5270 		return;
5271 	}
5272 
5273 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
5274 
5275 }
5276 
5277 void
5278 wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,
5279 				      struct sir_sme_rx_aggr_hole_ind *pmsg)
5280 {
5281 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
5282 	int status;
5283 	uint32_t data_size, hole_info_size;
5284 	struct sk_buff *vendor_event;
5285 	enum qca_nl80211_vendor_subcmds_index index =
5286 		QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX;
5287 
5288 	status = wlan_hdd_validate_context(hdd_ctx);
5289 	if (0 != status)
5290 		return;
5291 
5292 	if (!pmsg) {
5293 		hdd_err("msg received here is null");
5294 		return;
5295 	}
5296 
5297 	hole_info_size = (pmsg->hole_cnt)*sizeof(pmsg->hole_info_array[0]);
5298 	data_size = sizeof(struct sir_sme_rx_aggr_hole_ind) + hole_info_size;
5299 
5300 	vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
5301 							data_size +
5302 							NLMSG_HDRLEN +
5303 							NLMSG_HDRLEN,
5304 							index, GFP_KERNEL);
5305 	if (!vendor_event) {
5306 		hdd_err("vendor_event_alloc failed for STATS_EXT2");
5307 		return;
5308 	}
5309 
5310 	if (nla_put_u32(vendor_event,
5311 			QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM,
5312 			pmsg->hole_cnt)) {
5313 		hdd_err("%s put fail",
5314 			"QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM");
5315 		wlan_cfg80211_vendor_free_skb(vendor_event);
5316 		return;
5317 	}
5318 	if (nla_put(vendor_event,
5319 		    QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO,
5320 		    hole_info_size,
5321 		    (void *)(pmsg->hole_info_array))) {
5322 		hdd_err("%s put fail",
5323 			"QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO");
5324 		wlan_cfg80211_vendor_free_skb(vendor_event);
5325 		return;
5326 	}
5327 
5328 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
5329 }
5330 
5331 #else
5332 void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,
5333 					  struct stats_ext_event *data)
5334 {
5335 }
5336 
5337 void
5338 wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,
5339 				      struct sir_sme_rx_aggr_hole_ind *pmsg)
5340 {
5341 }
5342 #endif /* End of WLAN_FEATURE_STATS_EXT */
5343 
5344 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
5345 /**
5346  * enum roam_event_rt_info_reset - Reset the notif param value of struct
5347  * roam_event_rt_info to 0
5348  * @ROAM_EVENT_RT_INFO_RESET: Reset the value to 0
5349  */
5350 enum roam_event_rt_info_reset {
5351 	ROAM_EVENT_RT_INFO_RESET = 0,
5352 };
5353 
5354 /**
5355  * struct roam_ap - Roamed/Failed AP info
5356  * @num_cand: number of candidate APs
5357  * @bssid:    BSSID of roamed/failed AP
5358  * @rssi:     RSSI of roamed/failed AP
5359  * @freq:     Frequency of roamed/failed AP
5360  */
5361 struct roam_ap {
5362 	uint32_t num_cand;
5363 	struct qdf_mac_addr bssid;
5364 	int8_t rssi;
5365 	uint16_t freq;
5366 };
5367 
5368 /**
5369  * hdd_get_roam_rt_stats_event_len() - calculate length of skb required for
5370  * sending roam events stats.
5371  * @roam_stats: pointer to roam_stats_event structure
5372  * @idx:          TLV index of roam stats event
5373  *
5374  * Return: length of skb
5375  */
5376 static uint32_t
5377 hdd_get_roam_rt_stats_event_len(struct roam_stats_event *roam_stats,
5378 				uint8_t idx)
5379 {
5380 	uint32_t len = 0;
5381 	uint8_t i = 0, num_cand = 0;
5382 
5383 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON  */
5384 	if (roam_stats->trigger[idx].present)
5385 		len += nla_total_size(sizeof(uint32_t));
5386 
5387 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON */
5388 	if (roam_stats->roam_event_param.roam_invoke_fail_reason)
5389 		len += nla_total_size(sizeof(uint32_t));
5390 
5391 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE */
5392 	if (roam_stats->roam_event_param.roam_scan_state)
5393 		len += nla_total_size(sizeof(uint8_t));
5394 
5395 	if (roam_stats->scan[idx].present) {
5396 		if (roam_stats->scan[idx].num_chan &&
5397 		    roam_stats->scan[idx].type == ROAM_STATS_SCAN_TYPE_PARTIAL)
5398 			for (i = 0; i < roam_stats->scan[idx].num_chan;)
5399 				i++;
5400 
5401 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST */
5402 		len += (nla_total_size(sizeof(uint32_t)) * i);
5403 
5404 		if (roam_stats->result[idx].present &&
5405 		    roam_stats->result[idx].fail_reason) {
5406 			num_cand++;
5407 		} else if (roam_stats->trigger[idx].present) {
5408 			for (i = 0; i < roam_stats->scan[idx].num_ap; i++) {
5409 				if (roam_stats->scan[idx].ap[i].type == 2)
5410 					num_cand++;
5411 			}
5412 		}
5413 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO */
5414 		len += NLA_HDRLEN;
5415 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID */
5416 		len += (nla_total_size(QDF_MAC_ADDR_SIZE) * num_cand);
5417 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI */
5418 		len += (nla_total_size(sizeof(int32_t)) * num_cand);
5419 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ */
5420 		len += (nla_total_size(sizeof(uint32_t)) * num_cand);
5421 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON */
5422 		len += (nla_total_size(sizeof(uint32_t)) * num_cand);
5423 	}
5424 
5425 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE */
5426 	if (len)
5427 		len += nla_total_size(sizeof(uint32_t));
5428 
5429 	return len;
5430 }
5431 
5432 #define SUBCMD_ROAM_EVENTS_INDEX \
5433 	QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS_INDEX
5434 #define ROAM_SCAN_FREQ_LIST \
5435 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST
5436 #define ROAM_INVOKE_FAIL_REASON \
5437 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON
5438 #define ROAM_SCAN_STATE         QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE
5439 #define ROAM_EVENTS_CANDIDATE   QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO
5440 #define CANDIDATE_BSSID \
5441 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID
5442 #define CANDIDATE_RSSI \
5443 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI
5444 #define CANDIDATE_FREQ \
5445 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ
5446 #define ROAM_FAIL_REASON \
5447 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON
5448 
5449 /**
5450  * roam_rt_stats_fill_scan_freq() - Fill the scan frequency list from the
5451  * roam stats event.
5452  * @vendor_event: pointer to sk_buff structure
5453  * @idx:          TLV index of roam stats event
5454  * @roam_stats:   pointer to roam_stats_event structure
5455  *
5456  * Return: none
5457  */
5458 static void
5459 roam_rt_stats_fill_scan_freq(struct sk_buff *vendor_event, uint8_t idx,
5460 			     struct roam_stats_event *roam_stats)
5461 {
5462 	struct nlattr *nl_attr;
5463 	uint8_t i;
5464 
5465 	nl_attr = nla_nest_start(vendor_event, ROAM_SCAN_FREQ_LIST);
5466 	if (!nl_attr) {
5467 		hdd_err("nla nest start fail");
5468 		kfree_skb(vendor_event);
5469 		return;
5470 	}
5471 	if (roam_stats->scan[idx].num_chan &&
5472 	    roam_stats->scan[idx].type == ROAM_STATS_SCAN_TYPE_PARTIAL) {
5473 		for (i = 0; i < roam_stats->scan[idx].num_chan; i++) {
5474 			if (nla_put_u32(vendor_event, i,
5475 					roam_stats->scan[idx].chan_freq[i])) {
5476 				hdd_err("failed to put freq at index %d", i);
5477 				kfree_skb(vendor_event);
5478 				return;
5479 			}
5480 		}
5481 	}
5482 	nla_nest_end(vendor_event, nl_attr);
5483 }
5484 
5485 /**
5486  * roam_rt_stats_fill_cand_info() - Fill the roamed/failed AP info from the
5487  * roam stats event.
5488  * @vendor_event: pointer to sk_buff structure
5489  * @idx:          TLV index of roam stats event
5490  * @roam_stats:   pointer to roam_stats_event structure
5491  *
5492  * Return: none
5493  */
5494 static void
5495 roam_rt_stats_fill_cand_info(struct sk_buff *vendor_event, uint8_t idx,
5496 			     struct roam_stats_event *roam_stats)
5497 {
5498 	struct nlattr *nl_attr, *nl_array;
5499 	struct roam_ap cand_ap = {0};
5500 	uint8_t i, num_cand = 0;
5501 
5502 	if (roam_stats->result[idx].present &&
5503 	    roam_stats->result[idx].fail_reason &&
5504 	    roam_stats->result[idx].fail_reason != ROAM_FAIL_REASON_UNKNOWN) {
5505 		num_cand++;
5506 		for (i = 0; i < roam_stats->scan[idx].num_ap; i++) {
5507 			if (roam_stats->scan[idx].ap[i].type == 0 &&
5508 			    qdf_is_macaddr_equal(&roam_stats->
5509 						 result[idx].fail_bssid,
5510 						 &roam_stats->
5511 						 scan[idx].ap[i].bssid)) {
5512 				qdf_copy_macaddr(&cand_ap.bssid,
5513 						 &roam_stats->
5514 						 scan[idx].ap[i].bssid);
5515 				cand_ap.rssi = roam_stats->scan[idx].ap[i].rssi;
5516 				cand_ap.freq = roam_stats->scan[idx].ap[i].freq;
5517 			}
5518 		}
5519 	} else if (roam_stats->trigger[idx].present) {
5520 		for (i = 0; i < roam_stats->scan[idx].num_ap; i++) {
5521 			if (roam_stats->scan[idx].ap[i].type == 2) {
5522 				num_cand++;
5523 				qdf_copy_macaddr(&cand_ap.bssid,
5524 						 &roam_stats->
5525 						 scan[idx].ap[i].bssid);
5526 				cand_ap.rssi = roam_stats->scan[idx].ap[i].rssi;
5527 				cand_ap.freq = roam_stats->scan[idx].ap[i].freq;
5528 			}
5529 		}
5530 	}
5531 
5532 	nl_array = nla_nest_start(vendor_event, ROAM_EVENTS_CANDIDATE);
5533 	if (!nl_array) {
5534 		hdd_err("nl array nest start fail");
5535 		kfree_skb(vendor_event);
5536 		return;
5537 	}
5538 	for (i = 0; i < num_cand; i++) {
5539 		nl_attr = nla_nest_start(vendor_event, i);
5540 		if (!nl_attr) {
5541 			hdd_err("nl attr nest start fail");
5542 			kfree_skb(vendor_event);
5543 			return;
5544 		}
5545 		if (nla_put(vendor_event, CANDIDATE_BSSID,
5546 			    sizeof(cand_ap.bssid), cand_ap.bssid.bytes)) {
5547 			hdd_err("%s put fail",
5548 				"ROAM_EVENTS_CANDIDATE_INFO_BSSID");
5549 			kfree_skb(vendor_event);
5550 			return;
5551 		}
5552 		if (nla_put_s32(vendor_event, CANDIDATE_RSSI, cand_ap.rssi)) {
5553 			hdd_err("%s put fail",
5554 				"ROAM_EVENTS_CANDIDATE_INFO_RSSI");
5555 			kfree_skb(vendor_event);
5556 			return;
5557 		}
5558 		if (nla_put_u32(vendor_event, CANDIDATE_FREQ, cand_ap.freq)) {
5559 			hdd_err("%s put fail",
5560 				"ROAM_EVENTS_CANDIDATE_INFO_FREQ");
5561 			kfree_skb(vendor_event);
5562 			return;
5563 		}
5564 		if (roam_stats->result[idx].present &&
5565 		    roam_stats->result[idx].fail_reason) {
5566 			if (nla_put_u32(vendor_event, ROAM_FAIL_REASON,
5567 					roam_stats->result[idx].fail_reason)) {
5568 				hdd_err("%s put fail",
5569 					"ROAM_EVENTS_CANDIDATE_FAIL_REASON");
5570 				kfree_skb(vendor_event);
5571 				return;
5572 			}
5573 		}
5574 		nla_nest_end(vendor_event, nl_attr);
5575 	}
5576 	nla_nest_end(vendor_event, nl_array);
5577 }
5578 
5579 void
5580 wlan_hdd_cfg80211_roam_events_callback(struct roam_stats_event *roam_stats,
5581 				       uint8_t idx)
5582 {
5583 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
5584 	int status;
5585 	uint32_t data_size, roam_event_type = 0;
5586 	struct sk_buff *vendor_event;
5587 	struct wlan_hdd_link_info *link_info;
5588 
5589 	status = wlan_hdd_validate_context(hdd_ctx);
5590 	if (status) {
5591 		hdd_err("Invalid hdd_ctx");
5592 		return;
5593 	}
5594 
5595 	if (!roam_stats) {
5596 		hdd_err("msg received here is null");
5597 		return;
5598 	}
5599 
5600 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, roam_stats->vdev_id);
5601 	if (!link_info) {
5602 		hdd_err("vdev_id %d does not exist with host",
5603 			roam_stats->vdev_id);
5604 		return;
5605 	}
5606 
5607 	data_size = hdd_get_roam_rt_stats_event_len(roam_stats, idx);
5608 	if (!data_size) {
5609 		hdd_err("No data requested");
5610 		return;
5611 	}
5612 
5613 	data_size += NLMSG_HDRLEN;
5614 	vendor_event =
5615 		wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
5616 						 &link_info->adapter->wdev,
5617 						 data_size,
5618 						 SUBCMD_ROAM_EVENTS_INDEX,
5619 						 GFP_KERNEL);
5620 
5621 	if (!vendor_event) {
5622 		hdd_err("vendor_event_alloc failed for ROAM_EVENTS_STATS");
5623 		return;
5624 	}
5625 
5626 	if (roam_stats->scan[idx].present && roam_stats->trigger[idx].present) {
5627 		roam_rt_stats_fill_scan_freq(vendor_event, idx, roam_stats);
5628 		roam_rt_stats_fill_cand_info(vendor_event, idx, roam_stats);
5629 	}
5630 
5631 	if (roam_stats->roam_event_param.roam_scan_state) {
5632 		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_ROAM_SCAN_STATE;
5633 		if (nla_put_u8(vendor_event, ROAM_SCAN_STATE,
5634 			       roam_stats->roam_event_param.roam_scan_state)) {
5635 			hdd_err("%s put fail",
5636 				"VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE");
5637 			wlan_cfg80211_vendor_free_skb(vendor_event);
5638 			return;
5639 		}
5640 		roam_stats->roam_event_param.roam_scan_state =
5641 						ROAM_EVENT_RT_INFO_RESET;
5642 	}
5643 	if (roam_stats->trigger[idx].present) {
5644 		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_TRIGGER_REASON;
5645 		if (nla_put_u32(vendor_event,
5646 				QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON,
5647 				roam_stats->trigger[idx].trigger_reason)) {
5648 			hdd_err("%s put fail",
5649 				"VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON");
5650 			wlan_cfg80211_vendor_free_skb(vendor_event);
5651 			return;
5652 		}
5653 	}
5654 	if (roam_stats->roam_event_param.roam_invoke_fail_reason) {
5655 		roam_event_type |=
5656 			QCA_WLAN_VENDOR_ROAM_EVENT_INVOKE_FAIL_REASON;
5657 		if (nla_put_u32(vendor_event, ROAM_INVOKE_FAIL_REASON,
5658 				roam_stats->
5659 				roam_event_param.roam_invoke_fail_reason)) {
5660 			hdd_err("%s put fail",
5661 				"VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON");
5662 			wlan_cfg80211_vendor_free_skb(vendor_event);
5663 			return;
5664 		}
5665 		roam_stats->roam_event_param.roam_invoke_fail_reason =
5666 						ROAM_EVENT_RT_INFO_RESET;
5667 	}
5668 	if (roam_stats->result[idx].present &&
5669 	    roam_stats->result[idx].fail_reason)
5670 		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_FAIL_REASON;
5671 
5672 	if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE,
5673 			roam_event_type)) {
5674 		hdd_err("%s put fail", "QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE");
5675 			wlan_cfg80211_vendor_free_skb(vendor_event);
5676 		return;
5677 	}
5678 
5679 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
5680 }
5681 
5682 #undef SUBCMD_ROAM_EVENTS_INDEX
5683 #undef ROAM_SCAN_FREQ_LIST
5684 #undef ROAM_INVOKE_FAIL_REASON
5685 #undef ROAM_SCAN_STATE
5686 #undef ROAM_EVENTS_CANDIDATE
5687 #undef CANDIDATE_BSSID
5688 #undef CANDIDATE_RSSI
5689 #undef CANDIDATE_FREQ
5690 #undef ROAM_FAIL_REASON
5691 #endif /* End of WLAN_FEATURE_ROAM_OFFLOAD */
5692 
5693 #ifdef LINKSPEED_DEBUG_ENABLED
5694 #define linkspeed_dbg(format, args...) pr_info(format, ## args)
5695 #else
5696 #define linkspeed_dbg(format, args...)
5697 #endif /* LINKSPEED_DEBUG_ENABLED */
5698 
5699 static void
5700 wlan_hdd_fill_per_link_summary_stats(tCsrSummaryStatsInfo *stats,
5701 				     struct station_info *info,
5702 				     struct wlan_hdd_link_info *link_info)
5703 {
5704 	uint8_t i;
5705 	uint32_t orig_cnt;
5706 	uint32_t orig_fail_cnt;
5707 	QDF_STATUS status;
5708 	uint8_t *peer_mac;
5709 	ol_txrx_soc_handle soc;
5710 	struct cdp_peer_stats *peer_stats;
5711 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
5712 
5713 	if (wlan_hdd_validate_context(hdd_ctx))
5714 		return;
5715 
5716 	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx))
5717 		return;
5718 
5719 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
5720 	if (!peer_stats)
5721 		return;
5722 
5723 	soc = cds_get_context(QDF_MODULE_ID_SOC);
5724 	peer_mac = link_info->session.station.conn_info.bssid.bytes;
5725 	status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
5726 						 peer_mac, peer_stats,
5727 						 CDP_WILD_PEER_TYPE,
5728 						 WLAN_MAX_MLD);
5729 
5730 	if (QDF_IS_STATUS_ERROR(status)) {
5731 		hdd_err("Unable to get per link peer stats for the peer: "
5732 			QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(peer_mac));
5733 		goto exit;
5734 	}
5735 
5736 	info->tx_retries = 0;
5737 	info->tx_failed = 0;
5738 
5739 	for (i = 0; i < WIFI_MAX_AC; ++i) {
5740 		info->tx_retries += stats->multiple_retry_cnt[i];
5741 		info->tx_failed += stats->fail_cnt[i];
5742 	}
5743 
5744 	orig_cnt = info->tx_retries;
5745 	orig_fail_cnt = info->tx_failed;
5746 	info->tx_retries = peer_stats->tx.retries_mpdu;
5747 	info->tx_failed += peer_stats->tx.mpdu_success_with_retries;
5748 	hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx retries adjust from %d to %d",
5749 		  QDF_MAC_ADDR_REF(peer_mac), orig_cnt, info->tx_retries);
5750 	hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx failed adjust from %d to %d",
5751 		  QDF_MAC_ADDR_REF(peer_mac), orig_fail_cnt, info->tx_failed);
5752 exit:
5753 	qdf_mem_free(peer_stats);
5754 }
5755 
5756 /**
5757  * wlan_hdd_fill_summary_stats() - populate station_info summary stats
5758  * @stats: summary stats to use as a source
5759  * @info: kernel station_info struct to use as a destination
5760  * @vdev_id: stats get from which vdev id
5761  *
5762  * Return: None
5763  */
5764 static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
5765 					struct station_info *info,
5766 					uint8_t vdev_id)
5767 {
5768 	int i;
5769 	struct cds_vdev_dp_stats dp_stats;
5770 	uint32_t orig_cnt;
5771 	uint32_t orig_fail_cnt;
5772 
5773 	info->rx_packets = stats->rx_frm_cnt;
5774 	info->tx_packets = 0;
5775 	info->tx_retries = 0;
5776 	info->tx_failed = 0;
5777 
5778 	for (i = 0; i < WIFI_MAX_AC; ++i) {
5779 		info->tx_packets += stats->tx_frm_cnt[i];
5780 		info->tx_retries += stats->multiple_retry_cnt[i];
5781 		info->tx_failed += stats->fail_cnt[i];
5782 	}
5783 
5784 	if (cds_dp_get_vdev_stats(vdev_id, &dp_stats)) {
5785 		orig_cnt = info->tx_retries;
5786 		orig_fail_cnt = info->tx_failed;
5787 		info->tx_retries = dp_stats.tx_retries_mpdu;
5788 		info->tx_failed += dp_stats.tx_mpdu_success_with_retries;
5789 		hdd_debug("vdev %d tx retries adjust from %d to %d",
5790 			  vdev_id, orig_cnt, info->tx_retries);
5791 		hdd_debug("tx failed adjust from %d to %d",
5792 			  orig_fail_cnt, info->tx_failed);
5793 	}
5794 
5795 	info->filled |= HDD_INFO_TX_PACKETS |
5796 			HDD_INFO_TX_RETRIES |
5797 			HDD_INFO_TX_FAILED;
5798 }
5799 
5800 /**
5801  * wlan_hdd_get_sap_stats() - get aggregate SAP stats
5802  * @link_info: Link info pointer in HDD adapter
5803  * @info: kernel station_info struct to populate
5804  *
5805  * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to
5806  * support "station dump" and "station get" for SAP vdevs, even though they
5807  * aren't technically stations.
5808  *
5809  * Return: errno
5810  */
5811 static int wlan_hdd_get_sap_stats(struct wlan_hdd_link_info *link_info,
5812 				  struct station_info *info)
5813 {
5814 	int ret;
5815 
5816 	ret = wlan_hdd_get_station_stats(link_info);
5817 	if (ret) {
5818 		hdd_err("Failed to get SAP stats; status:%d", ret);
5819 		return ret;
5820 	}
5821 
5822 	wlan_hdd_fill_summary_stats(&link_info->hdd_stats.summary_stat,
5823 				    info, link_info->vdev_id);
5824 
5825 	return 0;
5826 }
5827 
5828 /**
5829  * hdd_get_max_rate_legacy() - get max rate for legacy mode
5830  * @stainfo: stainfo pointer
5831  * @rssidx: rssi index
5832  *
5833  * This function will get max rate for legacy mode
5834  *
5835  * Return: max rate on success, otherwise 0
5836  */
5837 static uint32_t hdd_get_max_rate_legacy(struct hdd_station_info *stainfo,
5838 					uint8_t rssidx)
5839 {
5840 	uint32_t maxrate = 0;
5841 	/*Minimum max rate, 6Mbps*/
5842 	int maxidx = 12;
5843 	int i;
5844 
5845 	/* check supported rates */
5846 	if (stainfo->max_supp_idx != 0xff &&
5847 	    maxidx < stainfo->max_supp_idx)
5848 		maxidx = stainfo->max_supp_idx;
5849 
5850 	/* check extended rates */
5851 	if (stainfo->max_ext_idx != 0xff &&
5852 	    maxidx < stainfo->max_ext_idx)
5853 		maxidx = stainfo->max_ext_idx;
5854 
5855 	for (i = 0; i < QDF_ARRAY_SIZE(supported_data_rate); i++) {
5856 		if (supported_data_rate[i].beacon_rate_index == maxidx)
5857 			maxrate =
5858 				supported_data_rate[i].supported_rate[rssidx];
5859 	}
5860 
5861 	hdd_debug("maxrate %d", maxrate);
5862 
5863 	return maxrate;
5864 }
5865 
5866 /**
5867  * hdd_get_max_rate_ht() - get max rate for ht mode
5868  * @stainfo: stainfo pointer
5869  * @stats: fw txrx status pointer
5870  * @rate_flags: rate flags
5871  * @nss: number of streams
5872  * @maxrate: returned max rate buffer pointer
5873  * @max_mcs_idx: max mcs idx
5874  * @report_max: report max rate or actual rate
5875  *
5876  * This function will get max rate for ht mode
5877  *
5878  * Return: None
5879  */
5880 static void hdd_get_max_rate_ht(struct hdd_station_info *stainfo,
5881 				struct hdd_fw_txrx_stats *stats,
5882 				uint32_t rate_flags,
5883 				uint8_t nss,
5884 				uint32_t *maxrate,
5885 				uint8_t *max_mcs_idx,
5886 				bool report_max)
5887 {
5888 	struct index_data_rate_type *supported_mcs_rate;
5889 	uint32_t tmprate;
5890 	uint8_t flag = 0, mcsidx;
5891 	int8_t rssi = stats->rssi;
5892 	int mode;
5893 	int i;
5894 
5895 	if (rate_flags & TX_RATE_HT40)
5896 		mode = 1;
5897 	else
5898 		mode = 0;
5899 
5900 	if (rate_flags & TX_RATE_HT40)
5901 		flag |= 1;
5902 	if (rate_flags & TX_RATE_SGI)
5903 		flag |= 2;
5904 
5905 	supported_mcs_rate = (struct index_data_rate_type *)
5906 		((nss == 1) ? &supported_mcs_rate_nss1 :
5907 		 &supported_mcs_rate_nss2);
5908 
5909 	if (stainfo->max_mcs_idx == 0xff) {
5910 		hdd_err("invalid max_mcs_idx");
5911 		/* report real mcs idx */
5912 		mcsidx = stats->tx_rate.mcs;
5913 	} else {
5914 		mcsidx = stainfo->max_mcs_idx;
5915 	}
5916 
5917 	if (!report_max) {
5918 		for (i = 0; i < MAX_HT_MCS_INDEX && i < mcsidx; i++) {
5919 			if (rssi <= rssi_mcs_tbl[mode][i]) {
5920 				mcsidx = i;
5921 				break;
5922 			}
5923 		}
5924 		if (mcsidx < stats->tx_rate.mcs &&
5925 		    stats->tx_rate.mcs <= MAX_HT_MCS_INDEX)
5926 			mcsidx = stats->tx_rate.mcs;
5927 	}
5928 
5929 	if (mcsidx > MAX_HT_MCS_INDEX)
5930 		mcsidx = MAX_HT_MCS_INDEX;
5931 	tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
5932 
5933 	hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
5934 
5935 	*maxrate = tmprate;
5936 	*max_mcs_idx = mcsidx;
5937 }
5938 
5939 /**
5940  * hdd_get_max_rate_vht() - get max rate for vht mode
5941  * @stainfo: stainfo pointer
5942  * @stats: fw txrx status pointer
5943  * @rate_flags: rate flags
5944  * @nss: number of streams
5945  * @maxrate: returned max rate buffer pointer
5946  * @max_mcs_idx: max mcs idx
5947  * @report_max: report max rate or actual rate
5948  *
5949  * This function will get max rate for vht mode
5950  *
5951  * Return: None
5952  */
5953 static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo,
5954 				 struct hdd_fw_txrx_stats *stats,
5955 				 uint32_t rate_flags,
5956 				 uint8_t nss,
5957 				 uint32_t *maxrate,
5958 				 uint8_t *max_mcs_idx,
5959 				 bool report_max)
5960 {
5961 	struct index_vht_data_rate_type *supported_vht_mcs_rate;
5962 	uint32_t tmprate = 0;
5963 	uint32_t vht_max_mcs;
5964 	uint8_t flag = 0, mcsidx = INVALID_MCS_IDX;
5965 	int8_t rssi = stats->rssi;
5966 	int mode;
5967 	int i;
5968 
5969 	supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
5970 		((nss == 1) ?
5971 		 &supported_vht_mcs_rate_nss1 :
5972 		 &supported_vht_mcs_rate_nss2);
5973 
5974 	if (rate_flags & TX_RATE_VHT80)
5975 		mode = 2;
5976 	else if (rate_flags & TX_RATE_VHT40)
5977 		mode = 1;
5978 	else
5979 		mode = 0;
5980 
5981 	if (rate_flags &
5982 	    (TX_RATE_VHT20 | TX_RATE_VHT40 | TX_RATE_VHT80)) {
5983 		vht_max_mcs =
5984 			(enum data_rate_11ac_max_mcs)
5985 			(stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK);
5986 		if (rate_flags & TX_RATE_SGI)
5987 			flag |= 1;
5988 
5989 		if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) {
5990 			mcsidx = 7;
5991 		} else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) {
5992 			mcsidx = 8;
5993 		} else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) {
5994 			/*
5995 			 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
5996 			 * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6
5997 			 * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8
5998 			 */
5999 			if ((rate_flags & TX_RATE_VHT20) &&
6000 			    (nss != 3 && nss != 6))
6001 				mcsidx = 8;
6002 			else
6003 				mcsidx = 9;
6004 		} else {
6005 			hdd_err("invalid vht_max_mcs");
6006 			/* report real mcs idx */
6007 			mcsidx = stats->tx_rate.mcs;
6008 		}
6009 
6010 		if (!report_max) {
6011 			for (i = 0; i <= mcsidx && i < MAX_RSSI_MCS_INDEX; i++) {
6012 				if (rssi <= rssi_mcs_tbl[mode][i]) {
6013 					mcsidx = i;
6014 					break;
6015 				}
6016 			}
6017 			if (mcsidx < stats->tx_rate.mcs)
6018 				mcsidx = stats->tx_rate.mcs;
6019 		}
6020 
6021 		if (rate_flags & TX_RATE_VHT80)
6022 			tmprate =
6023 		    supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag];
6024 		else if (rate_flags & TX_RATE_VHT40)
6025 			tmprate =
6026 		    supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag];
6027 		else if (rate_flags & TX_RATE_VHT20)
6028 			tmprate =
6029 		    supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag];
6030 	}
6031 
6032 	hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
6033 
6034 	*maxrate = tmprate;
6035 	*max_mcs_idx = mcsidx;
6036 }
6037 
6038 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
6039 #if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC)
6040 static bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info,
6041 				enum tx_rate_info rate_flags,
6042 				uint8_t mcsidx,
6043 				uint8_t nss,
6044 				uint8_t rate_info_flag)
6045 {
6046 	if (rate_info_flag == RATE_INFO_FLAGS_EHT_MCS) {
6047 		rate_info->nss = nss;
6048 		rate_info->mcs = mcsidx;
6049 		rate_info->flags |= RATE_INFO_FLAGS_EHT_MCS;
6050 		if (rate_flags & TX_RATE_EHT320)
6051 			rate_info->bw = RATE_INFO_BW_320;
6052 		else if (rate_flags & TX_RATE_EHT160)
6053 			rate_info->bw = RATE_INFO_BW_160;
6054 		else if (rate_flags & TX_RATE_EHT80)
6055 			rate_info->bw = RATE_INFO_BW_80;
6056 		else if (rate_flags & TX_RATE_EHT40)
6057 			rate_info->bw = RATE_INFO_BW_40;
6058 		else if (rate_flags & TX_RATE_EHT20)
6059 			rate_info->bw = RATE_INFO_BW_20;
6060 
6061 		return true;
6062 	}
6063 
6064 	return false;
6065 }
6066 #else
6067 static inline bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info,
6068 				       enum tx_rate_info rate_flags,
6069 				       uint8_t mcsidx,
6070 				       uint8_t nss,
6071 				       uint8_t rate_info_flag)
6072 {
6073 	return false;
6074 }
6075 #endif
6076 /**
6077  * hdd_fill_bw_mcs() - fill ch width and mcs flags
6078  * @rate_info: pointer to struct rate_info
6079  * @rate_flags: HDD rate flags
6080  * @mcsidx: mcs index
6081  * @nss: number of streams
6082  * @rate_info_flag: rate info flags
6083  *
6084  * This function will fill ch width and mcs flags
6085  *
6086  * Return: None
6087  */
6088 static void hdd_fill_bw_mcs(struct rate_info *rate_info,
6089 			    enum tx_rate_info rate_flags,
6090 			    uint8_t mcsidx,
6091 			    uint8_t nss,
6092 			    uint8_t rate_info_flag)
6093 {
6094 	if (hdd_fill_eht_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6095 				rate_info_flag))
6096 		return;
6097 
6098 	if (rate_info_flag == RATE_INFO_FLAGS_HE_MCS) {
6099 		rate_info->nss = nss;
6100 		rate_info->mcs = mcsidx;
6101 		rate_info->flags |= RATE_INFO_FLAGS_HE_MCS;
6102 		if (rate_flags & TX_RATE_HE160)
6103 			rate_info->bw = RATE_INFO_BW_160;
6104 		else if (rate_flags & TX_RATE_HE80)
6105 			rate_info->bw = RATE_INFO_BW_80;
6106 		else if (rate_flags & TX_RATE_HE40)
6107 			rate_info->bw = RATE_INFO_BW_40;
6108 		else if (rate_flags & TX_RATE_HE20)
6109 			rate_info->bw = RATE_INFO_BW_20;
6110 	} else if (rate_info_flag == RATE_INFO_FLAGS_VHT_MCS) {
6111 		rate_info->nss = nss;
6112 		rate_info->mcs = mcsidx;
6113 		rate_info->flags |= RATE_INFO_FLAGS_VHT_MCS;
6114 		if (rate_flags & TX_RATE_VHT160)
6115 			rate_info->bw = RATE_INFO_BW_160;
6116 		else if (rate_flags & TX_RATE_VHT80)
6117 			rate_info->bw = RATE_INFO_BW_80;
6118 		else if (rate_flags & TX_RATE_VHT40)
6119 			rate_info->bw = RATE_INFO_BW_40;
6120 		else if (rate_flags & TX_RATE_VHT20)
6121 			rate_info->bw = RATE_INFO_BW_20;
6122 	} else {
6123 		rate_info->mcs = (nss - 1) << 3;
6124 		rate_info->mcs |= mcsidx;
6125 		rate_info->flags |= RATE_INFO_FLAGS_MCS;
6126 		if (rate_flags & TX_RATE_HT40)
6127 			rate_info->bw = RATE_INFO_BW_40;
6128 	}
6129 }
6130 #else
6131 /**
6132  * hdd_fill_bw_mcs() - fill ch width and mcs flags
6133  * @rate_info: pointer to struct rate_info
6134  * @rate_flags: HDD rate flags
6135  * @mcsidx: mcs index
6136  * @nss: number of streams
6137  * @rate_info_flag: rate info flags
6138  *
6139  * This function will fill ch width and mcs flags
6140  *
6141  * Return: None
6142  */
6143 static void hdd_fill_bw_mcs(struct rate_info *rate_info,
6144 			    enum tx_rate_info rate_flags,
6145 			    uint8_t mcsidx,
6146 			    uint8_t nss,
6147 			    uint8_t rate_info_flag)
6148 {
6149 	if (rate_info_flag == RATE_INFO_FLAGS_VHT_MCS) {
6150 		rate_info->nss = nss;
6151 		rate_info->mcs = mcsidx;
6152 		rate_info->flags |= RATE_INFO_FLAGS_VHT_MCS;
6153 		if (rate_flags & TX_RATE_VHT80)
6154 			rate_info->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
6155 		else if (rate_flags & TX_RATE_VHT40)
6156 			rate_info->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
6157 		else if (rate_flags & TX_RATE_VHT20)
6158 			rate_info->bw = RATE_INFO_BW_20;
6159 	} else {
6160 		rate_info->mcs = (nss - 1) << 3;
6161 		rate_info->mcs |= mcsidx;
6162 		rate_info->flags |= RATE_INFO_FLAGS_MCS;
6163 		if (rate_flags & TX_RATE_HT40)
6164 			rate_info->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
6165 	}
6166 }
6167 #endif
6168 
6169 #if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC)
6170 static void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info,
6171 					 uint32_t rate_flags, uint8_t mcsidx,
6172 					 uint8_t nss)
6173 {
6174 	if (rate_flags &
6175 			(TX_RATE_EHT320 |
6176 			 TX_RATE_EHT160 |
6177 			 TX_RATE_EHT80 |
6178 			 TX_RATE_EHT40 |
6179 			 TX_RATE_EHT20)) {
6180 		hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6181 				RATE_INFO_FLAGS_EHT_MCS);
6182 	}
6183 }
6184 #else
6185 static inline void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info,
6186 						uint32_t rate_flags,
6187 						uint8_t mcsidx,
6188 						uint8_t nss)
6189 {
6190 }
6191 #endif
6192 
6193 /**
6194  * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
6195  * @sinfo: pointer to struct station_info
6196  * @rate_flags: HDD rate flags
6197  * @mcsidx: mcs index
6198  * @nss: number of streams
6199  * @rate: data rate (kbps)
6200  * @is_tx: flag to indicate whether it is tx or rx
6201  *
6202  * This function will fill rate info of sinfo struct
6203  *
6204  * Return: None
6205  */
6206 static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
6207 				     uint32_t rate_flags,
6208 				     uint8_t mcsidx,
6209 				     uint8_t nss,
6210 				     uint32_t rate,
6211 				     bool is_tx)
6212 {
6213 	struct rate_info *rate_info;
6214 
6215 	if (is_tx)
6216 		rate_info = &sinfo->txrate;
6217 	else
6218 		rate_info = &sinfo->rxrate;
6219 
6220 	if (rate_flags & TX_RATE_LEGACY) {
6221 		/* provide to the UI in units of 100kbps */
6222 		rate_info->legacy = rate;
6223 	} else {
6224 		/* must be MCS */
6225 		hdd_fill_sinfo_eht_rate_info(rate_info, rate_flags, mcsidx,
6226 					     nss);
6227 
6228 		if (rate_flags &
6229 				(TX_RATE_HE160 |
6230 				 TX_RATE_HE80 |
6231 				 TX_RATE_HE40 |
6232 				 TX_RATE_HE20)) {
6233 			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6234 					RATE_INFO_FLAGS_HE_MCS);
6235 		}
6236 		if (rate_flags &
6237 				(TX_RATE_VHT160 |
6238 				 TX_RATE_VHT80 |
6239 				 TX_RATE_VHT40 |
6240 				 TX_RATE_VHT20)) {
6241 			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6242 					RATE_INFO_FLAGS_VHT_MCS);
6243 		}
6244 		if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) {
6245 			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6246 					RATE_INFO_FLAGS_MCS);
6247 		}
6248 		if (rate_flags & TX_RATE_SGI) {
6249 			if (!(rate_info->flags & RATE_INFO_FLAGS_VHT_MCS))
6250 				rate_info->flags |= RATE_INFO_FLAGS_MCS;
6251 			rate_info->flags |= RATE_INFO_FLAGS_SHORT_GI;
6252 		}
6253 	}
6254 
6255 	hdd_debug("flag %x mcs %d legacy %d nss %d",
6256 		  rate_info->flags,
6257 		  rate_info->mcs,
6258 		  rate_info->legacy,
6259 		  rate_info->nss);
6260 
6261 	if (is_tx)
6262 		sinfo->filled |= HDD_INFO_TX_BITRATE;
6263 	else
6264 		sinfo->filled |= HDD_INFO_RX_BITRATE;
6265 }
6266 
6267 /**
6268  * hdd_fill_sta_flags() - fill sta flags of sinfo
6269  * @sinfo: station_info struct pointer
6270  * @stainfo: stainfo pointer
6271  *
6272  * This function will fill sta flags of sinfo
6273  *
6274  * Return: None
6275  */
6276 static void hdd_fill_sta_flags(struct station_info *sinfo,
6277 			       struct hdd_station_info *stainfo)
6278 {
6279 	sinfo->sta_flags.mask = NL80211_STA_FLAG_WME;
6280 
6281 	if (stainfo->is_qos_enabled)
6282 		sinfo->sta_flags.set |= NL80211_STA_FLAG_WME;
6283 	else
6284 		sinfo->sta_flags.set &= ~NL80211_STA_FLAG_WME;
6285 
6286 	sinfo->filled |= HDD_INFO_STA_FLAGS;
6287 }
6288 
6289 /**
6290  * hdd_fill_per_chain_avg_signal() - fill per chain avg rssi of sinfo
6291  * @sinfo: station_info struct pointer
6292  * @stainfo: stainfo pointer
6293  *
6294  * This function will fill per chain avg rssi of sinfo
6295  *
6296  * Return: None
6297  */
6298 static void hdd_fill_per_chain_avg_signal(struct station_info *sinfo,
6299 					  struct hdd_station_info *stainfo)
6300 {
6301 	bool rssi_stats_valid = false;
6302 	uint8_t i;
6303 
6304 	sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
6305 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
6306 		sinfo->chain_signal_avg[i] = stainfo->peer_rssi_per_chain[i];
6307 		sinfo->chains |= 1 << i;
6308 		if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
6309 		    sinfo->chain_signal_avg[i] != 0)
6310 			sinfo->signal_avg = sinfo->chain_signal_avg[i];
6311 
6312 		if (sinfo->chain_signal_avg[i])
6313 			rssi_stats_valid = true;
6314 	}
6315 
6316 	if (rssi_stats_valid) {
6317 		sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG;
6318 		sinfo->filled |= HDD_INFO_SIGNAL_AVG;
6319 	}
6320 }
6321 
6322 /**
6323  * hdd_fill_rate_info() - fill rate info of sinfo
6324  * @psoc: psoc context
6325  * @sinfo: station_info struct pointer
6326  * @stainfo: stainfo pointer
6327  * @stats: fw txrx status pointer
6328  *
6329  * This function will fill rate info of sinfo
6330  *
6331  * Return: None
6332  */
6333 static void hdd_fill_rate_info(struct wlan_objmgr_psoc *psoc,
6334 			       struct station_info *sinfo,
6335 			       struct hdd_station_info *stainfo,
6336 			       struct hdd_fw_txrx_stats *stats)
6337 {
6338 	enum tx_rate_info rate_flags;
6339 	uint8_t mcsidx = 0xff;
6340 	uint32_t tx_rate, rx_rate, maxrate, tmprate;
6341 	int rssidx;
6342 	int nss = 1;
6343 	int link_speed_rssi_high = 0;
6344 	int link_speed_rssi_mid = 0;
6345 	int link_speed_rssi_low = 0;
6346 	uint32_t link_speed_rssi_report = 0;
6347 
6348 	ucfg_mlme_stats_get_cfg_values(psoc,
6349 				       &link_speed_rssi_high,
6350 				       &link_speed_rssi_mid,
6351 				       &link_speed_rssi_low,
6352 				       &link_speed_rssi_report);
6353 
6354 	hdd_debug("reportMaxLinkSpeed %d", link_speed_rssi_report);
6355 
6356 	/* convert to 100kbps expected in rate table */
6357 	tx_rate = stats->tx_rate.rate / 100;
6358 	rate_flags = stainfo->rate_flags;
6359 	if (!(rate_flags & TX_RATE_LEGACY)) {
6360 		nss = stainfo->nss;
6361 		if (ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
6362 			/* Get current rate flags if report actual */
6363 			if (stats->tx_rate.rate_flags)
6364 				rate_flags =
6365 					stats->tx_rate.rate_flags;
6366 			nss = stats->tx_rate.nss;
6367 		}
6368 
6369 		if (stats->tx_rate.mcs == INVALID_MCS_IDX)
6370 			rate_flags = TX_RATE_LEGACY;
6371 	}
6372 
6373 	if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
6374 		/* we do not want to necessarily report the current speed */
6375 		if (ucfg_mlme_stats_is_link_speed_report_max(psoc)) {
6376 			/* report the max possible speed */
6377 			rssidx = 0;
6378 		} else if (ucfg_mlme_stats_is_link_speed_report_max_scaled(
6379 					psoc)) {
6380 			/* report the max possible speed with RSSI scaling */
6381 			if (stats->rssi >= link_speed_rssi_high) {
6382 				/* report the max possible speed */
6383 				rssidx = 0;
6384 			} else if (stats->rssi >= link_speed_rssi_mid) {
6385 				/* report middle speed */
6386 				rssidx = 1;
6387 			} else if (stats->rssi >= link_speed_rssi_low) {
6388 				/* report low speed */
6389 				rssidx = 2;
6390 			} else {
6391 				/* report actual speed */
6392 				rssidx = 3;
6393 			}
6394 		} else {
6395 			/* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
6396 			hdd_err("Invalid value for reportMaxLinkSpeed: %u",
6397 				link_speed_rssi_report);
6398 			rssidx = 0;
6399 		}
6400 
6401 		maxrate = hdd_get_max_rate_legacy(stainfo, rssidx);
6402 
6403 		/*
6404 		 * Get MCS Rate Set --
6405 		 * Only if we are connected in non legacy mode and not
6406 		 * reporting actual speed
6407 		 */
6408 		if ((rssidx != 3) &&
6409 		    !(rate_flags & TX_RATE_LEGACY)) {
6410 			hdd_get_max_rate_vht(stainfo,
6411 					     stats,
6412 					     rate_flags,
6413 					     nss,
6414 					     &tmprate,
6415 					     &mcsidx,
6416 					     rssidx == 0);
6417 
6418 			if (maxrate < tmprate &&
6419 			    mcsidx != INVALID_MCS_IDX)
6420 				maxrate = tmprate;
6421 
6422 			if (mcsidx == INVALID_MCS_IDX)
6423 				hdd_get_max_rate_ht(stainfo,
6424 						    stats,
6425 						    rate_flags,
6426 						    nss,
6427 						    &tmprate,
6428 						    &mcsidx,
6429 						    rssidx == 0);
6430 
6431 			if (maxrate < tmprate &&
6432 			    mcsidx != INVALID_MCS_IDX)
6433 				maxrate = tmprate;
6434 		} else if (!(rate_flags & TX_RATE_LEGACY)) {
6435 			maxrate = tx_rate;
6436 			mcsidx = stats->tx_rate.mcs;
6437 		}
6438 
6439 		/*
6440 		 * make sure we report a value at least as big as our
6441 		 * current rate
6442 		 */
6443 		if (maxrate < tx_rate || maxrate == 0) {
6444 			maxrate = tx_rate;
6445 			if (!(rate_flags & TX_RATE_LEGACY)) {
6446 				mcsidx = stats->tx_rate.mcs;
6447 				/*
6448 				 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
6449 				 * - MCS9 is valid for VHT20 when Nss = 3 or
6450 				 *   Nss = 6
6451 				 * - MCS9 is not valid for VHT20 when
6452 				 *   Nss = 1,2,4,5,7,8
6453 				 */
6454 				if ((rate_flags & TX_RATE_VHT20) &&
6455 				    (mcsidx > 8) &&
6456 				    (nss != 3 && nss != 6))
6457 					mcsidx = 8;
6458 			}
6459 		}
6460 	} else {
6461 		/* report current rate instead of max rate */
6462 		maxrate = tx_rate;
6463 		if (!(rate_flags & TX_RATE_LEGACY))
6464 			mcsidx = stats->tx_rate.mcs;
6465 	}
6466 
6467 	hdd_fill_sinfo_rate_info(sinfo, rate_flags, mcsidx, nss,
6468 				 maxrate, true);
6469 
6470 	/* convert to 100kbps expected in rate table */
6471 	rx_rate = stats->rx_rate.rate / 100;
6472 
6473 	/* report current rx rate*/
6474 	rate_flags = stainfo->rate_flags;
6475 	if (!(rate_flags & TX_RATE_LEGACY)) {
6476 		if (stats->rx_rate.rate_flags)
6477 			rate_flags = stats->rx_rate.rate_flags;
6478 		nss = stats->rx_rate.nss;
6479 		if (stats->rx_rate.mcs == INVALID_MCS_IDX)
6480 			rate_flags = TX_RATE_LEGACY;
6481 	}
6482 	if (!(rate_flags & TX_RATE_LEGACY))
6483 		mcsidx = stats->rx_rate.mcs;
6484 
6485 	hdd_fill_sinfo_rate_info(sinfo, rate_flags, mcsidx, nss,
6486 				 rx_rate, false);
6487 
6488 	sinfo->expected_throughput = stainfo->max_phy_rate;
6489 	sinfo->filled |= HDD_INFO_EXPECTED_THROUGHPUT;
6490 }
6491 
6492 /**
6493  * wlan_hdd_fill_station_info() - fill station_info struct
6494  * @psoc: psoc context
6495  * @adapter: The HDD adapter structure
6496  * @sinfo: station_info struct pointer
6497  * @stainfo: stainfo pointer
6498  * @stats: fw txrx status pointer
6499  *
6500  * This function will fill station_info struct
6501  *
6502  * Return: None
6503  */
6504 static void wlan_hdd_fill_station_info(struct wlan_objmgr_psoc *psoc,
6505 				       struct hdd_adapter *adapter,
6506 				       struct station_info *sinfo,
6507 				       struct hdd_station_info *stainfo,
6508 				       struct hdd_fw_txrx_stats *stats)
6509 {
6510 	qdf_time_t curr_time, dur;
6511 	struct cdp_peer_stats *peer_stats;
6512 	QDF_STATUS status;
6513 
6514 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
6515 	if (!peer_stats)
6516 		return;
6517 
6518 	status =
6519 		cdp_host_get_peer_stats(cds_get_context(QDF_MODULE_ID_SOC),
6520 					adapter->deflink->vdev_id,
6521 					stainfo->sta_mac.bytes,
6522 					peer_stats);
6523 
6524 	if (QDF_IS_STATUS_ERROR(status)) {
6525 		hdd_err("cdp_host_get_peer_stats failed. error: %u", status);
6526 		qdf_mem_free(peer_stats);
6527 		return;
6528 	}
6529 
6530 	stainfo->last_tx_rx_ts =
6531 		peer_stats->tx.last_tx_ts > peer_stats->rx.last_rx_ts ?
6532 		peer_stats->tx.last_tx_ts : peer_stats->rx.last_rx_ts;
6533 
6534 	qdf_mem_free(peer_stats);
6535 
6536 	curr_time = qdf_system_ticks();
6537 	dur = curr_time - stainfo->assoc_ts;
6538 	sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000;
6539 	sinfo->filled |= HDD_INFO_CONNECTED_TIME;
6540 	dur = curr_time - stainfo->last_tx_rx_ts;
6541 	sinfo->inactive_time = qdf_system_ticks_to_msecs(dur);
6542 	sinfo->filled |= HDD_INFO_INACTIVE_TIME;
6543 	sinfo->signal = stats->rssi;
6544 	sinfo->filled |= HDD_INFO_SIGNAL;
6545 	sinfo->tx_bytes = stats->tx_bytes;
6546 	sinfo->filled |= HDD_INFO_TX_BYTES | HDD_INFO_TX_BYTES64;
6547 	sinfo->tx_packets = stats->tx_packets;
6548 	sinfo->filled |= HDD_INFO_TX_PACKETS;
6549 	sinfo->rx_bytes = stats->rx_bytes;
6550 	sinfo->filled |= HDD_INFO_RX_BYTES | HDD_INFO_RX_BYTES64;
6551 	sinfo->rx_packets = stats->rx_packets;
6552 	sinfo->filled |= HDD_INFO_RX_PACKETS;
6553 	sinfo->tx_failed = stats->tx_failed;
6554 	sinfo->filled |= HDD_INFO_TX_FAILED;
6555 	sinfo->tx_retries = stats->tx_retries;
6556 
6557 	/* sta flags */
6558 	hdd_fill_sta_flags(sinfo, stainfo);
6559 
6560 	/* per chain avg rssi */
6561 	hdd_fill_per_chain_avg_signal(sinfo, stainfo);
6562 
6563 	/* tx / rx rate info */
6564 	hdd_fill_rate_info(psoc, sinfo, stainfo, stats);
6565 
6566 	/* assoc req ies */
6567 	sinfo->assoc_req_ies = stainfo->assoc_req_ies.ptr;
6568 	sinfo->assoc_req_ies_len = stainfo->assoc_req_ies.len;
6569 
6570 	/* dump sta info*/
6571 	hdd_debug("dump stainfo");
6572 	hdd_debug("con_time %d inact_time %d tx_pkts %d rx_pkts %d",
6573 		  sinfo->connected_time, sinfo->inactive_time,
6574 		  sinfo->tx_packets, sinfo->rx_packets);
6575 	hdd_debug("failed %d retries %d tx_bytes %lld rx_bytes %lld",
6576 		  sinfo->tx_failed, sinfo->tx_retries,
6577 		  sinfo->tx_bytes, sinfo->rx_bytes);
6578 	hdd_debug("rssi %d tx mcs %d legacy %d nss %d flags %x",
6579 		  sinfo->signal, sinfo->txrate.mcs,
6580 		  sinfo->txrate.legacy, sinfo->txrate.nss,
6581 		  sinfo->txrate.flags);
6582 	hdd_debug("rx mcs %d legacy %d nss %d flags %x",
6583 		  sinfo->rxrate.mcs, sinfo->rxrate.legacy,
6584 		  sinfo->rxrate.nss, sinfo->rxrate.flags);
6585 }
6586 
6587 /**
6588  * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs
6589  * @rate: Data rate (100 kbps)
6590  * @nss: Number of streams
6591  * @mcs: HT mcs index
6592  *
6593  * This function is used to construct HT rate flag with rate, nss and mcs
6594  *
6595  * Return: rate flags for success, 0 on failure.
6596  */
6597 static uint8_t hdd_get_rate_flags_ht(uint32_t rate,
6598 				     uint8_t nss,
6599 				     uint8_t mcs)
6600 {
6601 	struct index_data_rate_type *mcs_rate;
6602 	uint8_t flags = 0;
6603 
6604 	mcs_rate = (struct index_data_rate_type *)
6605 		((nss == 1) ? &supported_mcs_rate_nss1 :
6606 		 &supported_mcs_rate_nss2);
6607 
6608 	if (rate == mcs_rate[mcs].supported_rate[0]) {
6609 		flags |= TX_RATE_HT20;
6610 	} else if (rate == mcs_rate[mcs].supported_rate[1]) {
6611 		flags |= TX_RATE_HT40;
6612 	} else if (rate == mcs_rate[mcs].supported_rate[2]) {
6613 		flags |= TX_RATE_HT20;
6614 		flags |= TX_RATE_SGI;
6615 	} else if (rate == mcs_rate[mcs].supported_rate[3]) {
6616 		flags |= TX_RATE_HT40;
6617 		flags |= TX_RATE_SGI;
6618 	} else {
6619 		hdd_err("invalid params rate %d nss %d mcs %d",
6620 			rate, nss, mcs);
6621 	}
6622 
6623 	return flags;
6624 }
6625 
6626 /**
6627  * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs
6628  * @rate: Data rate (100 kbps)
6629  * @nss: Number of streams
6630  * @mcs: VHT mcs index
6631  *
6632  * This function is used to construct VHT rate flag with rate, nss and mcs
6633  *
6634  * Return: rate flags for success, 0 on failure.
6635  */
6636 static uint8_t hdd_get_rate_flags_vht(uint32_t rate,
6637 				      uint8_t nss,
6638 				      uint8_t mcs)
6639 {
6640 	struct index_vht_data_rate_type *mcs_rate;
6641 	uint8_t flags = 0;
6642 
6643 	if (mcs >= ARRAY_SIZE(supported_vht_mcs_rate_nss1)) {
6644 		hdd_err("Invalid mcs index %d", mcs);
6645 		return flags;
6646 	}
6647 
6648 	mcs_rate = (struct index_vht_data_rate_type *)
6649 		((nss == 1) ?
6650 		 &supported_vht_mcs_rate_nss1 :
6651 		 &supported_vht_mcs_rate_nss2);
6652 
6653 	if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
6654 		flags |= TX_RATE_VHT80;
6655 	} else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
6656 		flags |= TX_RATE_VHT80;
6657 		flags |= TX_RATE_SGI;
6658 	} else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
6659 		flags |= TX_RATE_VHT40;
6660 	} else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
6661 		flags |= TX_RATE_VHT40;
6662 		flags |= TX_RATE_SGI;
6663 	} else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
6664 		flags |= TX_RATE_VHT20;
6665 	} else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
6666 		flags |= TX_RATE_VHT20;
6667 		flags |= TX_RATE_SGI;
6668 	} else {
6669 		hdd_err("invalid params rate %d nss %d mcs %d",
6670 			rate, nss, mcs);
6671 	}
6672 
6673 	return flags;
6674 }
6675 
6676 /**
6677  * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs
6678  * @rate: Data rate (100 kbps)
6679  * @mode: Tx/Rx mode
6680  * @nss: Number of streams
6681  * @mcs: Mcs index
6682  *
6683  * This function is used to construct rate flag with rate, nss and mcs
6684  *
6685  * Return: rate flags for success, 0 on failure.
6686  */
6687 static uint8_t hdd_get_rate_flags(uint32_t rate,
6688 				  uint8_t mode,
6689 				  uint8_t nss,
6690 				  uint8_t mcs)
6691 {
6692 	uint8_t flags = 0;
6693 
6694 	if (mode == SIR_SME_PHY_MODE_HT)
6695 		flags = hdd_get_rate_flags_ht(rate, nss, mcs);
6696 	else if (mode == SIR_SME_PHY_MODE_VHT)
6697 		flags = hdd_get_rate_flags_vht(rate, nss, mcs);
6698 	else
6699 		hdd_debug("invalid mode param %d", mode);
6700 
6701 	return flags;
6702 }
6703 
6704 /**
6705  * wlan_hdd_fill_rate_info() - fill HDD rate info from peer info
6706  * @txrx_stats: pointer to txrx stats to be filled with rate info
6707  * @peer_info: peer info pointer
6708  *
6709  * This function is used to fill HDD rate info from peer info
6710  *
6711  * Return: None
6712  */
6713 static void wlan_hdd_fill_rate_info(struct hdd_fw_txrx_stats *txrx_stats,
6714 				    struct peer_stats_info_ext_event *peer_info)
6715 {
6716 	uint8_t flags;
6717 	uint32_t rate_code;
6718 
6719 	/* tx rate info */
6720 	txrx_stats->tx_rate.rate = peer_info->tx_rate;
6721 	rate_code = peer_info->tx_rate_code;
6722 
6723 	if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6724 			WMI_RATE_PREAMBLE_HT)
6725 		txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_HT;
6726 	else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6727 			WMI_RATE_PREAMBLE_VHT)
6728 		txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_VHT;
6729 	else
6730 		txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
6731 
6732 	txrx_stats->tx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
6733 	txrx_stats->tx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
6734 
6735 	flags = hdd_get_rate_flags(txrx_stats->tx_rate.rate / 100,
6736 				   txrx_stats->tx_rate.mode,
6737 				   txrx_stats->tx_rate.nss,
6738 				   txrx_stats->tx_rate.mcs);
6739 
6740 	txrx_stats->tx_rate.rate_flags = flags;
6741 
6742 	hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x",
6743 		  txrx_stats->tx_rate.mode,
6744 		  txrx_stats->tx_rate.nss,
6745 		  txrx_stats->tx_rate.mcs,
6746 		  txrx_stats->tx_rate.rate_flags,
6747 		  flags);
6748 
6749 	/* rx rate info */
6750 	txrx_stats->rx_rate.rate = peer_info->rx_rate;
6751 	rate_code = peer_info->rx_rate_code;
6752 
6753 	if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6754 			WMI_RATE_PREAMBLE_HT)
6755 		txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_HT;
6756 	else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6757 			WMI_RATE_PREAMBLE_VHT)
6758 		txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_VHT;
6759 	else
6760 		txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
6761 
6762 	txrx_stats->rx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
6763 	txrx_stats->rx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
6764 
6765 	flags = hdd_get_rate_flags(txrx_stats->rx_rate.rate / 100,
6766 				   txrx_stats->rx_rate.mode,
6767 				   txrx_stats->rx_rate.nss,
6768 				   txrx_stats->rx_rate.mcs);
6769 
6770 	txrx_stats->rx_rate.rate_flags = flags;
6771 
6772 	hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x",
6773 		 txrx_stats->rx_rate.mode,
6774 		 txrx_stats->rx_rate.nss,
6775 		 txrx_stats->rx_rate.mcs,
6776 		 txrx_stats->rx_rate.rate_flags,
6777 		 flags);
6778 }
6779 
6780 /**
6781  * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
6782  * @wiphy: pointer to wiphy
6783  * @dev: pointer to net_device structure
6784  * @stainfo: request peer station info
6785  * @sinfo: pointer to station_info struct
6786  *
6787  * This function will get remote peer info from fw and fill sinfo struct
6788  *
6789  * Return: 0 on success, otherwise error value
6790  */
6791 static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
6792 				       struct net_device *dev,
6793 				       struct hdd_station_info *stainfo,
6794 				       struct station_info *sinfo)
6795 {
6796 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
6797 	struct hdd_context *hddctx = wiphy_priv(wiphy);
6798 	struct stats_event *stats;
6799 	struct hdd_fw_txrx_stats txrx_stats;
6800 	int i, status;
6801 
6802 	stats = wlan_cfg80211_mc_cp_stats_get_peer_stats(adapter->deflink->vdev,
6803 							 stainfo->sta_mac.bytes,
6804 							 &status);
6805 	if (status || !stats) {
6806 		wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
6807 		hdd_err("fail to get peer info from fw");
6808 		return -EPERM;
6809 	}
6810 
6811 	for (i = 0; i < WMI_MAX_CHAINS; i++)
6812 		stainfo->peer_rssi_per_chain[i] =
6813 			    stats->peer_stats_info_ext->peer_rssi_per_chain[i];
6814 
6815 	qdf_mem_zero(&txrx_stats, sizeof(txrx_stats));
6816 	txrx_stats.tx_packets = stats->peer_stats_info_ext->tx_packets;
6817 	txrx_stats.tx_bytes = stats->peer_stats_info_ext->tx_bytes;
6818 	txrx_stats.rx_packets = stats->peer_stats_info_ext->rx_packets;
6819 	txrx_stats.rx_bytes = stats->peer_stats_info_ext->rx_bytes;
6820 	txrx_stats.tx_retries = stats->peer_stats_info_ext->tx_retries;
6821 	txrx_stats.tx_failed = stats->peer_stats_info_ext->tx_failed;
6822 	txrx_stats.tx_succeed = stats->peer_stats_info_ext->tx_succeed;
6823 	txrx_stats.rssi = stats->peer_stats_info_ext->rssi;
6824 	wlan_hdd_fill_rate_info(&txrx_stats, stats->peer_stats_info_ext);
6825 	wlan_hdd_fill_station_info(hddctx->psoc, adapter,
6826 				   sinfo, stainfo, &txrx_stats);
6827 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
6828 
6829 	return status;
6830 }
6831 
6832 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \
6833 	defined(WLAN_FEATURE_11AX)
6834 /**
6835  * hdd_map_he_gi_to_os() - map txrate_gi to os guard interval
6836  * @guard_interval: guard interval get from fw rate
6837  *
6838  * Return: os guard interval value
6839  */
6840 static inline uint8_t hdd_map_he_gi_to_os(enum txrate_gi guard_interval)
6841 {
6842 	switch (guard_interval) {
6843 	case TXRATE_GI_0_8_US:
6844 		return NL80211_RATE_INFO_HE_GI_0_8;
6845 	case TXRATE_GI_1_6_US:
6846 		return NL80211_RATE_INFO_HE_GI_1_6;
6847 	case TXRATE_GI_3_2_US:
6848 		return NL80211_RATE_INFO_HE_GI_3_2;
6849 	default:
6850 		return NL80211_RATE_INFO_HE_GI_0_8;
6851 	}
6852 }
6853 
6854 /**
6855  * wlan_hdd_fill_os_he_rateflags() - Fill HE related rate_info
6856  * @os_rate: rate info for os
6857  * @rate_flags: rate flags
6858  * @dcm: dcm from rate
6859  * @guard_interval: guard interval from rate
6860  *
6861  * Return: none
6862  */
6863 static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
6864 					  enum tx_rate_info rate_flags,
6865 					  uint8_t dcm,
6866 					  enum txrate_gi guard_interval)
6867 {
6868 	/* as fw not yet report ofdma to host, so we doesn't
6869 	 * fill RATE_INFO_BW_HE_RU.
6870 	 */
6871 	if (rate_flags & (TX_RATE_HE80 | TX_RATE_HE40 |
6872 		TX_RATE_HE20 | TX_RATE_HE160)) {
6873 		if (rate_flags & TX_RATE_HE160)
6874 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_160);
6875 		else if (rate_flags & TX_RATE_HE80)
6876 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
6877 		else if (rate_flags & TX_RATE_HE40)
6878 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
6879 
6880 		os_rate->flags |= RATE_INFO_FLAGS_HE_MCS;
6881 
6882 		os_rate->he_gi = hdd_map_he_gi_to_os(guard_interval);
6883 		os_rate->he_dcm = dcm;
6884 	}
6885 }
6886 #else
6887 static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
6888 					  enum tx_rate_info rate_flags,
6889 					  uint8_t dcm,
6890 					  enum txrate_gi guard_interval)
6891 {}
6892 #endif
6893 
6894 /**
6895  * wlan_hdd_fill_os_rate_info() - Fill os related rate_info
6896  * @rate_flags: rate flags
6897  * @legacy_rate: 802.11abg rate
6898  * @os_rate: rate info for os
6899  * @mcs_index: mcs
6900  * @nss: number of spatial streams
6901  * @dcm: dcm from rate
6902  * @guard_interval: guard interval from rate
6903  *
6904  * Return: none
6905  */
6906 static void wlan_hdd_fill_os_rate_info(enum tx_rate_info rate_flags,
6907 				       uint16_t legacy_rate,
6908 				       struct rate_info *os_rate,
6909 				       uint8_t mcs_index, uint8_t nss,
6910 				       uint8_t dcm,
6911 				       enum txrate_gi guard_interval)
6912 {
6913 	os_rate->nss = nss;
6914 	if (rate_flags & TX_RATE_LEGACY) {
6915 		os_rate->legacy = legacy_rate;
6916 		hdd_debug("Reporting legacy rate %d", os_rate->legacy);
6917 		return;
6918 	}
6919 
6920 	/* assume basic BW. anything else will override this later */
6921 	hdd_set_rate_bw(os_rate, HDD_RATE_BW_20);
6922 	os_rate->mcs = mcs_index;
6923 
6924 	wlan_hdd_fill_os_eht_rateflags(os_rate, rate_flags, dcm,
6925 				       guard_interval);
6926 	wlan_hdd_fill_os_he_rateflags(os_rate, rate_flags, dcm, guard_interval);
6927 
6928 	if (rate_flags & (TX_RATE_VHT160 | TX_RATE_VHT80 | TX_RATE_VHT40 |
6929 	    TX_RATE_VHT20)) {
6930 		if (rate_flags & TX_RATE_VHT160)
6931 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_160);
6932 		else if (rate_flags & TX_RATE_VHT80)
6933 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
6934 		else if (rate_flags & TX_RATE_VHT40)
6935 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
6936 		os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
6937 	}
6938 
6939 	if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) {
6940 		if (rate_flags & TX_RATE_HT40)
6941 			hdd_set_rate_bw(os_rate,
6942 					HDD_RATE_BW_40);
6943 		os_rate->flags |= RATE_INFO_FLAGS_MCS;
6944 	}
6945 
6946 	if (rate_flags & TX_RATE_SGI)
6947 		os_rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
6948 }
6949 
6950 void hdd_get_max_tx_bitrate(struct wlan_hdd_link_info *link_info)
6951 {
6952 	struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx;
6953 	struct station_info sinfo;
6954 	enum tx_rate_info tx_rate_flags;
6955 	uint8_t tx_mcs_index, tx_nss = 1;
6956 	uint16_t my_tx_rate;
6957 	struct hdd_station_ctx *hdd_sta_ctx;
6958 	struct wlan_objmgr_vdev *vdev;
6959 
6960 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
6961 
6962 	qdf_mem_zero(&sinfo, sizeof(struct station_info));
6963 
6964 	sinfo.signal = link_info->rssi;
6965 	tx_mcs_index = link_info->hdd_stats.class_a_stat.tx_mcs_index;
6966 	my_tx_rate = link_info->hdd_stats.class_a_stat.tx_rate;
6967 	tx_rate_flags = link_info->hdd_stats.class_a_stat.tx_rx_rate_flags;
6968 
6969 	if (!(tx_rate_flags & TX_RATE_LEGACY)) {
6970 		vdev = hdd_objmgr_get_vdev_by_user(link_info,
6971 						   WLAN_OSIF_STATS_ID);
6972 		if (vdev) {
6973 			/*
6974 			 * Take static NSS for reporting max rates.
6975 			 * NSS from FW is not reliable as it changes
6976 			 * as per the environment quality.
6977 			 */
6978 			tx_nss = wlan_vdev_mlme_get_nss(vdev);
6979 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
6980 		} else {
6981 			tx_nss = link_info->hdd_stats.class_a_stat.tx_nss;
6982 		}
6983 		hdd_check_and_update_nss(hdd_ctx, &tx_nss, NULL);
6984 
6985 		if (tx_mcs_index == INVALID_MCS_IDX)
6986 			tx_mcs_index = 0;
6987 	}
6988 
6989 	if (hdd_report_max_rate(link_info, hdd_ctx->mac_handle, &sinfo.txrate,
6990 				sinfo.signal, tx_rate_flags, tx_mcs_index,
6991 				my_tx_rate, tx_nss)) {
6992 		hdd_sta_ctx->cache_conn_info.max_tx_bitrate = sinfo.txrate;
6993 		hdd_debug("Reporting max tx rate flags %d mcs %d nss %d bw %d",
6994 			  sinfo.txrate.flags, sinfo.txrate.mcs,
6995 			  sinfo.txrate.nss, sinfo.txrate.bw);
6996 	}
6997 }
6998 
6999 bool hdd_report_max_rate(struct wlan_hdd_link_info *link_info,
7000 			 mac_handle_t mac_handle,
7001 			 struct rate_info *rate,
7002 			 int8_t signal,
7003 			 enum tx_rate_info rate_flags,
7004 			 uint8_t mcs_index,
7005 			 uint16_t fw_rate, uint8_t nss)
7006 {
7007 	uint8_t i, j, rssidx = 0;
7008 	uint16_t max_rate = 0;
7009 	uint32_t vht_mcs_map;
7010 	bool is_vht20_mcs9 = false;
7011 	uint16_t he_mcs_12_13_map = 0;
7012 	uint16_t current_rate = 0;
7013 	qdf_size_t or_leng;
7014 	uint8_t operational_rates[CSR_DOT11_SUPPORTED_RATES_MAX];
7015 	uint8_t extended_rates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
7016 	qdf_size_t er_leng;
7017 	uint8_t mcs_rates[SIZE_OF_BASIC_MCS_SET];
7018 	qdf_size_t mcs_len;
7019 	struct index_data_rate_type *supported_mcs_rate;
7020 	enum data_rate_11ac_max_mcs vht_max_mcs;
7021 	uint8_t max_mcs_idx = 0;
7022 	uint8_t max_ht_mcs_idx;
7023 	uint8_t rate_flag = 1;
7024 	int mode = 0, max_ht_idx;
7025 	QDF_STATUS stat = QDF_STATUS_E_FAILURE;
7026 	struct hdd_context *hdd_ctx;
7027 	int link_speed_rssi_high = 0;
7028 	int link_speed_rssi_mid = 0;
7029 	int link_speed_rssi_low = 0;
7030 	uint32_t link_speed_rssi_report = 0;
7031 	struct wlan_objmgr_vdev *vdev;
7032 
7033 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
7034 	if (!hdd_ctx)
7035 		return false;
7036 
7037 	ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
7038 				       &link_speed_rssi_high,
7039 				       &link_speed_rssi_mid,
7040 				       &link_speed_rssi_low,
7041 				       &link_speed_rssi_report);
7042 
7043 	if (ucfg_mlme_stats_is_link_speed_report_max_scaled(hdd_ctx->psoc)) {
7044 		/* report the max possible speed with RSSI scaling */
7045 		if (signal >= link_speed_rssi_high) {
7046 			/* report the max possible speed */
7047 			rssidx = 0;
7048 		} else if (signal >= link_speed_rssi_mid) {
7049 			/* report middle speed */
7050 			rssidx = 1;
7051 		} else if (signal >= link_speed_rssi_low) {
7052 			/* report middle speed */
7053 			rssidx = 2;
7054 		} else {
7055 			/* report actual speed */
7056 			rssidx = 3;
7057 		}
7058 	}
7059 
7060 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
7061 	if (!vdev) {
7062 		hdd_err("failed to get vdev");
7063 		return false;
7064 	}
7065 
7066 	/* Get Basic Rate Set */
7067 	or_leng = ucfg_mlme_get_opr_rate(vdev, operational_rates,
7068 					 sizeof(operational_rates));
7069 	for (i = 0; i < or_leng; i++) {
7070 		for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) {
7071 			/* Validate Rate Set */
7072 			if (supported_data_rate[j].beacon_rate_index ==
7073 				(operational_rates[i] & 0x7F)) {
7074 				current_rate =
7075 					supported_data_rate[j].
7076 					supported_rate[rssidx];
7077 				break;
7078 			}
7079 		}
7080 		/* Update MAX rate */
7081 		max_rate = (current_rate > max_rate) ? current_rate : max_rate;
7082 	}
7083 
7084 	/* Get Extended Rate Set */
7085 	er_leng = ucfg_mlme_get_ext_opr_rate(vdev, extended_rates,
7086 					     sizeof(extended_rates));
7087 	he_mcs_12_13_map = wlan_vdev_mlme_get_he_mcs_12_13_map(vdev);
7088 
7089 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
7090 	for (i = 0; i < er_leng; i++) {
7091 		for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) {
7092 			if (supported_data_rate[j].beacon_rate_index ==
7093 			    (extended_rates[i] & 0x7F)) {
7094 				current_rate = supported_data_rate[j].
7095 					       supported_rate[rssidx];
7096 				break;
7097 			}
7098 		}
7099 		/* Update MAX rate */
7100 		max_rate = (current_rate > max_rate) ? current_rate : max_rate;
7101 	}
7102 	/* Get MCS Rate Set --
7103 	 * Only if we are connected in non legacy mode and not reporting
7104 	 * actual speed
7105 	 */
7106 	if ((3 != rssidx) && !(rate_flags & TX_RATE_LEGACY)) {
7107 		rate_flag = 0;
7108 		if (rate_flags & (TX_RATE_VHT80 | TX_RATE_HE80 |
7109 				TX_RATE_HE160 | TX_RATE_VHT160 |
7110 				TX_RATE_EHT80 | TX_RATE_EHT160 |
7111 				TX_RATE_EHT320))
7112 			mode = 2;
7113 		else if (rate_flags & (TX_RATE_HT40 |
7114 			 TX_RATE_VHT40 | TX_RATE_HE40 | TX_RATE_EHT40))
7115 			mode = 1;
7116 		else
7117 			mode = 0;
7118 
7119 		if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 |
7120 		    TX_RATE_VHT80 | TX_RATE_HE20 | TX_RATE_HE40 |
7121 		    TX_RATE_HE80 | TX_RATE_HE160 | TX_RATE_VHT160 |
7122 		    TX_RATE_EHT20 | TX_RATE_EHT40 | TX_RATE_EHT80 |
7123 		    TX_RATE_EHT160 | TX_RATE_EHT320)) {
7124 			stat = ucfg_mlme_cfg_get_vht_tx_mcs_map(hdd_ctx->psoc,
7125 								&vht_mcs_map);
7126 			if (QDF_IS_STATUS_ERROR(stat))
7127 				hdd_err("failed to get tx_mcs_map");
7128 
7129 			stat = ucfg_mlme_get_vht20_mcs9(hdd_ctx->psoc,
7130 							&is_vht20_mcs9);
7131 			if (QDF_IS_STATUS_ERROR(stat))
7132 				hdd_err("Failed to get VHT20 MCS9 enable val");
7133 
7134 			vht_max_mcs = (enum data_rate_11ac_max_mcs)
7135 				(vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
7136 			if (rate_flags & TX_RATE_SGI)
7137 				rate_flag |= 1;
7138 
7139 			if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs) {
7140 				max_mcs_idx = 7;
7141 			} else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs) {
7142 				max_mcs_idx = 8;
7143 			} else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs) {
7144 				/*
7145 				 * If the ini enable_vht20_mcs9 is disabled,
7146 				 * then max mcs index should not be set to 9
7147 				 * for TX_RATE_VHT20
7148 				 */
7149 				if (!is_vht20_mcs9 &&
7150 				    (rate_flags & TX_RATE_VHT20))
7151 					max_mcs_idx = 8;
7152 				else
7153 					max_mcs_idx = 9;
7154 			}
7155 
7156 			if (rate_flags & (TX_RATE_EHT20 | TX_RATE_EHT40 |
7157 			    TX_RATE_EHT80 | TX_RATE_EHT160 | TX_RATE_EHT320))
7158 				max_mcs_idx = 13;
7159 
7160 			if (rate_flags & (TX_RATE_HE20 | TX_RATE_HE40 |
7161 			    TX_RATE_HE80 | TX_RATE_HE160)) {
7162 				max_mcs_idx = 11;
7163 				if (he_mcs_12_13_map)
7164 					max_mcs_idx = 13;
7165 			}
7166 
7167 			if (rssidx != 0) {
7168 				for (i = 0; i <= max_mcs_idx; i++) {
7169 					if (signal <= rssi_mcs_tbl[mode][i]) {
7170 						max_mcs_idx = i;
7171 						break;
7172 					}
7173 				}
7174 			}
7175 
7176 			max_mcs_idx = (max_mcs_idx > mcs_index) ?
7177 				max_mcs_idx : mcs_index;
7178 		} else {
7179 			mcs_len = ucfg_mlme_get_mcs_rate(link_info->vdev,
7180 							 mcs_rates,
7181 							 sizeof(mcs_rates));
7182 			if (!mcs_len) {
7183 				hdd_err("Failed to get current mcs rate set");
7184 				/*To keep GUI happy */
7185 				return false;
7186 			}
7187 
7188 			if (rate_flags & TX_RATE_HT40)
7189 				rate_flag |= 1;
7190 			if (rate_flags & TX_RATE_SGI)
7191 				rate_flag |= 2;
7192 
7193 			supported_mcs_rate =
7194 				(struct index_data_rate_type *)
7195 				((nss == 1) ? &supported_mcs_rate_nss1 :
7196 				 &supported_mcs_rate_nss2);
7197 			max_ht_mcs_idx =
7198 				QDF_ARRAY_SIZE(supported_mcs_rate_nss1);
7199 			max_ht_idx = max_ht_mcs_idx;
7200 			if (rssidx != 0) {
7201 				for (i = 0; i < max_ht_mcs_idx; i++) {
7202 					if (signal <= rssi_mcs_tbl[mode][i]) {
7203 						max_ht_idx = i + 1;
7204 						break;
7205 					}
7206 				}
7207 			}
7208 
7209 			for (i = 0; i < mcs_len; i++) {
7210 				for (j = 0; j < max_ht_idx; j++) {
7211 					if (supported_mcs_rate[j].
7212 						beacon_rate_index ==
7213 						mcs_rates[i]) {
7214 						current_rate =
7215 						  supported_mcs_rate[j].
7216 						  supported_rate
7217 						  [rate_flag];
7218 						max_mcs_idx =
7219 						  supported_mcs_rate[j].
7220 						  beacon_rate_index;
7221 						break;
7222 					}
7223 				}
7224 
7225 				if ((j < max_ht_mcs_idx) &&
7226 				    (current_rate > max_rate))
7227 					max_rate = current_rate;
7228 			}
7229 
7230 			if (nss == 2)
7231 				max_mcs_idx += max_ht_mcs_idx;
7232 			max_mcs_idx = (max_mcs_idx > mcs_index) ?
7233 				max_mcs_idx : mcs_index;
7234 		}
7235 	}
7236 
7237 	else if (!(rate_flags & TX_RATE_LEGACY)) {
7238 		max_rate = fw_rate;
7239 		max_mcs_idx = mcs_index;
7240 	}
7241 	/* report a value at least as big as current rate */
7242 	if ((max_rate < fw_rate) || (0 == max_rate)) {
7243 		max_rate = fw_rate;
7244 	}
7245 	hdd_debug("RLMS %u, rate_flags 0x%x, max_rate %d mcs %d nss %d",
7246 		  link_speed_rssi_report, rate_flags,
7247 		  max_rate, max_mcs_idx, nss);
7248 	wlan_hdd_fill_os_rate_info(rate_flags, max_rate, rate,
7249 				   max_mcs_idx, nss, 0, 0);
7250 
7251 	return true;
7252 }
7253 
7254 /**
7255  * hdd_report_actual_rate() - Fill the actual rate stats.
7256  * @rate_flags: The rate flags computed from rate
7257  * @my_rate: The rate from fw stats
7258  * @rate: The station_info struct member struct rate_info to be filled
7259  * @mcs_index: The mcs index computed from rate
7260  * @nss: The NSS from fw stats
7261  * @dcm: the dcm computed from rate
7262  * @guard_interval: the guard interval computed from rate
7263  *
7264  * Return: None
7265  */
7266 static void hdd_report_actual_rate(enum tx_rate_info rate_flags,
7267 				   uint16_t my_rate,
7268 				   struct rate_info *rate, uint8_t mcs_index,
7269 				   uint8_t nss, uint8_t dcm,
7270 				   enum txrate_gi guard_interval)
7271 {
7272 	/* report current rate instead of max rate */
7273 	wlan_hdd_fill_os_rate_info(rate_flags, my_rate, rate,
7274 				   mcs_index, nss, dcm, guard_interval);
7275 }
7276 
7277 /**
7278  * hdd_wlan_fill_per_chain_rssi_stats() - Fill per chain rssi stats
7279  *
7280  * @sinfo: The station_info structure to be filled.
7281  * @link_info: pointer to link_info struct in adapter
7282  *
7283  * Return: None
7284  */
7285 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
7286 static void
7287 hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
7288 				   struct wlan_hdd_link_info *link_info)
7289 {
7290 	bool rssi_stats_valid = false;
7291 	uint8_t i;
7292 
7293 	sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
7294 	for (i = 0; i < NUM_CHAINS_MAX; i++) {
7295 		sinfo->chain_signal_avg[i] =
7296 			   link_info->hdd_stats.per_chain_rssi_stats.rssi[i];
7297 		sinfo->chains |= 1 << i;
7298 		if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
7299 		    sinfo->chain_signal_avg[i] != 0)
7300 			sinfo->signal_avg = sinfo->chain_signal_avg[i];
7301 
7302 		hdd_debug("RSSI for chain %d, vdev_id %d is %d",
7303 			  i, link_info->vdev_id, sinfo->chain_signal_avg[i]);
7304 
7305 		if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
7306 			rssi_stats_valid = true;
7307 	}
7308 
7309 	if (rssi_stats_valid) {
7310 		sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG;
7311 		sinfo->filled |= HDD_INFO_SIGNAL_AVG;
7312 	}
7313 }
7314 #else
7315 static inline void
7316 hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
7317 				   struct wlan_hdd_link_info *link_info)
7318 {
7319 }
7320 #endif
7321 
7322 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) || \
7323 	defined(CFG80211_RX_FCS_ERROR_REPORTING_SUPPORT)
7324 static void hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info *link_info,
7325 					struct station_info *sinfo)
7326 {
7327 	sinfo->rx_mpdu_count = link_info->hdd_stats.peer_stats.rx_count;
7328 	sinfo->fcs_err_count = link_info->hdd_stats.peer_stats.fcs_count;
7329 	hdd_debug("RX mpdu count %d fcs_err_count %d",
7330 		  sinfo->rx_mpdu_count, sinfo->fcs_err_count);
7331 	sinfo->filled |= HDD_INFO_FCS_ERROR_COUNT | HDD_INFO_RX_MPDUS;
7332 }
7333 #else
7334 static void hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info *link_info,
7335 					struct station_info *sinfo)
7336 {
7337 }
7338 #endif
7339 
7340 void hdd_check_and_update_nss(struct hdd_context *hdd_ctx,
7341 			      uint8_t *tx_nss, uint8_t *rx_nss)
7342 {
7343 	if (tx_nss && (*tx_nss > 1) &&
7344 	    policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
7345 	    !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
7346 		hdd_debug("Hw mode is DBS, Reduce tx nss(%d) to 1", *tx_nss);
7347 		(*tx_nss)--;
7348 	}
7349 
7350 	if (rx_nss && (*rx_nss > 1) &&
7351 	    policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
7352 	    !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
7353 		hdd_debug("Hw mode is DBS, Reduce rx nss(%d) to 1", *rx_nss);
7354 		(*rx_nss)--;
7355 	}
7356 }
7357 
7358 #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER
7359 static void
7360 wlan_hdd_refill_os_bw(struct rate_info *os_rate, enum rx_tlv_bw bw)
7361 {
7362 	if (bw == RX_TLV_BW_20MHZ)
7363 		os_rate->bw = RATE_INFO_BW_20;
7364 	else if (bw == RX_TLV_BW_40MHZ)
7365 		os_rate->bw = RATE_INFO_BW_40;
7366 	else if (bw == RX_TLV_BW_80MHZ)
7367 		os_rate->bw = RATE_INFO_BW_80;
7368 	else if (bw == RX_TLV_BW_160MHZ)
7369 		os_rate->bw = RATE_INFO_BW_160;
7370 	else
7371 		wlan_hdd_refill_os_eht_bw(os_rate, bw);
7372 }
7373 
7374 static void
7375 wlan_hdd_refill_os_rateflags(struct rate_info *os_rate, uint8_t preamble)
7376 {
7377 	if (preamble == DOT11_N)
7378 		os_rate->flags |= RATE_INFO_FLAGS_MCS;
7379 	else if (preamble == DOT11_AC)
7380 		os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
7381 	else if (preamble == DOT11_AX)
7382 		os_rate->flags |= RATE_INFO_FLAGS_HE_MCS;
7383 	else
7384 		wlan_hdd_refill_os_eht_rateflags(os_rate, preamble);
7385 }
7386 
7387 /**
7388  * wlan_hdd_refill_actual_rate() - Refill actual rates info stats
7389  * @sinfo: kernel station_info struct to populate
7390  * @link_info: pointer to link_info struct in adapter,
7391  *             where hdd_stats is located in this struct
7392  *
7393  * This function is to replace RX rates which was previously filled by fw.
7394  *
7395  * Return: None
7396  */
7397 static void
7398 wlan_hdd_refill_actual_rate(struct station_info *sinfo,
7399 			    struct wlan_hdd_link_info *link_info)
7400 {
7401 	uint8_t preamble = link_info->hdd_stats.class_a_stat.rx_preamble;
7402 
7403 	sinfo->rxrate.nss = link_info->hdd_stats.class_a_stat.rx_nss;
7404 	if (preamble == DOT11_A || preamble == DOT11_B) {
7405 		/* Clear rxrate which may have been set previously */
7406 		qdf_mem_zero(&sinfo->rxrate, sizeof(sinfo->rxrate));
7407 		sinfo->rxrate.legacy =
7408 			link_info->hdd_stats.class_a_stat.rx_rate;
7409 		hdd_debug("Reporting legacy rate %d", sinfo->rxrate.legacy);
7410 		return;
7411 	} else if (qdf_unlikely(preamble == INVALID_PREAMBLE)) {
7412 		/*
7413 		 * If preamble is invalid, it means that DP has not received
7414 		 * a data frame since assoc or roaming so there is no rates.
7415 		 * In this case, using FW rates which was set previously.
7416 		 */
7417 		hdd_debug("Driver failed to get rate, reporting FW rate");
7418 		return;
7419 	}
7420 
7421 	wlan_hdd_refill_os_rateflags(&sinfo->rxrate, preamble);
7422 
7423 	sinfo->rxrate.mcs = link_info->hdd_stats.class_a_stat.rx_mcs_index;
7424 
7425 	wlan_hdd_refill_os_bw(&sinfo->rxrate,
7426 			      link_info->hdd_stats.class_a_stat.rx_bw);
7427 	/* Fill out gi and dcm in HE mode */
7428 	sinfo->rxrate.he_gi =
7429 		hdd_map_he_gi_to_os(link_info->hdd_stats.class_a_stat.rx_gi);
7430 	sinfo->rxrate.he_dcm = 0;
7431 
7432 	if (link_info->hdd_stats.class_a_stat.rx_gi == TXRATE_GI_0_4_US)
7433 		sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
7434 
7435 	hdd_debug("sgi=%d, preamble=%d, bw=%d, mcs=%d, nss=%d, rate_flag=0x%x",
7436 		  link_info->hdd_stats.class_a_stat.rx_gi, preamble,
7437 		  link_info->hdd_stats.class_a_stat.rx_bw,
7438 		  link_info->hdd_stats.class_a_stat.rx_mcs_index,
7439 		  link_info->hdd_stats.class_a_stat.rx_nss,
7440 		  sinfo->rxrate.flags);
7441 }
7442 #else
7443 static inline void
7444 wlan_hdd_refill_actual_rate(struct station_info *sinfo,
7445 			    struct wlan_hdd_link_info *link_info)
7446 {
7447 }
7448 #endif
7449 
7450 static void wlan_hdd_update_rssi(struct wlan_hdd_link_info *link_info,
7451 				 struct station_info *sinfo)
7452 {
7453 	struct hdd_station_ctx *sta_ctx;
7454 	int8_t snr;
7455 	mac_handle_t mac_handle;
7456 
7457 	mac_handle = hdd_adapter_get_mac_handle(link_info->adapter);
7458 	if (!mac_handle) {
7459 		hdd_err("mac ctx NULL");
7460 		return;
7461 	}
7462 
7463 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7464 	link_info->rssi = link_info->hdd_stats.summary_stat.rssi;
7465 	link_info->snr = link_info->hdd_stats.summary_stat.snr;
7466 	snr = link_info->snr;
7467 
7468 	/* for new connection there might be no valid previous RSSI */
7469 	if (!link_info->rssi) {
7470 		hdd_get_rssi_snr_by_bssid(mac_handle,
7471 					  sta_ctx->conn_info.bssid.bytes,
7472 					  &link_info->rssi, &snr);
7473 	}
7474 
7475 	/* If RSSi is reported as positive then it is invalid */
7476 	if (link_info->rssi >= 0) {
7477 		hdd_debug_rl("Invalid RSSI %d, reset to -1", link_info->rssi);
7478 		link_info->rssi = -1;
7479 		link_info->hdd_stats.summary_stat.rssi = -1;
7480 	}
7481 
7482 	sinfo->signal = link_info->rssi;
7483 	hdd_debug("snr: %d, rssi: %d",
7484 		  link_info->hdd_stats.summary_stat.snr,
7485 		  link_info->hdd_stats.summary_stat.rssi);
7486 	sta_ctx->conn_info.signal = sinfo->signal;
7487 	sta_ctx->conn_info.noise = sta_ctx->conn_info.signal - snr;
7488 	sta_ctx->cache_conn_info.signal = sinfo->signal;
7489 	sta_ctx->cache_conn_info.noise = sta_ctx->conn_info.noise;
7490 	sinfo->filled |= HDD_INFO_SIGNAL;
7491 }
7492 
7493 static void
7494 wlan_hdd_update_mlo_peer_stats(struct wlan_hdd_link_info *link_info,
7495 			       struct station_info *sinfo)
7496 {
7497 	ol_txrx_soc_handle soc;
7498 	uint8_t *peer_mac;
7499 	struct cdp_peer_stats *peer_stats;
7500 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
7501 
7502 	if (wlan_hdd_validate_context(hdd_ctx)) {
7503 		hdd_err("invalid hdd_ctx");
7504 		return;
7505 	}
7506 
7507 	soc = cds_get_context(QDF_MODULE_ID_SOC);
7508 	peer_mac = link_info->session.station.conn_info.bssid.bytes;
7509 
7510 	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx))
7511 		return;
7512 
7513 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
7514 	if (!peer_stats) {
7515 		hdd_err("Failed to allocated memory for peer_stats");
7516 		return;
7517 	}
7518 
7519 	ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
7520 					peer_mac, peer_stats,
7521 					CDP_WILD_PEER_TYPE,
7522 					WLAN_MAX_MLD);
7523 
7524 	sinfo->tx_bytes = peer_stats->tx.tx_success.bytes;
7525 	sinfo->rx_bytes = peer_stats->rx.rcvd.bytes;
7526 	sinfo->rx_packets = peer_stats->rx.rcvd.num;
7527 
7528 	hdd_nofl_debug("Updated sinfo with per peer stats");
7529 	qdf_mem_free(peer_stats);
7530 }
7531 
7532 static int wlan_hdd_update_rate_info(struct wlan_hdd_link_info *link_info,
7533 				     struct station_info *sinfo)
7534 {
7535 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
7536 	struct hdd_station_ctx *sta_ctx;
7537 	mac_handle_t mac_handle;
7538 	struct wlan_objmgr_vdev *vdev;
7539 	enum tx_rate_info rate_flags, tx_rate_flags, rx_rate_flags;
7540 	enum txrate_gi tx_gi, rx_gi;
7541 	uint32_t link_speed_rssi_report = 0;
7542 	int link_speed_rssi_high = 0;
7543 	int link_speed_rssi_mid = 0;
7544 	int link_speed_rssi_low = 0;
7545 	uint16_t my_tx_rate, my_rx_rate;
7546 	uint8_t tx_mcs_index, rx_mcs_index;
7547 	uint8_t tx_nss = 1, rx_nss = 1, tx_dcm, rx_dcm;
7548 	qdf_net_dev_stats stats = {0};
7549 	struct hdd_stats *hdd_stats;
7550 
7551 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7552 	ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
7553 				       &link_speed_rssi_high,
7554 				       &link_speed_rssi_mid,
7555 				       &link_speed_rssi_low,
7556 				       &link_speed_rssi_report);
7557 
7558 	hdd_stats = &link_info->hdd_stats;
7559 	rate_flags = hdd_stats->class_a_stat.tx_rx_rate_flags;
7560 	tx_rate_flags = rx_rate_flags = rate_flags;
7561 
7562 	tx_mcs_index = hdd_stats->class_a_stat.tx_mcs_index;
7563 	rx_mcs_index = hdd_stats->class_a_stat.rx_mcs_index;
7564 	mac_handle = hdd_ctx->mac_handle;
7565 
7566 	/* convert to the UI units of 100kbps */
7567 	my_tx_rate = hdd_stats->class_a_stat.tx_rate;
7568 	my_rx_rate = hdd_stats->class_a_stat.rx_rate;
7569 
7570 	tx_dcm = hdd_stats->class_a_stat.tx_dcm;
7571 	rx_dcm = hdd_stats->class_a_stat.rx_dcm;
7572 	tx_gi = hdd_stats->class_a_stat.tx_gi;
7573 	rx_gi = hdd_stats->class_a_stat.rx_gi;
7574 
7575 	if (!(rate_flags & TX_RATE_LEGACY)) {
7576 		tx_nss = hdd_stats->class_a_stat.tx_nss;
7577 		rx_nss = hdd_stats->class_a_stat.rx_nss;
7578 
7579 		hdd_check_and_update_nss(hdd_ctx, &tx_nss, &rx_nss);
7580 
7581 		if (ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) {
7582 			/* Get current rate flags if report actual */
7583 			/* WMA fails to find mcs_index for legacy tx rates */
7584 			if (tx_mcs_index == INVALID_MCS_IDX && my_tx_rate)
7585 				tx_rate_flags = TX_RATE_LEGACY;
7586 			else
7587 				tx_rate_flags =
7588 				    hdd_stats->class_a_stat.tx_mcs_rate_flags;
7589 
7590 			if (rx_mcs_index == INVALID_MCS_IDX && my_rx_rate)
7591 				rx_rate_flags = TX_RATE_LEGACY;
7592 			else
7593 				rx_rate_flags =
7594 				    hdd_stats->class_a_stat.rx_mcs_rate_flags;
7595 		}
7596 
7597 		if (tx_mcs_index == INVALID_MCS_IDX)
7598 			tx_mcs_index = 0;
7599 		if (rx_mcs_index == INVALID_MCS_IDX)
7600 			rx_mcs_index = 0;
7601 	}
7602 
7603 	hdd_debug("[RSSI %d, RLMS %u, rssi high %d, rssi mid %d, rssi low %d]-"
7604 		  "[Rate info: TX: %d, RX: %d]-[Rate flags: TX: 0x%x, RX: 0x%x]"
7605 		  "-[MCS Index: TX: %d, RX: %d]-[NSS: TX: %d, RX: %d]-"
7606 		  "[dcm: TX: %d, RX: %d]-[guard interval: TX: %d, RX: %d",
7607 		  sinfo->signal, link_speed_rssi_report,
7608 		  link_speed_rssi_high, link_speed_rssi_mid,
7609 		  link_speed_rssi_low, my_tx_rate, my_rx_rate,
7610 		  (int)tx_rate_flags, (int)rx_rate_flags, (int)tx_mcs_index,
7611 		  (int)rx_mcs_index, (int)tx_nss, (int)rx_nss,
7612 		  (int)tx_dcm, (int)rx_dcm, (int)tx_gi, (int)rx_gi);
7613 
7614 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
7615 
7616 	if (!vdev) {
7617 		hdd_nofl_debug("vdev object NULL");
7618 		return -EINVAL;
7619 	}
7620 
7621 	if (!ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) {
7622 		bool tx_rate_calc, rx_rate_calc;
7623 		uint8_t tx_nss_max, rx_nss_max;
7624 
7625 		/*
7626 		 * Take static NSS for reporting max rates. NSS from the FW
7627 		 * is not reliable as it changes as per the environment
7628 		 * quality.
7629 		 */
7630 		tx_nss_max = wlan_vdev_mlme_get_nss(vdev);
7631 		rx_nss_max = wlan_vdev_mlme_get_nss(vdev);
7632 
7633 		hdd_check_and_update_nss(hdd_ctx, &tx_nss_max, &rx_nss_max);
7634 
7635 		tx_rate_calc = hdd_report_max_rate(link_info, mac_handle,
7636 						   &sinfo->txrate,
7637 						   sinfo->signal,
7638 						   tx_rate_flags,
7639 						   tx_mcs_index,
7640 						   my_tx_rate,
7641 						   tx_nss_max);
7642 
7643 		rx_rate_calc = hdd_report_max_rate(link_info, mac_handle,
7644 						   &sinfo->rxrate,
7645 						   sinfo->signal,
7646 						   rx_rate_flags,
7647 						   rx_mcs_index,
7648 						   my_rx_rate,
7649 						   rx_nss_max);
7650 
7651 		if (!tx_rate_calc || !rx_rate_calc) {
7652 			hdd_report_actual_rate(tx_rate_flags, my_tx_rate,
7653 					       &sinfo->txrate, tx_mcs_index,
7654 					       tx_nss, tx_dcm, tx_gi);
7655 
7656 			hdd_report_actual_rate(rx_rate_flags, my_rx_rate,
7657 					       &sinfo->rxrate, rx_mcs_index,
7658 					       rx_nss, rx_dcm, rx_gi);
7659 		}
7660 	} else {
7661 		/* Fill TX stats */
7662 		hdd_report_actual_rate(tx_rate_flags, my_tx_rate,
7663 				       &sinfo->txrate, tx_mcs_index,
7664 				       tx_nss, tx_dcm, tx_gi);
7665 
7666 		/* Fill RX stats */
7667 		hdd_report_actual_rate(rx_rate_flags, my_rx_rate,
7668 				       &sinfo->rxrate, rx_mcs_index,
7669 				       rx_nss, rx_dcm, rx_gi);
7670 
7671 		/* Using driver RX rate to replace the FW RX rate */
7672 		wlan_hdd_refill_actual_rate(sinfo, link_info);
7673 	}
7674 
7675 	wlan_hdd_fill_summary_stats(&hdd_stats->summary_stat,
7676 				    sinfo, link_info->vdev_id);
7677 
7678 	wlan_hdd_fill_per_link_summary_stats(&hdd_stats->summary_stat,
7679 					     sinfo, link_info);
7680 
7681 	ucfg_dp_get_net_dev_stats(vdev, &stats);
7682 	sinfo->tx_bytes = stats.tx_bytes;
7683 	sinfo->rx_bytes = stats.rx_bytes;
7684 	sinfo->rx_packets = stats.rx_packets;
7685 	wlan_hdd_update_mlo_peer_stats(link_info, sinfo);
7686 
7687 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
7688 
7689 	qdf_mem_copy(&sta_ctx->conn_info.txrate,
7690 		     &sinfo->txrate, sizeof(sinfo->txrate));
7691 	qdf_mem_copy(&sta_ctx->cache_conn_info.txrate,
7692 		     &sinfo->txrate, sizeof(sinfo->txrate));
7693 
7694 	qdf_mem_copy(&sta_ctx->conn_info.rxrate,
7695 		     &sinfo->rxrate, sizeof(sinfo->rxrate));
7696 
7697 	sinfo->filled |= HDD_INFO_TX_BITRATE |
7698 			 HDD_INFO_RX_BITRATE |
7699 			 HDD_INFO_TX_BYTES   |
7700 			 HDD_INFO_RX_BYTES   |
7701 			 HDD_INFO_RX_PACKETS;
7702 
7703 	if (tx_rate_flags & TX_RATE_LEGACY) {
7704 		hdd_debug("[TX: Reporting legacy rate %d pkt cnt %d]-"
7705 			  "[RX: Reporting legacy rate %d pkt cnt %d]",
7706 			  sinfo->txrate.legacy, sinfo->tx_packets,
7707 			  sinfo->rxrate.legacy, sinfo->rx_packets);
7708 	} else {
7709 		hdd_debug("[TX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d]-"
7710 			  "[RX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d]",
7711 			  sinfo->txrate.mcs, sinfo->txrate.flags,
7712 			  sinfo->tx_packets, sinfo->txrate.nss,
7713 			  sinfo->txrate.bw, sinfo->rxrate.mcs,
7714 			  sinfo->rxrate.flags, sinfo->rx_packets,
7715 			  sinfo->rxrate.nss, sinfo->rxrate.bw);
7716 	}
7717 
7718 	return 0;
7719 }
7720 
7721 /**
7722  * wlan_hdd_get_sta_stats() - get aggregate STA stats
7723  * @link_info: Link info pointer of STA adapter to get stats for
7724  * @mac: mac address of sta
7725  * @sinfo: kernel station_info struct to populate
7726  *
7727  * Fetch the vdev-level aggregate stats for the given STA adapter. This is to
7728  * support "station dump" and "station get" for STA vdevs
7729  *
7730  * Return: errno
7731  */
7732 static int wlan_hdd_get_sta_stats(struct wlan_hdd_link_info *link_info,
7733 				  const uint8_t *mac,
7734 				  struct station_info *sinfo)
7735 {
7736 	struct hdd_adapter *adapter = link_info->adapter;
7737 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7738 	struct hdd_station_ctx *sta_ctx;
7739 	uint8_t *link_mac;
7740 	int32_t rcpi_value;
7741 
7742 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
7743 		   TRACE_CODE_HDD_CFG80211_GET_STA,
7744 		   link_info->vdev_id, 0);
7745 
7746 	if (link_info->vdev_id == WLAN_UMAC_VDEV_ID_MAX) {
7747 		wlan_hdd_update_sinfo(sinfo, link_info);
7748 		hdd_debug_rl("Sending Cached stats for standby link");
7749 		return 0;
7750 	}
7751 
7752 	if (!hdd_cm_is_vdev_associated(link_info)) {
7753 		hdd_debug("Not associated");
7754 		/*To keep GUI happy */
7755 		return 0;
7756 	}
7757 
7758 	if (hdd_is_roam_sync_in_progress(hdd_ctx, link_info->vdev_id)) {
7759 		hdd_debug("Roam sync is in progress, cannot continue with this request");
7760 		/*
7761 		 * supplicant reports very low rssi to upper layer
7762 		 * and handover happens to cellular.
7763 		 * send the cached rssi when get_station
7764 		 */
7765 		sinfo->signal = link_info->rssi;
7766 		sinfo->filled |= HDD_INFO_SIGNAL;
7767 		return 0;
7768 	}
7769 
7770 	if (hdd_ctx->rcpi_enabled)
7771 		wlan_hdd_get_rcpi(adapter, (uint8_t *)mac, &rcpi_value,
7772 				  RCPI_MEASUREMENT_TYPE_AVG_MGMT);
7773 
7774 	wlan_hdd_get_station_stats(link_info);
7775 
7776 	wlan_hdd_get_peer_rx_rate_stats(link_info);
7777 
7778 	wlan_hdd_update_rssi(link_info, sinfo);
7779 
7780 	/*
7781 	 * we notify connect to lpass here instead of during actual
7782 	 * connect processing because rssi info is not accurate during
7783 	 * actual connection.  lpass will ensure the notification is
7784 	 * only processed once per association.
7785 	 */
7786 	hdd_lpass_notify_connect(link_info);
7787 
7788 	if (wlan_hdd_update_rate_info(link_info, sinfo))
7789 		/* Keep GUI happy */
7790 		return 0;
7791 
7792 	hdd_fill_fcs_and_mpdu_count(link_info, sinfo);
7793 
7794 	hdd_wlan_fill_per_chain_rssi_stats(sinfo, link_info);
7795 
7796 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7797 	link_mac = sta_ctx->conn_info.bssid.bytes;
7798 	hdd_nofl_debug("Sending station stats for link " QDF_MAC_ADDR_FMT,
7799 		       QDF_MAC_ADDR_REF(link_mac));
7800 
7801 	wlan_hdd_copy_sinfo_to_link_info(link_info, sinfo);
7802 
7803 	hdd_exit();
7804 
7805 	return 0;
7806 }
7807 
7808 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
7809 /*
7810  * wlan_hdd_update_mlo_rate_info() - Populate mlo station stats rate info
7811  * @hdd_sinfo: Pointer to hdd stats station info struct
7812  * @sinfo: Pointer to kernel station info struct
7813  *
7814  * Return: none
7815  */
7816 static void
7817 wlan_hdd_update_mlo_rate_info(struct wlan_hdd_station_stats_info *hdd_sinfo,
7818 			      struct station_info *sinfo)
7819 {
7820 	uint8_t i;
7821 
7822 	hdd_sinfo->signal = sinfo->signal;
7823 	hdd_sinfo->signal_avg = sinfo->signal_avg;
7824 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
7825 		hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i];
7826 
7827 	qdf_mem_copy(&hdd_sinfo->txrate,
7828 		     &sinfo->txrate, sizeof(sinfo->txrate));
7829 
7830 	qdf_mem_copy(&hdd_sinfo->rxrate,
7831 		     &sinfo->rxrate, sizeof(sinfo->rxrate));
7832 }
7833 
7834 /*
7835  * wlan_hdd_update_mlo_sinfo() - Populate mlo stats station info
7836  * @link_info: Link info pointer of STA adapter
7837  * @hdd_sinfo: Pointer to hdd stats station info struct
7838  * @sinfo: Pointer to kernel station info struct
7839  *
7840  * Return: none
7841  */
7842 static void
7843 wlan_hdd_update_mlo_sinfo(struct wlan_hdd_link_info *link_info,
7844 			  struct wlan_hdd_station_stats_info *hdd_sinfo,
7845 			  struct station_info *sinfo)
7846 {
7847 	struct hdd_station_ctx *sta_ctx;
7848 
7849 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7850 
7851 	if (!link_info->is_mlo_vdev_active)
7852 		hdd_nofl_debug("vdev_id[%d] is inactive", link_info->vdev_id);
7853 
7854 	/* Update the rate info for link with best RSSI */
7855 	if (sinfo->signal > hdd_sinfo->signal) {
7856 		hdd_nofl_debug("Updating rates for link_id %d",
7857 			       sta_ctx->conn_info.ieee_link_id);
7858 		wlan_hdd_update_mlo_rate_info(hdd_sinfo, sinfo);
7859 	}
7860 
7861 	/* Send cumulative Tx/Rx packets and bytes data
7862 	 * of all active links to userspace
7863 	 */
7864 	hdd_sinfo->rx_bytes += sinfo->rx_bytes;
7865 	hdd_sinfo->tx_bytes += sinfo->tx_bytes;
7866 	hdd_sinfo->rx_packets += sinfo->rx_packets;
7867 	hdd_sinfo->tx_packets += sinfo->tx_packets;
7868 	hdd_sinfo->tx_retries += sinfo->tx_retries;
7869 	hdd_sinfo->tx_failed += sinfo->tx_failed;
7870 	hdd_sinfo->rx_mpdu_count += sinfo->rx_mpdu_count;
7871 	hdd_sinfo->fcs_err_count += sinfo->fcs_err_count;
7872 }
7873 
7874 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
7875 /**
7876  * wlan_hdd_get_mlo_sta_stats - get aggregate STA stats for MLO
7877  * @adapter: HDD adapter
7878  * @mac: mac address
7879  * @sinfo: kernel station_info struct to populate
7880  *
7881  * Return: 0 on success; errno on failure
7882  */
7883 static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
7884 				      const uint8_t *mac,
7885 				      struct station_info *sinfo)
7886 {
7887 	struct hdd_adapter *ml_adapter, *link_adapter;
7888 	struct hdd_mlo_adapter_info *mlo_adapter_info;
7889 	struct wlan_hdd_station_stats_info hdd_sinfo = {0};
7890 	uint8_t i;
7891 
7892 	/* Initialize the signal value to a default RSSI of -128dBm */
7893 	hdd_sinfo.signal = WLAN_INVALID_RSSI_VALUE;
7894 
7895 	ml_adapter = adapter;
7896 	if (hdd_adapter_is_link_adapter(ml_adapter))
7897 		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
7898 
7899 	wlan_hdd_get_sta_stats(ml_adapter->deflink, mac, sinfo);
7900 	wlan_hdd_update_mlo_sinfo(ml_adapter->deflink, &hdd_sinfo, sinfo);
7901 
7902 	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
7903 	for (i = 0; i < WLAN_MAX_MLD; i++) {
7904 		link_adapter = mlo_adapter_info->link_adapter[i];
7905 		if (!link_adapter ||
7906 		    hdd_adapter_is_associated_with_ml_adapter(link_adapter))
7907 			continue;
7908 
7909 		wlan_hdd_get_sta_stats(link_adapter->deflink, mac, sinfo);
7910 		wlan_hdd_update_mlo_sinfo(link_adapter->deflink, &hdd_sinfo,
7911 					  sinfo);
7912 	}
7913 
7914 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo);
7915 	hdd_nofl_debug("Sending aggregated mlo station stats");
7916 
7917 	hdd_exit();
7918 
7919 	return 0;
7920 }
7921 #else
7922 static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
7923 				      const uint8_t *mac,
7924 				      struct station_info *sinfo)
7925 {
7926 	struct wlan_hdd_link_info *link_info;
7927 	struct wlan_hdd_station_stats_info hdd_sinfo = {0};
7928 	struct hdd_station_ctx *sta_ctx;
7929 
7930 	/* Initialize the signal value to a default RSSI of -128dBm */
7931 	hdd_sinfo.signal = WLAN_INVALID_RSSI_VALUE;
7932 
7933 	hdd_adapter_for_each_link_info(adapter, link_info) {
7934 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7935 		if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID)
7936 			continue;
7937 		wlan_hdd_get_sta_stats(link_info, mac, sinfo);
7938 		wlan_hdd_update_mlo_sinfo(link_info, &hdd_sinfo, sinfo);
7939 	}
7940 
7941 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo);
7942 	hdd_nofl_debug("Sending aggregated mlo station stats");
7943 
7944 	hdd_exit();
7945 
7946 	return 0;
7947 }
7948 #endif
7949 #else
7950 static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
7951 				      const uint8_t *mac,
7952 				      struct station_info *sinfo)
7953 {
7954 	return wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
7955 }
7956 #endif
7957 
7958 /*
7959  * wlan_is_mlo_aggregated_stats_allowed() - Is aggregated stats requested
7960  * @adapter: HDD adapter
7961  * @mac: mac address
7962  *
7963  * Return: True if req is on mld_mac and FW supports per link stats, else False
7964  */
7965 static bool
7966 wlan_is_mlo_aggregated_stats_allowed(struct hdd_adapter *adapter,
7967 				     const uint8_t *mac)
7968 {
7969 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7970 	bool is_mld_req = false;
7971 	bool per_link_stats_cap = false;
7972 	struct qdf_mac_addr peer_mld_mac;
7973 	QDF_STATUS status;
7974 
7975 	if (!hdd_ctx) {
7976 		hdd_err("invalid hdd_ctx");
7977 		return false;
7978 	}
7979 
7980 	status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink, &peer_mld_mac);
7981 	if (QDF_IS_STATUS_ERROR(status)) {
7982 		hdd_err_rl("mlo_vdev_stats: failed to get bss peer mld mac");
7983 		return false;
7984 	}
7985 
7986 	is_mld_req = qdf_is_macaddr_equal(&peer_mld_mac,
7987 					  (struct qdf_mac_addr *)mac);
7988 	per_link_stats_cap = wlan_hdd_is_per_link_stats_supported(hdd_ctx);
7989 
7990 	if (is_mld_req && per_link_stats_cap) {
7991 		hdd_debug_rl("Fetching Aggregated station stats");
7992 		return true;
7993 	}
7994 
7995 	return false;
7996 }
7997 
7998 /**
7999  * wlan_hdd_send_mlo_station_stats() - send station stats to userspace
8000  * @adapter: Pointer to hdd adapter
8001  * @hdd_ctx: Pointer to hdd context
8002  * @mac: mac address
8003  * @sinfo: kernel station_info struct to populate
8004  *
8005  * Return: 0 on success; errno on failure
8006  */
8007 static int wlan_hdd_send_mlo_station_stats(struct hdd_adapter *adapter,
8008 					   struct hdd_context *hdd_ctx,
8009 					   const uint8_t *mac,
8010 					   struct station_info *sinfo)
8011 {
8012 	struct wlan_hdd_link_info *link_info;
8013 
8014 	if (!wlan_hdd_is_mlo_connection(adapter->deflink)) {
8015 		hdd_nofl_debug("Fetching station stats for legacy connection");
8016 		return wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
8017 	}
8018 
8019 	link_info = hdd_get_link_info_by_bssid(hdd_ctx, mac);
8020 	if (!link_info) {
8021 		if (wlan_is_mlo_aggregated_stats_allowed(adapter, mac))
8022 			return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo);
8023 
8024 		hdd_debug_rl("Invalid bssid");
8025 		return -EINVAL;
8026 	}
8027 	return wlan_hdd_get_sta_stats(link_info, mac, sinfo);
8028 }
8029 
8030 /**
8031  * __wlan_hdd_cfg80211_get_station() - get station statistics
8032  * @wiphy: Pointer to wiphy
8033  * @dev: Pointer to network device
8034  * @mac: Pointer to mac
8035  * @sinfo: Pointer to station info
8036  *
8037  * Return: 0 for success, non-zero for failure
8038  */
8039 static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
8040 					   struct net_device *dev,
8041 					   const uint8_t *mac,
8042 					   struct station_info *sinfo)
8043 {
8044 	int errno;
8045 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8046 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
8047 	struct hdd_station_info *stainfo;
8048 	bool get_peer_info_enable;
8049 	QDF_STATUS qdf_status;
8050 	struct wlan_hdd_link_info *link_info = adapter->deflink;
8051 
8052 	hdd_enter_dev(dev);
8053 
8054 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
8055 		hdd_err("Command not allowed in FTM mode");
8056 		return -EINVAL;
8057 	}
8058 
8059 	if (wlan_hdd_validate_context(hdd_ctx))
8060 		return -EINVAL;
8061 
8062 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
8063 		return -EINVAL;
8064 
8065 	hdd_nofl_debug("Stats request on MAC: " QDF_MAC_ADDR_FMT,
8066 		       QDF_MAC_ADDR_REF(mac));
8067 
8068 	if (!mac || qdf_is_macaddr_zero((struct qdf_mac_addr *)mac)) {
8069 		hdd_err("Invalid MAC addr");
8070 		return -EINVAL;
8071 	}
8072 
8073 	if (adapter->device_mode == QDF_SAP_MODE ||
8074 	    adapter->device_mode == QDF_P2P_GO_MODE) {
8075 		qdf_status = ucfg_mlme_get_sap_get_peer_info(
8076 				hdd_ctx->psoc, &get_peer_info_enable);
8077 		if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) {
8078 			stainfo = hdd_get_sta_info_by_mac(
8079 					&adapter->sta_info_list, mac,
8080 					STA_INFO_WLAN_HDD_CFG80211_GET_STATION);
8081 			if (!stainfo) {
8082 				hdd_debug("Peer " QDF_MAC_ADDR_FMT " not found",
8083 					  QDF_MAC_ADDR_REF(mac));
8084 				return -EINVAL;
8085 			}
8086 
8087 			errno = wlan_hdd_get_station_remote(wiphy, dev,
8088 							    stainfo, sinfo);
8089 			hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo,
8090 					     true,
8091 					STA_INFO_WLAN_HDD_CFG80211_GET_STATION
8092 					);
8093 			if (!errno)
8094 				return 0;
8095 		}
8096 		return wlan_hdd_get_sap_stats(link_info, sinfo);
8097 	}
8098 
8099 	return wlan_hdd_send_mlo_station_stats(adapter, hdd_ctx, mac, sinfo);
8100 }
8101 
8102 /**
8103  * _wlan_hdd_cfg80211_get_station() - get station statistics
8104  *
8105  * @wiphy: Pointer to wiphy
8106  * @dev: Pointer to network device
8107  * @mac: Pointer to mac
8108  * @sinfo: Pointer to station info
8109  *
8110  * This API tries runtime PM suspend right away after getting station
8111  * statistics.
8112  *
8113  * Return: 0 for success, non-zero for failure
8114  */
8115 static int _wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
8116 					  struct net_device *dev,
8117 					  const uint8_t *mac,
8118 					  struct station_info *sinfo)
8119 {
8120 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
8121 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8122 	int errno;
8123 	QDF_STATUS status;
8124 
8125 	errno = wlan_hdd_validate_context(hdd_ctx);
8126 	if (errno)
8127 		return errno;
8128 
8129 	if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) {
8130 		hdd_debug("Link Switch in progress, can't process request");
8131 		return -EBUSY;
8132 	}
8133 
8134 	status = wlan_hdd_stats_request_needed(adapter);
8135 	if (QDF_IS_STATUS_ERROR(status)) {
8136 		if (status == QDF_STATUS_E_ALREADY)
8137 			get_station_fw_request_needed = false;
8138 		else
8139 			return -EINVAL;
8140 	}
8141 
8142 	if (get_station_fw_request_needed) {
8143 		errno = wlan_hdd_qmi_get_sync_resume();
8144 		if (errno) {
8145 			hdd_err("qmi sync resume failed: %d", errno);
8146 			return errno;
8147 		}
8148 	}
8149 
8150 	errno = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
8151 
8152 	if (get_station_fw_request_needed)
8153 		wlan_hdd_qmi_put_suspend();
8154 
8155 	get_station_fw_request_needed = true;
8156 
8157 	return errno;
8158 }
8159 
8160 /**
8161  * wlan_hdd_cfg80211_get_station() - get station statistics
8162  * @wiphy: Pointer to wiphy
8163  * @dev: Pointer to network device
8164  * @mac: Pointer to mac
8165  * @sinfo: Pointer to station info
8166  *
8167  * Return: 0 for success, non-zero for failure
8168  */
8169 int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
8170 				  struct net_device *dev, const uint8_t *mac,
8171 				  struct station_info *sinfo)
8172 {
8173 	int errno;
8174 	struct osif_vdev_sync *vdev_sync;
8175 
8176 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
8177 	if (errno)
8178 		return errno;
8179 
8180 	errno = _wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
8181 
8182 	osif_vdev_sync_op_stop(vdev_sync);
8183 
8184 	return errno;
8185 }
8186 
8187 /**
8188  * __wlan_hdd_cfg80211_dump_station() - dump station statistics
8189  * @wiphy: Pointer to wiphy
8190  * @dev: Pointer to network device
8191  * @idx: variable to station index, kernel iterate all stations over idx
8192  * @mac: Pointer to mac
8193  * @sinfo: Pointer to station info
8194  *
8195  * Return: 0 for success, non-zero for failure
8196  */
8197 static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
8198 				struct net_device *dev,
8199 				int idx, u8 *mac,
8200 				struct station_info *sinfo)
8201 {
8202 	int errno;
8203 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8204 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
8205 	struct hdd_station_info *stainfo;
8206 	bool get_peer_info_enable;
8207 	QDF_STATUS qdf_status;
8208 
8209 	hdd_debug("idx: %d", idx);
8210 
8211 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
8212 		hdd_err("Command not allowed in FTM mode");
8213 		return -EINVAL;
8214 	}
8215 
8216 	if (wlan_hdd_validate_context(hdd_ctx))
8217 		return -EINVAL;
8218 
8219 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
8220 		return -EINVAL;
8221 
8222 	if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) {
8223 		hdd_debug("Link Switch in progress, can't process request");
8224 		return -EBUSY;
8225 	}
8226 
8227 	if (adapter->device_mode == QDF_SAP_MODE ||
8228 	    adapter->device_mode == QDF_P2P_GO_MODE) {
8229 		qdf_status = ucfg_mlme_get_sap_get_peer_info(
8230 				hdd_ctx->psoc, &get_peer_info_enable);
8231 		if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) {
8232 			stainfo = hdd_get_sta_info_by_id(
8233 					&adapter->sta_info_list,
8234 					idx,
8235 					STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION
8236 					);
8237 			if (!stainfo) {
8238 				hdd_err("peer idx %d NOT FOUND", idx);
8239 				return -ENOENT;
8240 			}
8241 
8242 			qdf_mem_copy(mac, &stainfo->sta_mac.bytes,
8243 				     QDF_MAC_ADDR_SIZE);
8244 			errno = wlan_hdd_get_station_remote(wiphy, dev,
8245 							    stainfo, sinfo);
8246 			hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo,
8247 					     true,
8248 					STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION
8249 					);
8250 		} else {
8251 			errno = -EINVAL;
8252 			hdd_err("sap get peer info disabled!");
8253 		}
8254 	} else {
8255 		if (idx != 0)
8256 			return -ENOENT;
8257 
8258 		qdf_mem_copy(mac, dev->dev_addr, QDF_MAC_ADDR_SIZE);
8259 
8260 		if (wlan_hdd_is_mlo_connection(adapter->deflink) &&
8261 		    wlan_hdd_is_per_link_stats_supported(hdd_ctx))
8262 			return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo);
8263 
8264 		hdd_nofl_debug("Sending Assoc Link stats");
8265 		errno = wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
8266 	}
8267 	return errno;
8268 }
8269 
8270 /**
8271  * wlan_hdd_cfg80211_dump_station() - dump station statistics
8272  * @wiphy: Pointer to wiphy
8273  * @dev: Pointer to network device
8274  * @idx: variable to determine whether to get stats or not
8275  * @mac: Pointer to mac
8276  * @sinfo: Pointer to station info
8277  *
8278  * Return: 0 for success, non-zero for failure
8279  */
8280 int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
8281 				struct net_device *dev,
8282 				int idx, u8 *mac,
8283 				struct station_info *sinfo)
8284 {
8285 	int errno;
8286 	struct osif_vdev_sync *vdev_sync;
8287 
8288 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
8289 	if (errno)
8290 		return errno;
8291 
8292 	errno = wlan_hdd_qmi_get_sync_resume();
8293 	if (errno) {
8294 		hdd_err("qmi sync resume failed: %d", errno);
8295 		goto end;
8296 	}
8297 
8298 	errno = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
8299 
8300 	wlan_hdd_qmi_put_suspend();
8301 
8302 end:
8303 	osif_vdev_sync_op_stop(vdev_sync);
8304 
8305 	return errno;
8306 }
8307 
8308 /**
8309  * hdd_get_stats() - Function to retrieve interface statistics
8310  * @dev: pointer to network device
8311  *
8312  * This function is the ndo_get_stats method for all netdevs
8313  * registered with the kernel
8314  *
8315  * Return: pointer to net_device_stats structure
8316  */
8317 struct net_device_stats *hdd_get_stats(struct net_device *dev)
8318 {
8319 	return (struct net_device_stats *)ucfg_dp_get_dev_stats(dev);
8320 }
8321 
8322 /*
8323  * FW sends value of cycle_count, rx_clear_count and tx_frame_count in usec.
8324  */
8325 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
8326 static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
8327 				    struct scan_chan_info *chan_info,
8328 				    struct ieee80211_channel *channels)
8329 {
8330 	if (channels->center_freq != (uint16_t)chan_info->freq)
8331 		return false;
8332 
8333 	survey->channel = channels;
8334 	survey->noise = chan_info->noise_floor;
8335 	survey->filled = 0;
8336 
8337 	if (chan_info->noise_floor)
8338 		survey->filled |= SURVEY_INFO_NOISE_DBM;
8339 
8340 	if (opfreq == chan_info->freq)
8341 		survey->filled |= SURVEY_INFO_IN_USE;
8342 
8343 	survey->time = chan_info->cycle_count;
8344 	survey->time_busy = chan_info->rx_clear_count;
8345 	survey->time_tx = chan_info->tx_frame_count;
8346 
8347 	survey->filled |= SURVEY_INFO_TIME |
8348 			  SURVEY_INFO_TIME_BUSY |
8349 			  SURVEY_INFO_TIME_TX;
8350 	return true;
8351 }
8352 #else
8353 static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
8354 				    struct scan_chan_info *chan_info,
8355 				    struct ieee80211_channel *channels)
8356 {
8357 	if (channels->center_freq != (uint16_t)chan_info->freq)
8358 		return false;
8359 
8360 	survey->channel = channels;
8361 	survey->noise = chan_info->noise_floor;
8362 	survey->filled = 0;
8363 
8364 	if (chan_info->noise_floor)
8365 		survey->filled |= SURVEY_INFO_NOISE_DBM;
8366 
8367 	if (opfreq == chan_info->freq)
8368 		survey->filled |= SURVEY_INFO_IN_USE;
8369 
8370 	survey->channel_time = chan_info->cycle_count;
8371 	survey->channel_time_busy = chan_info->rx_clear_count;
8372 	survey->channel_time_tx = chan_info->tx_frame_count;
8373 
8374 	survey->filled |= SURVEY_INFO_CHANNEL_TIME |
8375 			  SURVEY_INFO_CHANNEL_TIME_BUSY |
8376 			  SURVEY_INFO_CHANNEL_TIME_TX;
8377 	return true;
8378 }
8379 #endif
8380 
8381 static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
8382 					struct hdd_adapter *adapter,
8383 					struct survey_info *survey, int idx)
8384 {
8385 	bool filled = false;
8386 	int i, j = 0;
8387 	uint32_t opfreq = 0; /* Initialization Required */
8388 	struct hdd_context *hdd_ctx;
8389 
8390 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8391 	sme_get_operation_channel(hdd_ctx->mac_handle, &opfreq,
8392 				  adapter->deflink->vdev_id);
8393 
8394 	mutex_lock(&hdd_ctx->chan_info_lock);
8395 
8396 	for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) {
8397 		if (!wiphy->bands[i])
8398 			continue;
8399 
8400 		for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
8401 			struct ieee80211_supported_band *band = wiphy->bands[i];
8402 
8403 			filled = wlan_fill_survey_result(survey, opfreq,
8404 				&hdd_ctx->chan_info[idx],
8405 				&band->channels[j]);
8406 		}
8407 	}
8408 	mutex_unlock(&hdd_ctx->chan_info_lock);
8409 
8410 	return filled;
8411 }
8412 
8413 /**
8414  * __wlan_hdd_cfg80211_dump_survey() - get survey related info
8415  * @wiphy: Pointer to wiphy
8416  * @dev: Pointer to network device
8417  * @idx: Index
8418  * @survey: Pointer to survey info
8419  *
8420  * Return: 0 for success, non-zero for failure
8421  */
8422 static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
8423 					   struct net_device *dev,
8424 					   int idx, struct survey_info *survey)
8425 {
8426 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8427 	struct hdd_context *hdd_ctx;
8428 	int status;
8429 	bool filled = false;
8430 
8431 	if (idx > NUM_CHANNELS - 1)
8432 		return -ENOENT;
8433 
8434 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8435 	status = wlan_hdd_validate_context(hdd_ctx);
8436 	if (0 != status)
8437 		return status;
8438 
8439 	if (!hdd_ctx->chan_info) {
8440 		hdd_debug("chan_info is NULL");
8441 		return -EINVAL;
8442 	}
8443 
8444 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
8445 		hdd_err("Command not allowed in FTM mode");
8446 		return -EINVAL;
8447 	}
8448 
8449 	if (!ucfg_scan_is_snr_monitor_enabled(hdd_ctx->psoc))
8450 		return -ENONET;
8451 
8452 	if (hdd_cm_is_vdev_roaming(adapter->deflink)) {
8453 		hdd_debug("Roaming in progress, hence return");
8454 		return -ENONET;
8455 	}
8456 
8457 	filled = wlan_hdd_update_survey_info(wiphy, adapter, survey, idx);
8458 
8459 	if (!filled)
8460 		return -ENOENT;
8461 
8462 	return 0;
8463 }
8464 
8465 /**
8466  * wlan_hdd_cfg80211_dump_survey() - get survey related info
8467  * @wiphy: Pointer to wiphy
8468  * @dev: Pointer to network device
8469  * @idx: Index
8470  * @survey: Pointer to survey info
8471  *
8472  * Return: 0 for success, non-zero for failure
8473  */
8474 int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
8475 				  struct net_device *dev,
8476 				  int idx, struct survey_info *survey)
8477 {
8478 	int errno;
8479 	struct osif_vdev_sync *vdev_sync;
8480 
8481 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
8482 	if (errno)
8483 		return errno;
8484 
8485 	errno = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
8486 
8487 	osif_vdev_sync_op_stop(vdev_sync);
8488 
8489 	return errno;
8490 }
8491 
8492 /**
8493  * hdd_display_hif_stats() - display hif stats
8494  *
8495  * Return: none
8496  *
8497  */
8498 void hdd_display_hif_stats(void)
8499 {
8500 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
8501 
8502 	if (!hif_ctx)
8503 		return;
8504 
8505 	hif_display_stats(hif_ctx);
8506 }
8507 
8508 /**
8509  * hdd_clear_hif_stats() - clear hif stats
8510  *
8511  * Return: none
8512  */
8513 void hdd_clear_hif_stats(void)
8514 {
8515 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
8516 
8517 	if (!hif_ctx)
8518 		return;
8519 	hif_clear_stats(hif_ctx);
8520 }
8521 
8522 /**
8523  * hdd_is_rcpi_applicable() - validates RCPI request
8524  * @adapter: adapter upon which the measurement is requested
8525  * @mac_addr: peer addr for which measurement is requested
8526  * @rcpi_value: pointer to where the RCPI should be returned
8527  * @reassoc: used to return cached RCPI during reassoc
8528  *
8529  * Return: true for success, false for failure
8530  */
8531 
8532 static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter,
8533 				   struct qdf_mac_addr *mac_addr,
8534 				   int32_t *rcpi_value,
8535 				   bool *reassoc)
8536 {
8537 	struct hdd_station_ctx *hdd_sta_ctx;
8538 
8539 	if (adapter->device_mode == QDF_STA_MODE ||
8540 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
8541 		hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
8542 		if (!hdd_cm_is_vdev_associated(adapter->deflink))
8543 			return false;
8544 
8545 		if (hdd_cm_is_vdev_roaming(adapter->deflink)) {
8546 			/* return the cached rcpi, if mac addr matches */
8547 			hdd_debug("Roaming in progress, return cached RCPI");
8548 			if (!qdf_mem_cmp(&adapter->rcpi.mac_addr,
8549 					 mac_addr, sizeof(*mac_addr))) {
8550 				*rcpi_value = adapter->rcpi.rcpi;
8551 				*reassoc = true;
8552 				return true;
8553 			}
8554 			return false;
8555 		}
8556 
8557 		if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssid,
8558 				sizeof(*mac_addr))) {
8559 			hdd_err("mac addr is different from bssid connected");
8560 			return false;
8561 		}
8562 	} else if (adapter->device_mode == QDF_SAP_MODE ||
8563 		   adapter->device_mode == QDF_P2P_GO_MODE) {
8564 		if (!test_bit(SOFTAP_BSS_STARTED,
8565 			      &adapter->deflink->link_flags)) {
8566 			hdd_err("Invalid rcpi request, softap not started");
8567 			return false;
8568 		}
8569 
8570 		/* check if peer mac addr is associated to softap */
8571 		if (!hdd_is_peer_associated(adapter, mac_addr)) {
8572 			hdd_err("invalid peer mac-addr: not associated");
8573 			return false;
8574 		}
8575 	} else {
8576 		hdd_err("Invalid rcpi request");
8577 		return false;
8578 	}
8579 
8580 	*reassoc = false;
8581 	return true;
8582 }
8583 
8584 /**
8585  * wlan_hdd_get_rcpi_cb() - callback function for rcpi response
8586  * @context: Pointer to rcpi context
8587  * @mac_addr: peer MAC address
8588  * @rcpi: RCPI response
8589  * @status: QDF_STATUS of the request
8590  *
8591  * Return: None
8592  */
8593 static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr,
8594 				 int32_t rcpi, QDF_STATUS status)
8595 {
8596 	struct osif_request *request;
8597 	struct rcpi_info *priv;
8598 
8599 	if (!context) {
8600 		hdd_err("No rcpi context");
8601 		return;
8602 	}
8603 
8604 	request = osif_request_get(context);
8605 	if (!request) {
8606 		hdd_err("Obsolete RCPI request");
8607 		return;
8608 	}
8609 
8610 	priv = osif_request_priv(request);
8611 	priv->mac_addr = mac_addr;
8612 
8613 	if (!QDF_IS_STATUS_SUCCESS(status)) {
8614 		priv->rcpi = 0;
8615 		hdd_err("Error in computing RCPI");
8616 	} else {
8617 		priv->rcpi = rcpi;
8618 	}
8619 
8620 	osif_request_complete(request);
8621 	osif_request_put(request);
8622 }
8623 
8624 /**
8625  * wlan_hdd_get_rcpi() - local function to get RCPI
8626  * @adapter: adapter upon which the measurement is requested
8627  * @mac: peer addr for which measurement is requested
8628  * @rcpi_value: pointer to where the RCPI should be returned
8629  * @measurement_type: type of rcpi measurement
8630  *
8631  * Return: 0 for success, non-zero for failure
8632  */
8633 int wlan_hdd_get_rcpi(struct hdd_adapter *adapter,
8634 		      uint8_t *mac,
8635 		      int32_t *rcpi_value,
8636 		      enum rcpi_measurement_type measurement_type)
8637 {
8638 	struct hdd_context *hdd_ctx;
8639 	int status = 0, ret = 0;
8640 	struct qdf_mac_addr mac_addr;
8641 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
8642 	struct sme_rcpi_req *rcpi_req;
8643 	void *cookie;
8644 	struct rcpi_info *priv;
8645 	struct osif_request *request;
8646 	static const struct osif_request_params params = {
8647 		.priv_size = sizeof(*priv),
8648 		.timeout_ms = WLAN_WAIT_TIME_RCPI,
8649 	};
8650 	bool reassoc;
8651 
8652 	hdd_enter();
8653 
8654 	/* initialize the rcpi value to zero, useful in error cases */
8655 	*rcpi_value = 0;
8656 
8657 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
8658 		hdd_err("Command not allowed in FTM mode");
8659 		return -EINVAL;
8660 	}
8661 
8662 	if (!adapter) {
8663 		hdd_warn("adapter context is NULL");
8664 		return -EINVAL;
8665 	}
8666 
8667 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8668 	status = wlan_hdd_validate_context(hdd_ctx);
8669 	if (status)
8670 		return -EINVAL;
8671 
8672 	if (!hdd_ctx->rcpi_enabled) {
8673 		hdd_debug("RCPI not supported");
8674 		return -EINVAL;
8675 	}
8676 
8677 	if (!mac) {
8678 		hdd_warn("RCPI peer mac-addr is NULL");
8679 		return -EINVAL;
8680 	}
8681 
8682 	qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE);
8683 
8684 	if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc))
8685 		return -EINVAL;
8686 	if (reassoc)
8687 		return 0;
8688 
8689 	rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
8690 	if (!rcpi_req)
8691 		return -EINVAL;
8692 
8693 	request = osif_request_alloc(&params);
8694 	if (!request) {
8695 		hdd_err("Request allocation failure");
8696 		qdf_mem_free(rcpi_req);
8697 		return -ENOMEM;
8698 	}
8699 	cookie = osif_request_cookie(request);
8700 
8701 	rcpi_req->mac_addr = mac_addr;
8702 	rcpi_req->session_id = adapter->deflink->vdev_id;
8703 	rcpi_req->measurement_type = measurement_type;
8704 	rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb;
8705 	rcpi_req->rcpi_context = cookie;
8706 
8707 	qdf_status = sme_get_rcpi(hdd_ctx->mac_handle, rcpi_req);
8708 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
8709 		hdd_err("Unable to retrieve RCPI");
8710 		status = qdf_status_to_os_return(qdf_status);
8711 		goto out;
8712 	}
8713 
8714 	/* request was sent -- wait for the response */
8715 	ret = osif_request_wait_for_response(request);
8716 	if (ret) {
8717 		hdd_err("SME timed out while retrieving RCPI");
8718 		status = -EINVAL;
8719 		goto out;
8720 	}
8721 
8722 	/* update the adapter with the fresh results */
8723 	priv = osif_request_priv(request);
8724 	adapter->rcpi.mac_addr = priv->mac_addr;
8725 	adapter->rcpi.rcpi = priv->rcpi;
8726 	if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) {
8727 		hdd_err("mis match of mac addr from call-back");
8728 		status = -EINVAL;
8729 		goto out;
8730 	}
8731 
8732 	*rcpi_value = adapter->rcpi.rcpi;
8733 	hdd_debug("RCPI = %d", *rcpi_value);
8734 out:
8735 	qdf_mem_free(rcpi_req);
8736 	osif_request_put(request);
8737 
8738 	hdd_exit();
8739 	return status;
8740 }
8741 
8742 #ifdef WLAN_FEATURE_MIB_STATS
8743 QDF_STATUS wlan_hdd_get_mib_stats(struct hdd_adapter *adapter)
8744 {
8745 	int ret = 0;
8746 	struct stats_event *stats;
8747 	struct wlan_objmgr_vdev *vdev;
8748 
8749 	if (!adapter) {
8750 		hdd_err("Invalid context, adapter");
8751 		return QDF_STATUS_E_FAULT;
8752 	}
8753 
8754 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
8755 					   WLAN_OSIF_STATS_ID);
8756 	if (!vdev)
8757 		return QDF_STATUS_E_FAULT;
8758 
8759 	stats = wlan_cfg80211_mc_cp_stats_get_mib_stats(vdev, &ret);
8760 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
8761 	if (ret || !stats) {
8762 		wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
8763 		return ret;
8764 	}
8765 
8766 	hdd_debugfs_process_mib_stats(adapter, stats);
8767 
8768 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
8769 	return ret;
8770 }
8771 #endif
8772 
8773 QDF_STATUS wlan_hdd_get_rssi(struct wlan_hdd_link_info *link_info,
8774 			     int8_t *rssi_value)
8775 {
8776 	int ret = 0, i;
8777 	struct hdd_station_ctx *sta_ctx;
8778 	struct stats_event *rssi_info;
8779 	struct wlan_objmgr_vdev *vdev;
8780 
8781 	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
8782 		hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
8783 			cds_get_driver_state());
8784 		/* return a cached value */
8785 		*rssi_value = link_info->rssi;
8786 		return QDF_STATUS_SUCCESS;
8787 	}
8788 
8789 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
8790 	if (!hdd_cm_is_vdev_associated(link_info)) {
8791 		hdd_debug("Not associated!, rssi on disconnect %d",
8792 			  link_info->rssi_on_disconnect);
8793 		*rssi_value = link_info->rssi_on_disconnect;
8794 		return QDF_STATUS_SUCCESS;
8795 	}
8796 
8797 	if (hdd_cm_is_vdev_roaming(link_info)) {
8798 		hdd_debug("Roaming in progress, return cached RSSI");
8799 		*rssi_value = link_info->rssi;
8800 		return QDF_STATUS_SUCCESS;
8801 	}
8802 
8803 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
8804 	if (!vdev) {
8805 		*rssi_value = link_info->rssi;
8806 		return QDF_STATUS_SUCCESS;
8807 	}
8808 
8809 	rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi(
8810 			vdev,
8811 			sta_ctx->conn_info.bssid.bytes,
8812 			&ret);
8813 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
8814 	if (ret || !rssi_info) {
8815 		wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
8816 		return ret;
8817 	}
8818 
8819 	for (i = 0; i < rssi_info->num_peer_stats; i++) {
8820 		if (!qdf_mem_cmp(rssi_info->peer_stats[i].peer_macaddr,
8821 				 sta_ctx->conn_info.bssid.bytes,
8822 				 QDF_MAC_ADDR_SIZE)) {
8823 			*rssi_value = rssi_info->peer_stats[i].peer_rssi;
8824 			hdd_debug("RSSI = %d", *rssi_value);
8825 			wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
8826 			return QDF_STATUS_SUCCESS;
8827 		}
8828 	}
8829 
8830 	wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
8831 	hdd_err("bss peer not present in returned result");
8832 	return QDF_STATUS_E_FAULT;
8833 }
8834 
8835 struct snr_priv {
8836 	int8_t snr;
8837 };
8838 
8839 /**
8840  * hdd_get_snr_cb() - "Get SNR" callback function
8841  * @snr: Current SNR of the station
8842  * @context: opaque context originally passed to SME.  HDD always passes
8843  *	a cookie for the request context
8844  *
8845  * Return: None
8846  */
8847 static void hdd_get_snr_cb(int8_t snr, void *context)
8848 {
8849 	struct osif_request *request;
8850 	struct snr_priv *priv;
8851 
8852 	request = osif_request_get(context);
8853 	if (!request) {
8854 		hdd_err("Obsolete request");
8855 		return;
8856 	}
8857 
8858 	/* propagate response back to requesting thread */
8859 	priv = osif_request_priv(request);
8860 	priv->snr = snr;
8861 	osif_request_complete(request);
8862 	osif_request_put(request);
8863 }
8864 
8865 QDF_STATUS wlan_hdd_get_snr(struct wlan_hdd_link_info *link_info, int8_t *snr)
8866 {
8867 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
8868 	struct hdd_station_ctx *sta_ctx;
8869 	QDF_STATUS status;
8870 	int ret;
8871 	void *cookie;
8872 	struct osif_request *request;
8873 	struct snr_priv *priv;
8874 	static const struct osif_request_params params = {
8875 		.priv_size = sizeof(*priv),
8876 		.timeout_ms = WLAN_WAIT_TIME_STATS,
8877 	};
8878 
8879 	hdd_enter();
8880 
8881 	ret = wlan_hdd_validate_context(hdd_ctx);
8882 	if (ret)
8883 		return QDF_STATUS_E_FAULT;
8884 
8885 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
8886 
8887 	request = osif_request_alloc(&params);
8888 	if (!request) {
8889 		hdd_err("Request allocation failure");
8890 		return QDF_STATUS_E_FAULT;
8891 	}
8892 	cookie = osif_request_cookie(request);
8893 
8894 	status = sme_get_snr(hdd_ctx->mac_handle, hdd_get_snr_cb,
8895 			     sta_ctx->conn_info.bssid, cookie);
8896 	if (QDF_STATUS_SUCCESS != status) {
8897 		hdd_err("Unable to retrieve RSSI");
8898 		/* we'll returned a cached value below */
8899 	} else {
8900 		/* request was sent -- wait for the response */
8901 		ret = osif_request_wait_for_response(request);
8902 		if (ret) {
8903 			hdd_err("SME timed out while retrieving SNR");
8904 			/* we'll now returned a cached value below */
8905 		} else {
8906 			/* update the adapter with the fresh results */
8907 			priv = osif_request_priv(request);
8908 			link_info->snr = priv->snr;
8909 		}
8910 	}
8911 
8912 	/*
8913 	 * either we never sent a request, we sent a request and
8914 	 * received a response or we sent a request and timed out.
8915 	 * regardless we are done with the request.
8916 	 */
8917 	osif_request_put(request);
8918 
8919 	*snr = link_info->snr;
8920 	hdd_exit();
8921 	return QDF_STATUS_SUCCESS;
8922 }
8923 
8924 struct linkspeed_priv {
8925 	struct link_speed_info linkspeed_info;
8926 };
8927 
8928 static void
8929 hdd_get_link_speed_cb(struct link_speed_info *linkspeed_info, void *context)
8930 {
8931 	struct osif_request *request;
8932 	struct linkspeed_priv *priv;
8933 
8934 	if (!linkspeed_info) {
8935 		hdd_err("NULL linkspeed");
8936 		return;
8937 	}
8938 
8939 	request = osif_request_get(context);
8940 	if (!request) {
8941 		hdd_err("Obsolete request");
8942 		return;
8943 	}
8944 
8945 	priv = osif_request_priv(request);
8946 	priv->linkspeed_info = *linkspeed_info;
8947 	osif_request_complete(request);
8948 	osif_request_put(request);
8949 }
8950 
8951 int wlan_hdd_get_linkspeed_for_peermac(struct wlan_hdd_link_info *link_info,
8952 				       struct qdf_mac_addr *mac_address,
8953 				       uint32_t *linkspeed)
8954 {
8955 	int ret;
8956 	QDF_STATUS status;
8957 	void *cookie;
8958 	struct link_speed_info *linkspeed_info;
8959 	struct osif_request *request;
8960 	struct linkspeed_priv *priv;
8961 	struct hdd_adapter *adapter = link_info->adapter;
8962 	static const struct osif_request_params params = {
8963 		.priv_size = sizeof(*priv),
8964 		.timeout_ms = WLAN_WAIT_TIME_STATS,
8965 	};
8966 
8967 	if (!linkspeed) {
8968 		hdd_err("NULL argument");
8969 		return -EINVAL;
8970 	}
8971 
8972 	request = osif_request_alloc(&params);
8973 	if (!request) {
8974 		hdd_err("Request allocation failure");
8975 		ret = -ENOMEM;
8976 		goto return_cached_value;
8977 	}
8978 
8979 	cookie = osif_request_cookie(request);
8980 	priv = osif_request_priv(request);
8981 
8982 	linkspeed_info = &priv->linkspeed_info;
8983 	qdf_copy_macaddr(&linkspeed_info->peer_macaddr, mac_address);
8984 	status = sme_get_link_speed(adapter->hdd_ctx->mac_handle,
8985 				    linkspeed_info,
8986 				    cookie, hdd_get_link_speed_cb);
8987 	if (QDF_IS_STATUS_ERROR(status)) {
8988 		hdd_err("Unable to retrieve statistics for link speed");
8989 		ret = qdf_status_to_os_return(status);
8990 		goto cleanup;
8991 	}
8992 	ret = osif_request_wait_for_response(request);
8993 	if (ret) {
8994 		hdd_err("SME timed out while retrieving link speed");
8995 		goto cleanup;
8996 	}
8997 	link_info->estimated_linkspeed = linkspeed_info->estLinkSpeed;
8998 
8999 cleanup:
9000 	/*
9001 	 * either we never sent a request, we sent a request and
9002 	 * received a response or we sent a request and timed out.
9003 	 * regardless we are done with the request.
9004 	 */
9005 	osif_request_put(request);
9006 
9007 return_cached_value:
9008 	*linkspeed = link_info->estimated_linkspeed;
9009 
9010 	return ret;
9011 }
9012 
9013 static uint32_t
9014 wlan_hdd_get_per_link_speed(struct wlan_hdd_link_info *link_info)
9015 {
9016 	uint32_t link_speed;
9017 	struct qdf_mac_addr bssid;
9018 
9019 	if (!hdd_cm_is_vdev_associated(link_info)) {
9020 		/* we are not connected so we don't have a classAstats */
9021 		hdd_debug("Not connected");
9022 		return 0;
9023 	}
9024 	qdf_copy_macaddr(&bssid,
9025 			 &link_info->session.station.conn_info.bssid);
9026 
9027 	if (wlan_hdd_get_linkspeed_for_peermac(link_info,
9028 					       &bssid, &link_speed)) {
9029 		hdd_err("Unable to retrieve SME linkspeed");
9030 		return 0;
9031 	}
9032 	hdd_debug("linkspeed = %d", link_speed);
9033 	return link_speed;
9034 }
9035 
9036 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
9037 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
9038 static uint32_t
9039 wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
9040 {
9041 	struct hdd_adapter *ml_adapter = NULL;
9042 	struct hdd_adapter *link_adapter = NULL;
9043 	struct hdd_mlo_adapter_info *mlo_adapter_info = NULL;
9044 	uint32_t link_speed = 0;
9045 	uint32_t per_speed;
9046 	uint8_t link_id;
9047 
9048 	ml_adapter = adapter;
9049 	if (hdd_adapter_is_link_adapter(ml_adapter))
9050 		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
9051 
9052 	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
9053 	for (link_id = 0; link_id < WLAN_MAX_MLD; link_id++) {
9054 		link_adapter = mlo_adapter_info->link_adapter[link_id];
9055 		if (qdf_unlikely(!link_adapter)) {
9056 			hdd_err("link_adapter[%d] is Null", link_id);
9057 			continue;
9058 		}
9059 		per_speed = wlan_hdd_get_per_link_speed(ml_adapter->deflink);
9060 		link_speed += per_speed;
9061 		hdd_debug("Link%d speed=%d, total speed=%d",
9062 			  link_id, per_speed, link_speed);
9063 	}
9064 	return link_speed;
9065 }
9066 #else
9067 static uint32_t
9068 wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
9069 {
9070 	struct wlan_hdd_link_info *link_info = NULL;
9071 	uint32_t link_speed = 0;
9072 	uint32_t per_speed;
9073 
9074 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
9075 		per_speed = wlan_hdd_get_per_link_speed(link_info);
9076 		link_speed += per_speed;
9077 		hdd_debug("per_speed=%d, link_speed=%d", per_speed, link_speed);
9078 	}
9079 	return link_speed;
9080 }
9081 #endif
9082 
9083 #else
9084 static uint32_t
9085 wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
9086 {
9087 	uint32_t link_speed = wlan_hdd_get_per_link_speed(adapter->deflink);
9088 
9089 	hdd_debug("Not support MLO, linkspeed = %d", link_speed);
9090 	return link_speed;
9091 }
9092 #endif
9093 
9094 int wlan_hdd_get_link_speed(struct wlan_hdd_link_info *link_info,
9095 			    uint32_t *link_speed)
9096 {
9097 	struct hdd_adapter *adapter =  link_info->adapter;
9098 	struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter);
9099 	int ret;
9100 
9101 	ret = wlan_hdd_validate_context(hddctx);
9102 	if (ret)
9103 		return ret;
9104 
9105 	/* Linkspeed is allowed for CLIENT/STA mode */
9106 	if (adapter->device_mode != QDF_P2P_CLIENT_MODE &&
9107 	    adapter->device_mode != QDF_STA_MODE) {
9108 		hdd_err("Link Speed is not allowed in Device mode %s(%d)",
9109 			qdf_opmode_str(adapter->device_mode),
9110 			adapter->device_mode);
9111 		return -ENOTSUPP;
9112 	}
9113 
9114 	if (wlan_hdd_is_mlo_connection(link_info))
9115 		*link_speed = wlan_hdd_get_mlo_link_speed(adapter);
9116 	else
9117 		*link_speed = wlan_hdd_get_per_link_speed(link_info);
9118 
9119 	/* linkspeed in units of 500 kbps */
9120 	*link_speed = (*link_speed) / 500;
9121 	return 0;
9122 }
9123 
9124 int wlan_hdd_get_sap_go_peer_linkspeed(struct wlan_hdd_link_info *link_info,
9125 				       uint32_t *link_speed,
9126 				       uint8_t *command,
9127 				       uint8_t command_len)
9128 {
9129 	int ret;
9130 	struct qdf_mac_addr mac_address;
9131 	char macaddr_string[MAC_ADDRESS_STR_LEN + 1];
9132 	uint8_t *value = command;
9133 	struct hdd_adapter *adapter = link_info->adapter;
9134 	struct hdd_station_info *sta_info, *tmp = NULL;
9135 
9136 	value = value + command_len;
9137 	ret = sscanf(value, "%17s", &macaddr_string);
9138 
9139 	if (ret != 1)
9140 		return -EINVAL;
9141 
9142 	macaddr_string[MAC_ADDRESS_STR_LEN - 1] = '\0';
9143 	if (!mac_pton(macaddr_string, mac_address.bytes)) {
9144 		hdd_err("String to Hex conversion Failed");
9145 		return -EINVAL;
9146 	}
9147 
9148 	hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp,
9149 				  STA_INFO_GET_SOFTAP_LINKSPEED) {
9150 		if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) {
9151 			if (qdf_is_macaddr_equal(&mac_address,
9152 						 &sta_info->sta_mac)) {
9153 				ret = wlan_hdd_get_linkspeed_for_peermac(
9154 							adapter->deflink,
9155 							&mac_address,
9156 							link_speed);
9157 				hdd_put_sta_info_ref(
9158 						&adapter->sta_info_list,
9159 						&sta_info, true,
9160 						STA_INFO_GET_SOFTAP_LINKSPEED);
9161 				if (tmp)
9162 					hdd_put_sta_info_ref(
9163 						&adapter->sta_info_list,
9164 						&tmp, true,
9165 						STA_INFO_GET_SOFTAP_LINKSPEED);
9166 				break;
9167 			}
9168 		}
9169 		hdd_put_sta_info_ref(&adapter->sta_info_list,
9170 				     &sta_info, true,
9171 				     STA_INFO_GET_SOFTAP_LINKSPEED);
9172 	}
9173 
9174 	if (ret) {
9175 		hdd_err("Unable to retrieve SAP/GO linkspeed");
9176 		return ret;
9177 	}
9178 
9179 	*link_speed = (*link_speed) / 500;
9180 	return 0;
9181 }
9182 #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER
9183 /**
9184  * wlan_hdd_get_per_peer_stats - get per peer stats if supported by FW
9185  * @link_info: Link info pointer of STA adapter to get stats for
9186  * @peer_stats: Pointer to peer_stats
9187  *
9188  * Return: QDF_STATUS
9189  */
9190 static QDF_STATUS
9191 wlan_hdd_get_per_peer_stats(struct wlan_hdd_link_info *link_info,
9192 			    struct cdp_peer_stats *peer_stats)
9193 {
9194 	QDF_STATUS status;
9195 	ol_txrx_soc_handle soc;
9196 	uint8_t *peer_mac;
9197 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
9198 
9199 	if (wlan_hdd_validate_context(hdd_ctx)) {
9200 		hdd_err("invalid hdd_ctx");
9201 		return QDF_STATUS_E_FAILURE;
9202 	}
9203 
9204 	soc = cds_get_context(QDF_MODULE_ID_SOC);
9205 	peer_mac = link_info->session.station.conn_info.bssid.bytes;
9206 
9207 	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx)) {
9208 		hdd_debug("mlo per link stats is not supported by FW");
9209 		status = cdp_host_get_peer_stats(soc, link_info->vdev_id,
9210 						 peer_mac, peer_stats);
9211 		return status;
9212 	}
9213 
9214 	status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
9215 						 peer_mac, peer_stats,
9216 						 CDP_WILD_PEER_TYPE,
9217 						 WLAN_MAX_MLD);
9218 	return status;
9219 }
9220 
9221 void wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info *link_info)
9222 {
9223 	struct cdp_peer_stats *peer_stats;
9224 	QDF_STATUS status;
9225 	struct wlan_objmgr_psoc *psoc;
9226 	struct hdd_stats *hdd_stats = &link_info->hdd_stats;
9227 
9228 	psoc = link_info->adapter->hdd_ctx->psoc;
9229 	if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc))
9230 		return;
9231 
9232 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
9233 	if (!peer_stats) {
9234 		hdd_err("Failed to malloc peer_stats");
9235 		return;
9236 	}
9237 
9238 	/*
9239 	 * If failed to get RX rates info, assign an invalid value to the
9240 	 * preamble, used to tell driver to report max rates. The rx_rate
9241 	 * and rx_mcs_index are also assigned with tx_rate and tx_mcs_index
9242 	 * if they are invalid after ASSOC/REASSOC/ROAMING
9243 	 */
9244 	status = wlan_hdd_get_per_peer_stats(link_info, peer_stats);
9245 	if (qdf_unlikely(QDF_IS_STATUS_ERROR(status)) ||
9246 	    qdf_unlikely(peer_stats->rx.last_rx_rate == 0)) {
9247 		hdd_debug("Driver failed to get rx rates, rx mcs=%d, status=%d",
9248 			  hdd_stats->class_a_stat.rx_mcs_index, status);
9249 		hdd_stats->class_a_stat.rx_preamble = INVALID_PREAMBLE;
9250 		if (hdd_stats->class_a_stat.rx_mcs_index == INVALID_MCS_IDX) {
9251 			hdd_stats->class_a_stat.rx_rate =
9252 				hdd_stats->class_a_stat.tx_rate;
9253 			hdd_stats->class_a_stat.rx_mcs_index =
9254 				hdd_stats->class_a_stat.tx_mcs_index;
9255 		}
9256 		qdf_mem_free(peer_stats);
9257 		return;
9258 	}
9259 
9260 	/*
9261 	 * The linkspeed calculated by driver is in kbps so we
9262 	 * convert it in units of 100 kbps expected by userspace
9263 	 */
9264 	hdd_stats->class_a_stat.rx_rate = peer_stats->rx.last_rx_rate / 100;
9265 	hdd_stats->class_a_stat.rx_mcs_index = peer_stats->rx.mcs_info;
9266 	hdd_stats->class_a_stat.rx_nss = peer_stats->rx.nss_info;
9267 	hdd_stats->class_a_stat.rx_gi = peer_stats->rx.gi_info;
9268 	hdd_stats->class_a_stat.rx_preamble = peer_stats->rx.preamble_info;
9269 	hdd_stats->class_a_stat.rx_bw = peer_stats->rx.bw_info;
9270 
9271 	qdf_mem_free(peer_stats);
9272 }
9273 #endif
9274 
9275 int wlan_hdd_get_station_stats(struct wlan_hdd_link_info *link_info)
9276 {
9277 	int ret = 0;
9278 	struct stats_event *stats;
9279 	struct wlan_objmgr_vdev *vdev;
9280 
9281 	if (!get_station_fw_request_needed) {
9282 		hdd_debug("return cached get_station stats");
9283 		return 0;
9284 	}
9285 
9286 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
9287 	if (!vdev)
9288 		return -EINVAL;
9289 
9290 	stats = wlan_cfg80211_mc_cp_stats_get_station_stats(vdev, &ret);
9291 	if (ret || !stats) {
9292 		hdd_err("Invalid stats");
9293 		goto out;
9294 	}
9295 
9296 	if (!stats->vdev_summary_stats || !stats->vdev_chain_rssi ||
9297 	    !stats->peer_adv_stats || !stats->pdev_stats) {
9298 		hdd_err("Invalid:%s%s%s%s",
9299 			stats->vdev_summary_stats ? "" : " vdev_summary_stats",
9300 			stats->vdev_chain_rssi ? "" : " vdev_chain_rssi",
9301 			stats->peer_adv_stats ? "" : " peer_adv_stats",
9302 			stats->pdev_stats ? "" : " pdev_stats");
9303 		ret = -EINVAL;
9304 		goto out;
9305 	}
9306 
9307 	/* update get stats cached time stamp */
9308 	hdd_update_station_stats_cached_timestamp(link_info->adapter);
9309 	hdd_update_link_state_cached_timestamp(link_info->adapter);
9310 	copy_station_stats_to_adapter(link_info, stats);
9311 out:
9312 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
9313 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
9314 	return ret;
9315 }
9316 
9317 #ifdef WLAN_FEATURE_BIG_DATA_STATS
9318 int wlan_hdd_get_big_data_station_stats(struct wlan_hdd_link_info *link_info)
9319 {
9320 	int ret = 0;
9321 	struct big_data_stats_event *big_data_stats;
9322 	struct wlan_objmgr_vdev *vdev;
9323 
9324 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
9325 	if (!vdev)
9326 		return -EINVAL;
9327 
9328 	big_data_stats = wlan_cfg80211_mc_cp_get_big_data_stats(vdev, &ret);
9329 	if (ret || !big_data_stats)
9330 		goto out;
9331 
9332 	copy_station_big_data_stats_to_adapter(link_info, big_data_stats);
9333 out:
9334 	if (big_data_stats)
9335 		wlan_cfg80211_mc_cp_stats_free_big_data_stats_event(
9336 								big_data_stats);
9337 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
9338 	return ret;
9339 }
9340 #endif
9341 
9342 struct temperature_priv {
9343 	int temperature;
9344 };
9345 
9346 /**
9347  * hdd_get_temperature_cb() - "Get Temperature" callback function
9348  * @temperature: measured temperature
9349  * @context: callback context
9350  *
9351  * This function is passed to sme_get_temperature() as the callback
9352  * function to be invoked when the temperature measurement is
9353  * available.
9354  *
9355  * Return: None
9356  */
9357 static void hdd_get_temperature_cb(int temperature, void *context)
9358 {
9359 	struct osif_request *request;
9360 	struct temperature_priv *priv;
9361 
9362 	hdd_enter();
9363 
9364 	request = osif_request_get(context);
9365 	if (!request) {
9366 		hdd_err("Obsolete request");
9367 		return;
9368 	}
9369 
9370 	priv = osif_request_priv(request);
9371 	priv->temperature = temperature;
9372 	osif_request_complete(request);
9373 	osif_request_put(request);
9374 	hdd_exit();
9375 }
9376 
9377 int wlan_hdd_get_temperature(struct hdd_adapter *adapter, int *temperature)
9378 {
9379 	QDF_STATUS status;
9380 	int ret;
9381 	void *cookie;
9382 	struct osif_request *request;
9383 	struct temperature_priv *priv;
9384 	static const struct osif_request_params params = {
9385 		.priv_size = sizeof(*priv),
9386 		.timeout_ms = WLAN_WAIT_TIME_STATS,
9387 	};
9388 
9389 	hdd_enter();
9390 	if (!adapter) {
9391 		hdd_err("adapter is NULL");
9392 		return -EPERM;
9393 	}
9394 
9395 	if (!wlan_psoc_nif_fw_ext_cap_get(adapter->hdd_ctx->psoc,
9396 					  WLAN_SOC_CEXT_TT_SUPPORT)) {
9397 		hdd_err("WMI_SERVICE_THERM_THROT service from FW is disable");
9398 		return -EINVAL;
9399 	}
9400 
9401 	request = osif_request_alloc(&params);
9402 	if (!request) {
9403 		hdd_err("Request allocation failure");
9404 		return -ENOMEM;
9405 	}
9406 	cookie = osif_request_cookie(request);
9407 	status = sme_get_temperature(adapter->hdd_ctx->mac_handle, cookie,
9408 				     hdd_get_temperature_cb);
9409 	if (QDF_STATUS_SUCCESS != status) {
9410 		hdd_err("Unable to retrieve temperature");
9411 	} else {
9412 		ret = osif_request_wait_for_response(request);
9413 		if (ret) {
9414 			hdd_err("SME timed out while retrieving temperature");
9415 		} else {
9416 			/* update the adapter with the fresh results */
9417 			priv = osif_request_priv(request);
9418 			if (priv->temperature)
9419 				adapter->temperature = priv->temperature;
9420 		}
9421 	}
9422 
9423 	/*
9424 	 * either we never sent a request, we sent a request and
9425 	 * received a response or we sent a request and timed out.
9426 	 * regardless we are done with the request.
9427 	 */
9428 	osif_request_put(request);
9429 
9430 	*temperature = adapter->temperature;
9431 	hdd_exit();
9432 	return 0;
9433 }
9434 
9435 #ifdef TX_MULTIQ_PER_AC
9436 void wlan_hdd_display_tx_multiq_stats(hdd_cb_handle context,
9437 				      qdf_netdev_t netdev)
9438 {
9439 	struct hdd_adapter *adapter;
9440 	struct wlan_hdd_link_info *link_info;
9441 	struct hdd_tx_rx_stats *stats;
9442 	uint32_t total_inv_sk_and_skb_hash = 0;
9443 	uint32_t total_qselect_existing_skb_hash = 0;
9444 	uint32_t total_qselect_sk_tx_map = 0;
9445 	uint32_t total_qselect_skb_hash = 0;
9446 	unsigned int i;
9447 
9448 	adapter = WLAN_HDD_GET_PRIV_PTR(netdev);
9449 	if (!adapter) {
9450 		hdd_err("adapter is null");
9451 		return;
9452 	}
9453 
9454 	link_info = adapter->deflink;
9455 
9456 	stats = &link_info->hdd_stats.tx_rx_stats;
9457 
9458 	for (i = 0; i < NUM_CPUS; i++) {
9459 		total_inv_sk_and_skb_hash +=
9460 					  stats->per_cpu[i].inv_sk_and_skb_hash;
9461 		total_qselect_existing_skb_hash +=
9462 				    stats->per_cpu[i].qselect_existing_skb_hash;
9463 		total_qselect_sk_tx_map += stats->per_cpu[i].qselect_sk_tx_map;
9464 		total_qselect_skb_hash +=
9465 					stats->per_cpu[i].qselect_skb_hash_calc;
9466 	}
9467 
9468 	hdd_debug("TX_MULTIQ: INV %u skb_hash %u sk_tx_map %u skb_hash_calc %u",
9469 		  total_inv_sk_and_skb_hash, total_qselect_existing_skb_hash,
9470 		  total_qselect_sk_tx_map, total_qselect_skb_hash);
9471 }
9472 #endif
9473 
9474 #ifdef QCA_SUPPORT_CP_STATS
9475 /**
9476  * hdd_lost_link_cp_stats_info_cb() - callback function to get lost
9477  * link information
9478  * @stats_ev: Stats event pointer
9479  * FW sends vdev stats on vdev down, this callback is registered
9480  * with cp_stats component to get the last available vdev stats
9481  * From the FW.
9482  *
9483  * Return: None
9484  */
9485 
9486 static void hdd_lost_link_cp_stats_info_cb(void *stats_ev)
9487 {
9488 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
9489 	struct stats_event *ev = stats_ev;
9490 	uint8_t i, vdev_id;
9491 	int8_t rssi;
9492 	struct hdd_station_ctx *sta_ctx;
9493 	struct wlan_hdd_link_info *link_info;
9494 	struct qdf_mac_addr *mac_addr;
9495 
9496 	if (wlan_hdd_validate_context(hdd_ctx))
9497 		return;
9498 
9499 	for (i = 0; i < ev->num_summary_stats; i++) {
9500 		vdev_id = ev->vdev_summary_stats[i].vdev_id;
9501 		link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
9502 		if (!link_info) {
9503 			hdd_debug("invalid vdev %d", vdev_id);
9504 			continue;
9505 		}
9506 
9507 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
9508 
9509 		rssi = ev->vdev_summary_stats[i].stats.rssi;
9510 		if (rssi == 0) {
9511 			hdd_debug_rl("Invalid RSSI value sent by FW");
9512 			return;
9513 		}
9514 		link_info->rssi_on_disconnect = rssi;
9515 		sta_ctx->cache_conn_info.signal = rssi;
9516 
9517 		mac_addr = hdd_adapter_get_link_mac_addr(link_info);
9518 		if (!mac_addr)
9519 			return;
9520 
9521 		hdd_debug("rssi %d for " QDF_MAC_ADDR_FMT,
9522 			  link_info->rssi_on_disconnect,
9523 			  QDF_MAC_ADDR_REF(&mac_addr->bytes[0]));
9524 
9525 	}
9526 }
9527 
9528 void wlan_hdd_register_cp_stats_cb(struct hdd_context *hdd_ctx)
9529 {
9530 	ucfg_mc_cp_stats_register_lost_link_info_cb(
9531 					hdd_ctx->psoc,
9532 					hdd_lost_link_cp_stats_info_cb);
9533 }
9534 #endif
9535 
9536 #if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_ROAM_INFO_STATS)
9537 #define ROAM_CACHED_STATS_MAX QCA_WLAN_VENDOR_ATTR_ROAM_CACHED_STATS_MAX
9538 
9539 #define EVENTS_CONFIGURE QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CONFIGURE
9540 #define SUSPEND_STATE    QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_SUSPEND_STATE
9541 
9542 #define ROAM_STATS_ROAM_TRIGGER_TIMESTAMP \
9543 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_TRIGGER_TIMESTAMP
9544 #define ROAM_STATS_TRIGGER_REASON \
9545 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TRIGGER_REASON
9546 #define ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT \
9547 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT
9548 #define ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT \
9549 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT
9550 #define ROAM_STATS_FINAL_BMISS_CNT \
9551 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FINAL_BMISS_CNT
9552 #define ROAM_STATS_CONSECUTIVE_BMISS_CNT \
9553 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONSECUTIVE_BMISS_CNT
9554 #define ROAM_STATS_BMISS_QOS_NULL_SUCCESS \
9555 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BMISS_QOS_NULL_SUCCESS
9556 #define ROAM_STATS_POOR_RSSI_CURRENT_RSSI \
9557 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_CURRENT_RSSI
9558 #define ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD \
9559 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD
9560 #define ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS \
9561 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS
9562 #define ROAM_STATS_BETTER_RSSI_CURRENT_RSSI \
9563 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_CURRENT_RSSI
9564 #define ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD \
9565 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD
9566 #define ROAM_STATS_CONGESTION_RX_TPUT \
9567 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_RX_TPUT
9568 #define ROAM_STATS_CONGESTION_TX_TPUT \
9569 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_TX_TPUT
9570 #define ROAM_STATS_CONGESTION_ROAMABLE_CNT \
9571 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_ROAMABLE_CNT
9572 #define ROAM_STATS_USER_TRIGGER_INVOKE_REASON \
9573 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_USER_TRIGGER_INVOKE_REASON
9574 #define ROAM_STATS_BTM_REQUEST_MODE \
9575 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQUEST_MODE
9576 #define ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME \
9577 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME
9578 #define ROAM_STATS_BTM_VALID_INTERNAL \
9579 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_VALID_INTERNAL
9580 #define ROAM_STATS_BTM_CANDIDATE_LIST_CNT \
9581 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_CANDIDATE_LIST_CNT
9582 #define ROAM_STATS_BTM_RESPONSE_STATUS_CODE \
9583 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_RESPONSE_STATUS_CODE
9584 #define ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT \
9585 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT
9586 #define ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT \
9587 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT
9588 #define ROAM_STATS_BTM_REQ_DIALOG_TOKEN \
9589 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQ_DIALOG_TOKEN
9590 #define ROAM_STATS_BSS_CU_LOAD \
9591 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BSS_CU_LOAD
9592 #define ROAM_STATS_DISCONNECTION_TYPE \
9593 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_TYPE
9594 #define ROAM_STATS_DISCONNECTION_REASON \
9595 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_REASON
9596 #define ROAM_STATS_PERIODIC_TIMER_MS \
9597 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PERIODIC_TIMER_MS
9598 #define ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI \
9599 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI
9600 #define ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI \
9601 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI
9602 #define ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH \
9603 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_THRESH
9604 #define ROAM_STATS_TX_FAILURES_THRESHOLD \
9605 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_THRESHOLD
9606 #define ROAM_STATS_TX_FAILURES_REASON \
9607 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_REASON
9608 #define ROAM_STATS_ABORT_REASON \
9609 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ABORT_REASON
9610 #define ROAM_STATS_DATA_RSSI \
9611 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI
9612 #define ROAM_STATS_DATA_RSSI_THRESHOLD \
9613 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI_THRESHOLD
9614 #define ROAM_STATS_DATA_RX_LINKSPEED_STATUS \
9615 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RX_LINKSPEED_STATUS
9616 #define ROAM_STATS_SCAN_TYPE \
9617 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_TYPE
9618 #define ROAM_STATS_ROAM_STATUS \
9619 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_STATUS
9620 #define ROAM_STATS_FAIL_REASON \
9621 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FAIL_REASON
9622 #define ROAM_STATS_SCAN_CHAN_INFO \
9623 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHAN_INFO
9624 #define ROAM_STATS_TOTAL_SCAN_TIME \
9625 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TOTAL_SCAN_TIME
9626 #define ROAM_STATS_FRAME_INFO  \
9627 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO
9628 #define ROAM_STATS_SCAN_CHANNEL_FREQ \
9629 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHANNEL_FREQ
9630 #define ROAM_STATS_SCAN_DWELL_TYPE \
9631 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_DWELL_TYPE
9632 #define ROAM_STATS_MAX_DWELL_TIME \
9633 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_MAX_DWELL_TIME
9634 #define ROAM_STATS_FRAME_SUBTYPE \
9635 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_SUBTYPE
9636 #define ROAM_STATS_FRAME_STATUS \
9637 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_STATUS
9638 #define ROAM_STATS_FRAME_TIMESTAMP \
9639 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_TIMESTAMP
9640 
9641 static enum qca_roam_reason
9642 hdd_convert_roam_trigger_reason(enum roam_trigger_reason reason)
9643 {
9644 	switch (reason) {
9645 	case ROAM_TRIGGER_REASON_NONE:
9646 		return QCA_ROAM_REASON_UNKNOWN;
9647 	case ROAM_TRIGGER_REASON_PER:
9648 		return QCA_ROAM_REASON_PER;
9649 	case ROAM_TRIGGER_REASON_BMISS:
9650 		return QCA_ROAM_REASON_BEACON_MISS;
9651 	case ROAM_TRIGGER_REASON_LOW_RSSI:
9652 		return QCA_ROAM_REASON_POOR_RSSI;
9653 	case ROAM_TRIGGER_REASON_HIGH_RSSI:
9654 		return QCA_ROAM_REASON_BETTER_RSSI;
9655 	case ROAM_TRIGGER_REASON_PERIODIC:
9656 		return QCA_ROAM_REASON_PERIODIC_TIMER;
9657 	case ROAM_TRIGGER_REASON_DENSE:
9658 		return QCA_ROAM_REASON_CONGESTION;
9659 	case ROAM_TRIGGER_REASON_BACKGROUND:
9660 		return QCA_ROAM_REASON_BACKGROUND_SCAN;
9661 	case ROAM_TRIGGER_REASON_FORCED:
9662 		return QCA_ROAM_REASON_USER_TRIGGER;
9663 	case ROAM_TRIGGER_REASON_BTM:
9664 		return QCA_ROAM_REASON_BTM;
9665 	case ROAM_TRIGGER_REASON_BSS_LOAD:
9666 		return QCA_ROAM_REASON_BSS_LOAD;
9667 	case ROAM_TRIGGER_REASON_DEAUTH:
9668 		return QCA_ROAM_REASON_DISCONNECTION;
9669 	case ROAM_TRIGGER_REASON_STA_KICKOUT:
9670 		return QCA_ROAM_REASON_STA_KICKOUT;
9671 	default:
9672 		hdd_err("Invalid invoke reason received: %d", reason);
9673 		break;
9674 	}
9675 
9676 	return QCA_ROAM_REASON_UNKNOWN;
9677 }
9678 
9679 static enum qca_wlan_roam_stats_invoke_reason
9680 hdd_convert_roam_invoke_reason(enum roam_invoke_reason invoke)
9681 {
9682 	switch (invoke) {
9683 	case WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED:
9684 		return QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED;
9685 	case WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE:
9686 		return QCA_WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE;
9687 	case WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE:
9688 		return QCA_WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE;
9689 	default:
9690 		hdd_err("Invalid invoke reason received: %d", invoke);
9691 		break;
9692 	}
9693 
9694 	return QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED;
9695 }
9696 
9697 static enum qca_wlan_roam_stats_tx_failures_reason
9698 hdd_convert_roam_tx_failures_reason(enum roam_tx_failures_reason tx_failures)
9699 {
9700 	switch (tx_failures) {
9701 	case WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED:
9702 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED;
9703 	case WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY:
9704 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY;
9705 	case WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY:
9706 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY;
9707 	case WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT:
9708 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT;
9709 	case WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT:
9710 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT;
9711 	case WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT:
9712 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT;
9713 	case WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT:
9714 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT;
9715 	default:
9716 		hdd_err("Invalid tx_failures reason received: %d", tx_failures);
9717 		break;
9718 	}
9719 
9720 	return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED;
9721 }
9722 
9723 static enum qca_wlan_roam_stats_abort_reason
9724 hdd_convert_roam_abort_reason(enum roam_abort_reason abort)
9725 {
9726 	switch (abort) {
9727 	case WLAN_ROAM_STATS_ABORT_UNSPECIFIED:
9728 		return QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED;
9729 	case WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH:
9730 		return QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH;
9731 	case WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD:
9732 		return QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD;
9733 	case WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH:
9734 		return QCA_WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH;
9735 	case WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD:
9736 		return QCA_WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD;
9737 	default:
9738 		hdd_err("Invalid abort reason received: %d", abort);
9739 		break;
9740 	}
9741 
9742 	return QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED;
9743 }
9744 
9745 static enum qca_wlan_roam_stats_scan_type
9746 hdd_convert_roam_scan_type(enum roam_stats_scan_type              type)
9747 {
9748 	switch (type) {
9749 	case ROAM_STATS_SCAN_TYPE_PARTIAL:
9750 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL;
9751 	case ROAM_STATS_SCAN_TYPE_FULL:
9752 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_FULL;
9753 	case ROAM_STATS_SCAN_TYPE_NO_SCAN:
9754 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_NO_SCAN;
9755 	case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ:
9756 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ;
9757 	case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ:
9758 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ;
9759 	default:
9760 		hdd_err("Invalid roam scan type received: %d", type);
9761 		break;
9762 	}
9763 
9764 	return QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL;
9765 }
9766 
9767 static enum qca_wlan_roam_stats_scan_dwell_type
9768 hdd_convert_roam_chn_dwell_type(enum roam_scan_dwell_type type)
9769 {
9770 	switch (type) {
9771 	case WLAN_ROAM_DWELL_TYPE_UNSPECIFIED:
9772 		return QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED;
9773 	case WLAN_ROAM_DWELL_ACTIVE_TYPE:
9774 		return QCA_WLAN_ROAM_STATS_DWELL_TYPE_ACTIVE;
9775 	case WLAN_ROAM_DWELL_PASSIVE_TYPE:
9776 		return QCA_WLAN_ROAM_STATS_DWELL_TYPE_PASSIVE;
9777 	default:
9778 		hdd_err("Invalid abort reason received: %d", type);
9779 		break;
9780 	}
9781 
9782 	return QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED;
9783 }
9784 
9785 static enum qca_wlan_roam_stats_frame_subtype
9786 hdd_convert_roam_frame_type(enum eroam_frame_subtype type)
9787 {
9788 	switch (type) {
9789 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ:
9790 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
9791 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP:
9792 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP;
9793 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ:
9794 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ;
9795 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP:
9796 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP;
9797 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1:
9798 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1;
9799 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2:
9800 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2;
9801 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3:
9802 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3;
9803 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4:
9804 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4;
9805 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1:
9806 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1;
9807 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2:
9808 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2;
9809 	default:
9810 		hdd_err_rl("Invalid roam frame type received: %d", type);
9811 		break;
9812 	}
9813 
9814 	return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
9815 };
9816 
9817 static enum qca_wlan_roam_stats_frame_status
9818 hdd_convert_roam_frame_status(enum eroam_frame_status status)
9819 {
9820 	switch (status) {
9821 	case WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS:
9822 		return QCA_WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS;
9823 	case WLAN_ROAM_STATS_FRAME_STATUS_FAIL:
9824 		return QCA_WLAN_ROAM_STATS_FRAME_STATUS_FAIL;
9825 	default:
9826 		hdd_err("Invalid roam frame status received: %d", status);
9827 		break;
9828 	}
9829 
9830 	return QCA_WLAN_ROAM_STATS_FRAME_STATUS_FAIL;
9831 };
9832 
9833 static enum qca_vendor_roam_fail_reasons
9834 hdd_convert_roam_failures_reason(enum wlan_roam_failure_reason_code fail)
9835 {
9836 	switch (fail) {
9837 	case ROAM_FAIL_REASON_NO_SCAN_START:
9838 		return QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED;
9839 	case ROAM_FAIL_REASON_NO_AP_FOUND:
9840 		return QCA_ROAM_FAIL_REASON_NO_AP_FOUND;
9841 	case ROAM_FAIL_REASON_NO_CAND_AP_FOUND:
9842 		return QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND;
9843 	case ROAM_FAIL_REASON_HOST:
9844 		return QCA_ROAM_FAIL_REASON_HOST;
9845 	case ROAM_FAIL_REASON_AUTH_SEND:
9846 		return QCA_ROAM_FAIL_REASON_AUTH_SEND;
9847 	case ROAM_FAIL_REASON_NO_AUTH_RESP:
9848 		return QCA_ROAM_FAIL_REASON_NO_AUTH_RESP;
9849 	case ROAM_FAIL_REASON_AUTH_RECV:
9850 		return QCA_ROAM_FAIL_REASON_AUTH_RECV;
9851 	case ROAM_FAIL_REASON_REASSOC_SEND:
9852 		return QCA_ROAM_FAIL_REASON_REASSOC_SEND;
9853 	case ROAM_FAIL_REASON_REASSOC_RECV:
9854 		return QCA_ROAM_FAIL_REASON_REASSOC_RECV;
9855 	case ROAM_FAIL_REASON_NO_REASSOC_RESP:
9856 		return QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP;
9857 	case ROAM_FAIL_REASON_EAPOL_TIMEOUT:
9858 		return QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT;
9859 	case ROAM_FAIL_REASON_SCAN_START:
9860 		return QCA_ROAM_FAIL_REASON_SCAN_FAIL;
9861 	case ROAM_FAIL_REASON_AUTH_NO_ACK:
9862 		return QCA_ROAM_FAIL_REASON_AUTH_NO_ACK;
9863 	case ROAM_FAIL_REASON_AUTH_INTERNAL_DROP:
9864 		return QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP;
9865 	case ROAM_FAIL_REASON_REASSOC_NO_ACK:
9866 		return QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK;
9867 	case ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP:
9868 		return QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP;
9869 	case ROAM_FAIL_REASON_EAPOL_M2_SEND:
9870 		return QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND;
9871 	case ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP:
9872 		return QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP;
9873 	case ROAM_FAIL_REASON_EAPOL_M2_NO_ACK:
9874 		return QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK;
9875 	case ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT:
9876 		return QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT;
9877 	case ROAM_FAIL_REASON_EAPOL_M4_SEND:
9878 		return QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND;
9879 	case ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP:
9880 		return QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP;
9881 	case ROAM_FAIL_REASON_EAPOL_M4_NO_ACK:
9882 		return QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK;
9883 	case ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BMISS:
9884 		return QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS;
9885 	case ROAM_FAIL_REASON_DISCONNECT:
9886 		return QCA_ROAM_FAIL_REASON_DISCONNECT;
9887 	case ROAM_FAIL_REASON_SYNC:
9888 		return QCA_ROAM_FAIL_REASON_RESUME_ABORT;
9889 	case ROAM_FAIL_REASON_SAE_INVALID_PMKID:
9890 		return QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID;
9891 	case ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT:
9892 		return QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT;
9893 	case ROAM_FAIL_REASON_SAE_PREAUTH_FAIL:
9894 		return QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL;
9895 	case ROAM_FAIL_REASON_CURR_AP_STILL_OK:
9896 		return QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK;
9897 	case ROAM_FAIL_REASON_MLME:
9898 	case ROAM_FAIL_REASON_INTERNAL_ABORT:
9899 	case ROAM_FAIL_REASON_UNABLE_TO_START_ROAM_HO:
9900 	case ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT:
9901 	case ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT:
9902 	case ROAM_FAIL_REASON_SCAN_CANCEL:
9903 	case ROAM_FAIL_REASON_SCREEN_ACTIVITY:
9904 	case ROAM_FAIL_REASON_OTHER_PRIORITY_ROAM_SCAN:
9905 	case ROAM_FAIL_REASON_UNKNOWN:
9906 		hdd_err("Invalid roam failures reason");
9907 		break;
9908 	}
9909 
9910 	return QCA_ROAM_FAIL_REASON_NONE;
9911 }
9912 
9913 /**
9914  * hdd_get_roam_stats_individual_record_len() - calculates the required length
9915  * of an individual record of roaming stats
9916  *
9917  * @roam_info: pointer to roam info
9918  * @index:     index of roam info cached in driver
9919  *
9920  * Return: required length of an individual record of roaming stats
9921  */
9922 static uint32_t hdd_get_roam_stats_individual_record_len(struct enhance_roam_info *roam_info,
9923 							 uint32_t index)
9924 {
9925 	struct enhance_roam_info *info;
9926 	enum qca_roam_reason vendor_trigger_reason;
9927 	uint32_t len, i;
9928 
9929 	if (!roam_info) {
9930 		hdd_err("invalid param");
9931 		return 0;
9932 	}
9933 
9934 	info  = &roam_info[index];
9935 	vendor_trigger_reason =
9936 		hdd_convert_roam_trigger_reason(info->trigger.trigger_reason);
9937 
9938 	len = 0;
9939 	/* ROAM_STATS_ROAM_TRIGGER_TIMESTAMP */
9940 	len += nla_total_size_64bit(sizeof(uint64_t));
9941 	/* ROAM_STATS_TRIGGER_REASON */
9942 	len += nla_total_size(sizeof(uint32_t));
9943 
9944 	switch (vendor_trigger_reason) {
9945 	case QCA_ROAM_REASON_PER:
9946 		/* ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT */
9947 		len += nla_total_size(sizeof(uint8_t));
9948 		/* ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT */
9949 		len += nla_total_size(sizeof(uint8_t));
9950 		break;
9951 	case QCA_ROAM_REASON_BEACON_MISS:
9952 		/* ROAM_STATS_FINAL_BMISS_CNT */
9953 		len += nla_total_size(sizeof(uint32_t));
9954 		/* ROAM_STATS_CONSECUTIVE_BMISS_CNT */
9955 		len += nla_total_size(sizeof(uint32_t));
9956 		/* ROAM_STATS_BMISS_QOS_NULL_SUCCESS */
9957 		len += nla_total_size(sizeof(uint8_t));
9958 		break;
9959 	case QCA_ROAM_REASON_POOR_RSSI:
9960 		/* ROAM_STATS_POOR_RSSI_CURRENT_RSSI */
9961 		len += nla_total_size(sizeof(int8_t));
9962 		/* ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD */
9963 		len += nla_total_size(sizeof(int8_t));
9964 		/* ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS */
9965 		len += nla_total_size(sizeof(uint8_t));
9966 		break;
9967 	case QCA_ROAM_REASON_BETTER_RSSI:
9968 		/* ROAM_STATS_BETTER_RSSI_CURRENT_RSSI */
9969 		len += nla_total_size(sizeof(int8_t));
9970 		/* ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD */
9971 		len += nla_total_size(sizeof(int8_t));
9972 		break;
9973 	case QCA_ROAM_REASON_PERIODIC_TIMER:
9974 		/* ROAM_STATS_PERIODIC_TIMER_MS */
9975 		len += nla_total_size(sizeof(uint32_t));
9976 		break;
9977 	case QCA_ROAM_REASON_CONGESTION:
9978 		/* ROAM_STATS_CONGESTION_RX_TPUT */
9979 		len += nla_total_size(sizeof(uint32_t));
9980 		/* ROAM_STATS_CONGESTION_TX_TPUT */
9981 		len += nla_total_size(sizeof(uint32_t));
9982 		/* ROAM_STATS_CONGESTION_ROAMABLE_CNT */
9983 		len += nla_total_size(sizeof(uint8_t));
9984 		break;
9985 	case QCA_ROAM_REASON_BACKGROUND_SCAN:
9986 		/* ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI */
9987 		len += nla_total_size(sizeof(int8_t));
9988 		/* ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI */
9989 		len += nla_total_size(sizeof(int8_t));
9990 		/* ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH */
9991 		len += nla_total_size(sizeof(int8_t));
9992 		break;
9993 	case QCA_ROAM_REASON_USER_TRIGGER:
9994 		/* ROAM_STATS_USER_TRIGGER_INVOKE_REASON */
9995 		len += nla_total_size(sizeof(uint8_t));
9996 		break;
9997 	case QCA_ROAM_REASON_BTM:
9998 		/* ROAM_STATS_BTM_REQUEST_MODE */
9999 		len += nla_total_size(sizeof(uint8_t));
10000 		/* ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME */
10001 		len += nla_total_size(sizeof(uint32_t));
10002 		/* ROAM_STATS_BTM_VALID_INTERNAL */
10003 		len += nla_total_size(sizeof(uint32_t));
10004 		/* ROAM_STATS_BTM_CANDIDATE_LIST_CNT */
10005 		len += nla_total_size(sizeof(uint8_t));
10006 		/* ROAM_STATS_BTM_RESPONSE_STATUS_CODE */
10007 		len += nla_total_size(sizeof(uint8_t));
10008 		/* ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT */
10009 		len += nla_total_size(sizeof(uint32_t));
10010 		/* ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT */
10011 		len += nla_total_size(sizeof(uint32_t));
10012 		/* ROAM_STATS_BTM_REQ_DIALOG_TOKEN */
10013 		len += nla_total_size(sizeof(uint8_t));
10014 		break;
10015 	case QCA_ROAM_REASON_BSS_LOAD:
10016 		/* ROAM_STATS_BSS_CU_LOAD */
10017 		len += nla_total_size(sizeof(uint8_t));
10018 		break;
10019 	case QCA_ROAM_REASON_DISCONNECTION:
10020 		/* ROAM_STATS_DISCONNECTION_TYPE */
10021 		len += nla_total_size(sizeof(uint8_t));
10022 		/* ROAM_STATS_DISCONNECTION_REASON */
10023 		len += nla_total_size(sizeof(uint16_t));
10024 		break;
10025 	case QCA_ROAM_REASON_STA_KICKOUT:
10026 		/* ROAM_STATS_TX_FAILURES_THRESHOLD */
10027 		len += nla_total_size(sizeof(uint32_t));
10028 		/* ROAM_STATS_TX_FAILURES_REASON */
10029 		len += nla_total_size(sizeof(uint8_t));
10030 		break;
10031 	default:
10032 		break;
10033 	}
10034 
10035 	/* ROAM_STATS_SCAN_TYPE */
10036 	len += nla_total_size(sizeof(uint8_t));
10037 	/* ROAM_STATS_ROAM_STATUS */
10038 	len += nla_total_size(sizeof(uint8_t));
10039 
10040 	if (info->trigger.roam_status) {
10041 		/* ROAM_STATS_FAIL_REASON */
10042 		len += nla_total_size(sizeof(uint8_t));
10043 		if (info->trigger.abort.abort_reason_code) {
10044 			/* ROAM_STATS_ABORT_REASON */
10045 			len += nla_total_size(sizeof(uint8_t));
10046 			/* ROAM_STATS_DATA_RSSI */
10047 			len += nla_total_size(sizeof(int8_t));
10048 			/* ROAM_STATS_DATA_RSSI_THRESHOLD */
10049 			len += nla_total_size(sizeof(int8_t));
10050 			/* ROAM_STATS_DATA_RX_LINKSPEED_STATUS */
10051 			len += nla_total_size(sizeof(uint8_t));
10052 		}
10053 	}
10054 
10055 	/* ROAM_STATS_SCAN_CHAN_INFO */
10056 	len += nla_total_size(0);
10057 	for (i = 0; i < info->scan.num_channels; i++) {
10058 		/* nest attribute */
10059 		len += nla_total_size(0);
10060 		/* ROAM_STATS_SCAN_CHANNEL_FREQ */
10061 		len += nla_total_size(sizeof(uint32_t));
10062 		/* ROAM_STATS_SCAN_DWELL_TYPE */
10063 		len += nla_total_size(sizeof(uint32_t));
10064 		/* ROAM_STATS_MAX_DWELL_TIME */
10065 		len += nla_total_size(sizeof(uint32_t));
10066 	}
10067 
10068 	/* ROAM_STATS_TOTAL_SCAN_TIME */
10069 	len += nla_total_size(sizeof(uint32_t));
10070 
10071 	/* ROAM_STATS_FRAME_INFO */
10072 	len += nla_total_size(0);
10073 	for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) {
10074 		/* nest attribute */
10075 		len += nla_total_size(0);
10076 		/* ROAM_STATS_FRAME_SUBTYPE */
10077 		len += nla_total_size(sizeof(uint8_t));
10078 		/* ROAM_STATS_FRAME_STATUS */
10079 		len += nla_total_size(sizeof(uint8_t));
10080 		/* ROAM_STATS_FRAME_TIMESTAMP */
10081 		len += nla_total_size_64bit(sizeof(uint64_t));
10082 	}
10083 
10084 	return len;
10085 }
10086 
10087 /**
10088  * hdd_get_roam_stats_info_len() - calculate the length required by skb
10089  * @roam_info: pointer to roam info
10090  * @roam_cache_num: roam cache number
10091  *
10092  * Calculate the required length to send roam stats to upper layer
10093  *
10094  * Return: required len
10095  */
10096 static uint32_t
10097 hdd_get_roam_stats_info_len(struct enhance_roam_info *roam_info,
10098 			    uint8_t roam_cache_num)
10099 {
10100 	uint32_t len, i;
10101 
10102 	len = 0;
10103 	/* QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO */
10104 	len += nla_total_size(0);
10105 	for (i = 0; i < roam_cache_num; i++) {
10106 		/* nest attribute */
10107 		len += nla_total_size(0);
10108 		len += hdd_get_roam_stats_individual_record_len(roam_info, i);
10109 	}
10110 
10111 	return len;
10112 }
10113 
10114 /**
10115  * hdd_nla_put_roam_stats_info() - put roam statistics info attribute
10116  * values to userspace
10117  *
10118  * @skb:       pointer to sk buff
10119  * @roam_info: pointer to roam info
10120  * @index:     index of roam info cached in driver
10121  *
10122  * Return: 0 if success else error status
10123  */
10124 static int hdd_nla_put_roam_stats_info(struct sk_buff *skb,
10125 				       struct enhance_roam_info *roam_info,
10126 				       uint32_t index)
10127 {
10128 	struct nlattr *roam_chn_info, *roam_chn;
10129 	struct nlattr *roam_frame_info, *roam_frame;
10130 	struct enhance_roam_info *info;
10131 	enum roam_invoke_reason driver_invoke_reason;
10132 	enum qca_wlan_roam_stats_invoke_reason vendor_invoke_reason;
10133 	enum roam_tx_failures_reason driver_tx_failures_reason;
10134 	enum qca_wlan_roam_stats_tx_failures_reason vendor_tx_failures_reason;
10135 	enum roam_abort_reason driver_abort_reason;
10136 	enum qca_wlan_roam_stats_abort_reason vendor_abort_reason;
10137 	enum qca_wlan_roam_stats_scan_type vendor_scan_type;
10138 	enum roam_scan_dwell_type driver_dwell_type;
10139 	enum qca_wlan_roam_stats_scan_dwell_type vendor_dwell_type;
10140 	enum eroam_frame_subtype driver_frame_type;
10141 	enum qca_wlan_roam_stats_frame_subtype vendor_frame_type;
10142 	enum eroam_frame_status driver_frame_status;
10143 	enum qca_wlan_roam_stats_frame_status vendor_frame_status;
10144 	enum qca_roam_reason vendor_trigger_reason;
10145 	enum qca_vendor_roam_fail_reasons vendor_fail_reason;
10146 	uint32_t i;
10147 	int ret;
10148 
10149 	if (!roam_info) {
10150 		hdd_err("invalid param");
10151 		return -EINVAL;
10152 	}
10153 	info  = &roam_info[index];
10154 
10155 	vendor_trigger_reason =
10156 		hdd_convert_roam_trigger_reason(info->trigger.trigger_reason);
10157 
10158 	if (wlan_cfg80211_nla_put_u64(skb, ROAM_STATS_ROAM_TRIGGER_TIMESTAMP,
10159 				      info->trigger.timestamp)) {
10160 		hdd_err("timestamp put fail");
10161 		return -EINVAL;
10162 	}
10163 
10164 	if (nla_put_u32(skb, ROAM_STATS_TRIGGER_REASON, vendor_trigger_reason)) {
10165 		hdd_err(" put fail");
10166 		return -EINVAL;
10167 	}
10168 
10169 	switch (vendor_trigger_reason) {
10170 	case QCA_ROAM_REASON_PER:
10171 		if (nla_put_u8(skb,  ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT,
10172 			       info->trigger.condition.roam_per.rx_rate_thresh_percent)) {
10173 			hdd_err("roam_per.rx_rate_thresh_percent put fail");
10174 			return -EINVAL;
10175 		}
10176 		if (nla_put_u8(skb,  ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT,
10177 			       info->trigger.condition.roam_per.tx_rate_thresh_percent)) {
10178 			hdd_err("roam_per.rx_rate_thresh_percent put fail");
10179 			return -EINVAL;
10180 		}
10181 		break;
10182 	case QCA_ROAM_REASON_BEACON_MISS:
10183 		if (nla_put_u32(skb, ROAM_STATS_FINAL_BMISS_CNT,
10184 				info->trigger.condition.roam_bmiss.final_bmiss_cnt)) {
10185 			hdd_err("roam_bmiss.final_bmiss_cnt put fail");
10186 			return -EINVAL;
10187 		}
10188 		if (nla_put_u32(skb, ROAM_STATS_CONSECUTIVE_BMISS_CNT,
10189 				info->trigger.condition.roam_bmiss.consecutive_bmiss_cnt)) {
10190 			hdd_err("roam_bmiss.consecutive_bmiss_cnt put fail");
10191 			return -EINVAL;
10192 		}
10193 		if (nla_put_u8(skb, ROAM_STATS_BMISS_QOS_NULL_SUCCESS,
10194 			       info->trigger.condition.roam_bmiss.qos_null_success)) {
10195 			hdd_err("roam_bmiss.qos_null_success put fail");
10196 			return -EINVAL;
10197 		}
10198 		break;
10199 	case QCA_ROAM_REASON_POOR_RSSI:
10200 		if (nla_put_s8(skb, ROAM_STATS_POOR_RSSI_CURRENT_RSSI,
10201 			       info->trigger.condition.roam_poor_rssi.current_rssi)) {
10202 			hdd_err("roam_poor_rssi.current_rssi put fail");
10203 			return -EINVAL;
10204 		}
10205 		if (nla_put_s8(skb, ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD,
10206 			       info->trigger.condition.roam_poor_rssi.roam_rssi_threshold)) {
10207 			hdd_err("roam_poor_rssi.roam_rssi_threshold put fail");
10208 			return -EINVAL;
10209 		}
10210 		if (nla_put_u8(skb, ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS,
10211 			       info->trigger.condition.roam_poor_rssi.rx_linkspeed_status)) {
10212 			hdd_err("roam_poor_rssi.rx_linkspeed_status put fail");
10213 			return -EINVAL;
10214 		}
10215 		break;
10216 	case QCA_ROAM_REASON_BETTER_RSSI:
10217 		if (nla_put_s8(skb, ROAM_STATS_BETTER_RSSI_CURRENT_RSSI,
10218 			       info->trigger.condition.roam_better_rssi.current_rssi)) {
10219 			hdd_err("roam_better_rssi.current_rssi put fail");
10220 			return -EINVAL;
10221 		}
10222 		if (nla_put_s8(skb, ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD,
10223 			       info->trigger.condition.roam_better_rssi.hi_rssi_threshold)) {
10224 			hdd_err("roam_better_rssi.hi_rssi_threshold put fail");
10225 			return -EINVAL;
10226 		}
10227 		break;
10228 	case QCA_ROAM_REASON_PERIODIC_TIMER:
10229 		if (nla_put_u32(skb, ROAM_STATS_PERIODIC_TIMER_MS,
10230 				info->trigger.condition.roam_periodic.periodic_timer_ms)) {
10231 			hdd_err("roam_periodic.periodic_timer_ms put fail");
10232 			return -EINVAL;
10233 		}
10234 		break;
10235 	case QCA_ROAM_REASON_CONGESTION:
10236 		if (nla_put_u32(skb, ROAM_STATS_CONGESTION_RX_TPUT,
10237 				info->trigger.condition.roam_congestion.rx_tput)) {
10238 			hdd_err("roam_congestion.rx_tput put fail");
10239 			return -EINVAL;
10240 		}
10241 		if (nla_put_u32(skb, ROAM_STATS_CONGESTION_TX_TPUT,
10242 				info->trigger.condition.roam_congestion.tx_tput)) {
10243 			hdd_err("roam_congestion.tx_tput put fail");
10244 			return -EINVAL;
10245 		}
10246 		if (nla_put_u8(skb, ROAM_STATS_CONGESTION_ROAMABLE_CNT,
10247 			       info->trigger.condition.roam_congestion.roamable_count)) {
10248 			hdd_err("roam_congestion.roamable_count put fail");
10249 			return -EINVAL;
10250 		}
10251 		break;
10252 	case QCA_ROAM_REASON_BACKGROUND_SCAN:
10253 		if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI,
10254 			       info->trigger.condition.roam_background.current_rssi)) {
10255 			hdd_err("roam_background.current_rssi put fail");
10256 			return -EINVAL;
10257 		}
10258 		if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI,
10259 			       info->trigger.condition.roam_background.data_rssi)) {
10260 			hdd_err("roam_background.data_rssi put fail");
10261 			return -EINVAL;
10262 		}
10263 		if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH,
10264 			       info->trigger.condition.roam_background.data_rssi_threshold)) {
10265 			hdd_err("roam_background.data_rssi_threshold put fail");
10266 			return -EINVAL;
10267 		}
10268 		break;
10269 	case QCA_ROAM_REASON_USER_TRIGGER:
10270 		driver_invoke_reason =
10271 			info->trigger.condition.roam_user_trigger.invoke_reason;
10272 		vendor_invoke_reason = hdd_convert_roam_invoke_reason(driver_invoke_reason);
10273 		if (nla_put_u8(skb, ROAM_STATS_USER_TRIGGER_INVOKE_REASON,
10274 			       vendor_invoke_reason)) {
10275 			hdd_err("roam_user_trigger.invoke_reason put fail");
10276 			return -EINVAL;
10277 		}
10278 		break;
10279 	case QCA_ROAM_REASON_BTM:
10280 		if (nla_put_u8(skb, ROAM_STATS_BTM_REQUEST_MODE,
10281 			       info->trigger.condition.roam_btm.btm_request_mode)) {
10282 			hdd_err("roam_btm.btm_request_mode put fail");
10283 			return -EINVAL;
10284 		}
10285 		if (nla_put_u32(skb, ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME,
10286 				info->trigger.condition.roam_btm.disassoc_imminent_timer)) {
10287 			hdd_err("roam_btm.disassoc_imminent_timer put fail");
10288 			return -EINVAL;
10289 		}
10290 		if (nla_put_u32(skb, ROAM_STATS_BTM_VALID_INTERNAL,
10291 				info->trigger.condition.roam_btm.validity_internal)) {
10292 			hdd_err("roam_btm.validity_internal put fail");
10293 			return -EINVAL;
10294 		}
10295 		if (nla_put_u8(skb, ROAM_STATS_BTM_CANDIDATE_LIST_CNT,
10296 			       info->trigger.condition.roam_btm.candidate_list_count)) {
10297 			hdd_err("roam_btm.candidate_list_count put fail");
10298 			return -EINVAL;
10299 		}
10300 		if (nla_put_u8(skb, ROAM_STATS_BTM_RESPONSE_STATUS_CODE,
10301 			       info->trigger.condition.roam_btm.btm_response_status_code)) {
10302 			hdd_err("roam_btm.btm_response_status_code put fail");
10303 			return -EINVAL;
10304 		}
10305 		if (nla_put_u32(skb, ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT,
10306 				info->trigger.condition.roam_btm.btm_bss_termination_timeout)) {
10307 			hdd_err("roam btm_bss_termination_timeout put fail");
10308 			return -EINVAL;
10309 		}
10310 		if (nla_put_u32(skb, ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT,
10311 				info->trigger.condition.roam_btm.btm_mbo_assoc_retry_timeout)) {
10312 			hdd_err("roam btm_mbo_assoc_retry_timeout put fail");
10313 			return -EINVAL;
10314 		}
10315 		if (nla_put_u8(skb, ROAM_STATS_BTM_REQ_DIALOG_TOKEN,
10316 			       info->trigger.condition.roam_btm.btm_req_dialog_token)) {
10317 			hdd_err("roam_btm.btm_req_dialog_token put fail");
10318 			return -EINVAL;
10319 		}
10320 		break;
10321 	case QCA_ROAM_REASON_BSS_LOAD:
10322 		if (nla_put_u8(skb, ROAM_STATS_BSS_CU_LOAD,
10323 			       info->trigger.condition.roam_bss_load.cu_load)) {
10324 			hdd_err("roam_bss_load.cu_load put fail");
10325 			return -EINVAL;
10326 		}
10327 		break;
10328 	case QCA_ROAM_REASON_DISCONNECTION:
10329 		if (nla_put_u8(skb, ROAM_STATS_DISCONNECTION_TYPE,
10330 			       info->trigger.condition.roam_disconnection.deauth_type)) {
10331 			hdd_err("roam_disconnection.deauth_type put fail");
10332 			return -EINVAL;
10333 		}
10334 		if (nla_put_u16(skb, ROAM_STATS_DISCONNECTION_REASON,
10335 				info->trigger.condition.roam_disconnection.deauth_reason)) {
10336 			hdd_err("roam_disconnection.deauth_reason put fail");
10337 			return -EINVAL;
10338 		}
10339 		break;
10340 	case QCA_ROAM_REASON_STA_KICKOUT:
10341 		driver_tx_failures_reason =
10342 			info->trigger.condition.roam_tx_failures.kickout_threshold;
10343 		vendor_tx_failures_reason =
10344 			hdd_convert_roam_tx_failures_reason(driver_tx_failures_reason);
10345 		if (nla_put_u32(skb, ROAM_STATS_TX_FAILURES_THRESHOLD,
10346 				vendor_tx_failures_reason)) {
10347 			hdd_err("roam_tx_failures.kickout_threshold put fail");
10348 			return -EINVAL;
10349 		}
10350 		if (nla_put_u8(skb, ROAM_STATS_TX_FAILURES_REASON,
10351 			       info->trigger.condition.roam_tx_failures.kickout_reason)) {
10352 			hdd_err("roam_tx_failures.kickout_reason put fail");
10353 			return -EINVAL;
10354 		}
10355 		break;
10356 	default:
10357 		break;
10358 	}
10359 
10360 	vendor_scan_type = hdd_convert_roam_scan_type(info->trigger.roam_scan_type);
10361 	if (nla_put_u8(skb, ROAM_STATS_SCAN_TYPE, vendor_scan_type)) {
10362 		hdd_err("roam_scan_type put fail");
10363 		return -EINVAL;
10364 	}
10365 
10366 	if (nla_put_u8(skb, ROAM_STATS_ROAM_STATUS,
10367 		       info->trigger.roam_status)) {
10368 		hdd_err("roam_status put fail");
10369 		return -EINVAL;
10370 	}
10371 
10372 	if (info->trigger.roam_status) {
10373 		vendor_fail_reason = hdd_convert_roam_failures_reason(info->trigger.roam_fail_reason);
10374 		if (nla_put_u8(skb, ROAM_STATS_FAIL_REASON,
10375 			       vendor_fail_reason)) {
10376 			hdd_err("roam_fail_reason put fail");
10377 			return -EINVAL;
10378 		}
10379 
10380 		driver_abort_reason = info->trigger.abort.abort_reason_code;
10381 		vendor_abort_reason = hdd_convert_roam_abort_reason(driver_abort_reason);
10382 		if (info->trigger.abort.abort_reason_code) {
10383 			if (nla_put_u8(skb, ROAM_STATS_ABORT_REASON, vendor_abort_reason)) {
10384 				hdd_err("abort.abort_reason_code put fail");
10385 				return -EINVAL;
10386 			}
10387 			if (nla_put_s8(skb, ROAM_STATS_DATA_RSSI,
10388 				       info->trigger.abort.data_rssi)) {
10389 				hdd_err("abort.data_rssi put fail");
10390 				return -EINVAL;
10391 			}
10392 			if (nla_put_s8(skb, ROAM_STATS_DATA_RSSI_THRESHOLD,
10393 				       info->trigger.abort.data_rssi_threshold)) {
10394 				hdd_err("abort.data_rssi_threshold put fail");
10395 				return -EINVAL;
10396 			}
10397 			if (nla_put_u8(skb, ROAM_STATS_DATA_RX_LINKSPEED_STATUS,
10398 				       info->trigger.abort.rx_linkspeed_status)) {
10399 				hdd_err("abort.rx_linkspeed_status put fail");
10400 				return -EINVAL;
10401 			}
10402 		}
10403 	}
10404 
10405 	roam_chn_info = nla_nest_start(skb, ROAM_STATS_SCAN_CHAN_INFO);
10406 	if (!roam_chn_info) {
10407 		hdd_err("nla_nest_start fail");
10408 		return -EINVAL;
10409 	}
10410 
10411 	for (i = 0; i < info->scan.num_channels; i++) {
10412 		roam_chn = nla_nest_start(skb, i);
10413 		if (!roam_chn) {
10414 			hdd_err("nla_nest_start fail");
10415 			return -EINVAL;
10416 		}
10417 
10418 		if (nla_put_u32(skb, ROAM_STATS_SCAN_CHANNEL_FREQ,
10419 				info->scan.roam_chn[i].chan_freq)) {
10420 			hdd_err("roam_chn[%u].chan_freq put fail", i);
10421 			return -EINVAL;
10422 		}
10423 
10424 		driver_dwell_type = info->scan.roam_chn[i].dwell_type;
10425 		vendor_dwell_type = hdd_convert_roam_chn_dwell_type(driver_dwell_type);
10426 		if (nla_put_u32(skb, ROAM_STATS_SCAN_DWELL_TYPE,
10427 				vendor_dwell_type)) {
10428 			hdd_err("roam_chn[%u].dwell_type put fail", i);
10429 			return -EINVAL;
10430 		}
10431 		if (nla_put_u32(skb, ROAM_STATS_MAX_DWELL_TIME,
10432 				info->scan.roam_chn[i].max_dwell_time)) {
10433 			hdd_err("roam_chn[%u].max_dwell_time put fail", i);
10434 			return -EINVAL;
10435 		}
10436 		nla_nest_end(skb, roam_chn);
10437 	}
10438 	nla_nest_end(skb, roam_chn_info);
10439 
10440 	if (nla_put_u32(skb, ROAM_STATS_TOTAL_SCAN_TIME,
10441 			info->scan.total_scan_time)) {
10442 		hdd_err("roam_scan total_scan_time put fail");
10443 		return -EINVAL;
10444 	}
10445 
10446 	roam_frame_info = nla_nest_start(skb, ROAM_STATS_FRAME_INFO);
10447 	if (!roam_frame_info) {
10448 		hdd_err("nla_nest_start fail");
10449 		return -EINVAL;
10450 	}
10451 
10452 	for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) {
10453 		roam_frame = nla_nest_start(skb, i);
10454 		if (!roam_frame) {
10455 			hdd_err("nla_nest_start fail");
10456 			return -EINVAL;
10457 		}
10458 		driver_frame_type = info->timestamp[i].frame_type;
10459 		vendor_frame_type = hdd_convert_roam_frame_type(driver_frame_type);
10460 		ret = nla_put_u8(skb, ROAM_STATS_FRAME_SUBTYPE,
10461 				 vendor_frame_type);
10462 		if (ret) {
10463 			hdd_err("roam_frame[%u].type put fail %d", i, ret);
10464 			return -EINVAL;
10465 		}
10466 		driver_frame_status = info->timestamp[i].status;
10467 		vendor_frame_status = hdd_convert_roam_frame_status(driver_frame_status);
10468 		ret = nla_put_u8(skb, ROAM_STATS_FRAME_STATUS,
10469 				 vendor_frame_status);
10470 		if (ret) {
10471 			hdd_err("frame[%u].status put fail %d", i, ret);
10472 			return -EINVAL;
10473 		}
10474 		ret = wlan_cfg80211_nla_put_u64(skb, ROAM_STATS_FRAME_TIMESTAMP,
10475 						info->timestamp[i].timestamp);
10476 		if (ret) {
10477 			hdd_err("frame[%u].timestamp put fail %d", i, ret);
10478 			return -EINVAL;
10479 		}
10480 		ret = nla_put(skb,
10481 			      QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_BSSID,
10482 			      QDF_MAC_ADDR_SIZE,
10483 			      info->timestamp[i].bssid.bytes);
10484 		if (ret) {
10485 			hdd_err("roam candidate AP bssid put fail");
10486 			return -EINVAL;
10487 		}
10488 
10489 		nla_nest_end(skb, roam_frame);
10490 	}
10491 	nla_nest_end(skb, roam_frame_info);
10492 
10493 	if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ORIGINAL_BSSID,
10494 		    QDF_MAC_ADDR_SIZE, info->scan.original_bssid.bytes)) {
10495 		hdd_err("roam original AP bssid put fail");
10496 		return -EINVAL;
10497 	}
10498 	if (!info->trigger.roam_status) {
10499 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAMED_BSSID,
10500 			    QDF_MAC_ADDR_SIZE, info->scan.roamed_bssid.bytes)) {
10501 			hdd_err("roam roamed AP bssid put fail");
10502 			return -EINVAL;
10503 		}
10504 	}
10505 
10506 	return 0;
10507 }
10508 
10509 /**
10510  * hdd_get_roam_stats_info() - get roam statistics info to userspace,
10511  * for STA mode only
10512  * @skb:     pointer to sk buff
10513  * @hdd_ctx: pointer to hdd context
10514  * @roam_info: pointer to roam info
10515  * @roam_cache_num: roam cache number
10516  *
10517  * Return: 0 if success else error status
10518  */
10519 static int hdd_get_roam_stats_info(struct sk_buff *skb,
10520 				   struct hdd_context *hdd_ctx,
10521 				   struct enhance_roam_info *roam_info,
10522 				   uint32_t  roam_cache_num)
10523 {
10524 	struct nlattr *config, *roam_params;
10525 	uint32_t i;
10526 	int ret;
10527 
10528 	config = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO);
10529 	if (!config) {
10530 		hdd_err("nla nest start failure");
10531 		return -EINVAL;
10532 	}
10533 
10534 	/* Send all driver cached roam info to user space one time,
10535 	 * and don't flush them, since they will be cover by
10536 	 * new roam event info.
10537 	 */
10538 	for (i = 0; i < roam_cache_num; i++) {
10539 		roam_params = nla_nest_start(skb, i);
10540 		if (!roam_params)
10541 			return -EINVAL;
10542 
10543 		ret = hdd_nla_put_roam_stats_info(skb, roam_info, i);
10544 		if (ret) {
10545 			hdd_err("nla put failure");
10546 			return -EINVAL;
10547 		}
10548 
10549 		nla_nest_end(skb, roam_params);
10550 	}
10551 	nla_nest_end(skb, config);
10552 
10553 	return 0;
10554 }
10555 
10556 /**
10557  * hdd_get_roam_stats() - send roam statistics info to userspace
10558  * @hdd_ctx: pointer to hdd context
10559  * @adapter: pointer to adapter
10560  *
10561  * Return: 0 if success else error status
10562  */
10563 static int
10564 hdd_get_roam_stats(struct hdd_context *hdd_ctx,
10565 		   struct hdd_adapter *adapter)
10566 {
10567 	struct sk_buff *skb;
10568 	uint32_t skb_len;
10569 	int ret = 0;
10570 	struct wlan_objmgr_vdev *vdev;
10571 	QDF_STATUS status;
10572 	struct enhance_roam_info *roam_info = NULL;
10573 	uint32_t roam_num = 0;
10574 
10575 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
10576 					   WLAN_OSIF_STATS_ID);
10577 	if (!vdev)
10578 		return -EINVAL;
10579 
10580 	status = ucfg_cm_roam_stats_info_get(vdev, &roam_info, &roam_num);
10581 	if (QDF_IS_STATUS_ERROR(status)) {
10582 		hdd_err("Failed to get roam info : %d", status);
10583 		wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID);
10584 		return qdf_status_to_os_return(status);
10585 	}
10586 	wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID);
10587 
10588 	skb_len = hdd_get_roam_stats_info_len(roam_info, roam_num);
10589 	if (!skb_len) {
10590 		hdd_err("No data requested");
10591 		ucfg_cm_roam_stats_info_put(roam_info);
10592 		return -EINVAL;
10593 	}
10594 
10595 	skb_len += NLMSG_HDRLEN;
10596 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, skb_len);
10597 	if (!skb) {
10598 		hdd_info("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
10599 		ucfg_cm_roam_stats_info_put(roam_info);
10600 		return -ENOMEM;
10601 	}
10602 
10603 	ret = hdd_get_roam_stats_info(skb, hdd_ctx, roam_info, roam_num);
10604 	if (ret) {
10605 		hdd_info("get roam stats fail");
10606 		wlan_cfg80211_vendor_free_skb(skb);
10607 		ucfg_cm_roam_stats_info_put(roam_info);
10608 		return -ENOMEM;
10609 	}
10610 
10611 	ucfg_cm_roam_stats_info_put(roam_info);
10612 
10613 	return wlan_cfg80211_vendor_cmd_reply(skb);
10614 }
10615 
10616 /**
10617  * __wlan_hdd_cfg80211_get_roam_stats() - get roam statstics information
10618  * @wiphy: wiphy pointer
10619  * @wdev: pointer to struct wireless_dev
10620  * @data: pointer to incoming NL vendor data
10621  * @data_len: length of @data
10622  *
10623  * Return: 0 on success; error number otherwise.
10624  */
10625 static int
10626 __wlan_hdd_cfg80211_get_roam_stats(struct wiphy *wiphy,
10627 				   struct wireless_dev *wdev,
10628 				   const void *data,
10629 				   int data_len)
10630 {
10631 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
10632 	struct net_device *dev = wdev->netdev;
10633 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
10634 	int32_t status;
10635 
10636 	hdd_enter_dev(dev);
10637 
10638 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE ||
10639 	    hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) {
10640 		hdd_err_rl("Command not allowed in FTM / Monitor mode");
10641 		status = -EPERM;
10642 		goto out;
10643 	}
10644 
10645 	status = wlan_hdd_validate_context(hdd_ctx);
10646 	if (status != 0)
10647 		goto out;
10648 
10649 	if (adapter->device_mode == QDF_STA_MODE) {
10650 		status = hdd_get_roam_stats(hdd_ctx, adapter);
10651 	} else {
10652 		hdd_err_rl("Invalid device_mode: %d", adapter->device_mode);
10653 		status = -EINVAL;
10654 	}
10655 
10656 	hdd_exit();
10657 out:
10658 	return status;
10659 }
10660 
10661 /**
10662  * wlan_hdd_cfg80211_get_roam_stats() - get roam statstics information
10663  * @wiphy: wiphy pointer
10664  * @wdev: pointer to struct wireless_dev
10665  * @data: pointer to incoming NL vendor data
10666  * @data_len: length of @data
10667  *
10668  * Return: 0 on success; error number otherwise.
10669  */
10670 int wlan_hdd_cfg80211_get_roam_stats(struct wiphy *wiphy,
10671 				     struct wireless_dev *wdev,
10672 				     const void *data,
10673 				     int data_len)
10674 {
10675 	int errno;
10676 	struct osif_vdev_sync *vdev_sync;
10677 
10678 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
10679 	if (errno)
10680 		return errno;
10681 
10682 	errno = __wlan_hdd_cfg80211_get_roam_stats(wiphy, wdev,
10683 						   data, data_len);
10684 
10685 	osif_vdev_sync_op_stop(vdev_sync);
10686 
10687 	return errno;
10688 }
10689 #endif
10690 
10691 #ifdef WLAN_FEATURE_TX_LATENCY_STATS
10692 #define TX_LATENCY_BUCKET_DISTRIBUTION_LEN \
10693 	(sizeof(uint32_t) * CDP_TX_LATENCY_TYPE_MAX)
10694 
10695 #define TX_LATENCY_ATTR(_name) QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ ## _name
10696 
10697 static const struct nla_policy
10698 tx_latency_bucket_policy[TX_LATENCY_ATTR(BUCKET_MAX) + 1] = {
10699 	[TX_LATENCY_ATTR(BUCKET_TYPE)] = {.type = NLA_U8},
10700 	[TX_LATENCY_ATTR(BUCKET_GRANULARITY)] = {.type = NLA_U32},
10701 	[TX_LATENCY_ATTR(BUCKET_AVERAGE)] = {.type = NLA_U32},
10702 	[TX_LATENCY_ATTR(BUCKET_DISTRIBUTION)] = {
10703 		.type = NLA_BINARY, .len = TX_LATENCY_BUCKET_DISTRIBUTION_LEN},
10704 };
10705 
10706 static const struct nla_policy
10707 tx_latency_link_policy[TX_LATENCY_ATTR(LINK_MAX) + 1] = {
10708 	[TX_LATENCY_ATTR(LINK_MAC_REMOTE)] = {
10709 		.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE},
10710 	[TX_LATENCY_ATTR(LINK_STAT_BUCKETS)] =
10711 		VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_bucket_policy),
10712 };
10713 
10714 const struct nla_policy
10715 tx_latency_policy[TX_LATENCY_ATTR(MAX) + 1] = {
10716 	[TX_LATENCY_ATTR(ACTION)] = {.type = NLA_U32},
10717 	[TX_LATENCY_ATTR(PERIODIC_REPORT)] = {.type = NLA_FLAG},
10718 	[TX_LATENCY_ATTR(PERIOD)] = {.type = NLA_U32 },
10719 	[TX_LATENCY_ATTR(BUCKETS)] =
10720 		VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_bucket_policy),
10721 	[TX_LATENCY_ATTR(LINKS)] =
10722 		VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_link_policy),
10723 };
10724 
10725 /**
10726  * struct tx_latency_link_node - Link info of remote peer
10727  * @node: list node for membership in the link list
10728  * @vdev_id: Unique value to identify VDEV
10729  * @mac_remote: link MAC address of the remote peer
10730  */
10731 struct tx_latency_link_node {
10732 	qdf_list_node_t node;
10733 	uint8_t vdev_id;
10734 	struct qdf_mac_addr mac_remote;
10735 };
10736 
10737 /**
10738  * hdd_tx_latency_set_for_link() - set tx latency stats config for a link
10739  * @link_info: link specific information
10740  * @config: pointer to tx latency stats config
10741  *
10742  * Return: QDF_STATUS
10743  */
10744 static inline QDF_STATUS
10745 hdd_tx_latency_set_for_link(struct wlan_hdd_link_info *link_info,
10746 			    struct cdp_tx_latency_config *config)
10747 {
10748 	QDF_STATUS status;
10749 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
10750 
10751 	if (!soc)
10752 		return QDF_STATUS_E_INVAL;
10753 
10754 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
10755 		return QDF_STATUS_SUCCESS;
10756 
10757 	status = cdp_host_tx_latency_stats_config(soc,
10758 						  link_info->vdev_id,
10759 						  config);
10760 	if (QDF_IS_STATUS_ERROR(status)) {
10761 		hdd_err_rl("failed to %s for vdev id %d, status %d",
10762 			   config->enable ? "enable" : "disable",
10763 			   link_info->vdev_id, status);
10764 		return status;
10765 	}
10766 
10767 	return QDF_STATUS_SUCCESS;
10768 }
10769 
10770 /**
10771  * hdd_tx_latency_restore_config() - restore tx latency stats config for a link
10772  * @link_info: link specific information
10773  *
10774  * Return: QDF_STATUS
10775  */
10776 QDF_STATUS
10777 hdd_tx_latency_restore_config(struct wlan_hdd_link_info *link_info)
10778 {
10779 	QDF_STATUS status;
10780 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
10781 	struct cdp_tx_latency_config *config;
10782 
10783 	if (!soc)
10784 		return QDF_STATUS_E_INVAL;
10785 
10786 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
10787 		return QDF_STATUS_SUCCESS;
10788 
10789 	config = &link_info->adapter->tx_latency_cfg;
10790 	status = cdp_host_tx_latency_stats_config(soc,
10791 						  link_info->vdev_id,
10792 						  config);
10793 	if (QDF_IS_STATUS_ERROR(status)) {
10794 		hdd_err_rl("failed to %s for vdev id %d, status %d",
10795 			   config->enable ? "enable" : "disable",
10796 			   link_info->vdev_id, status);
10797 		return status;
10798 	}
10799 
10800 	return QDF_STATUS_SUCCESS;
10801 }
10802 
10803 /**
10804  * hdd_tx_latency_set() - restore tx latency stats config for a link
10805  * @adapter: pointer to hdd vdev/net_device context
10806  * @config: pointer to tx latency stats config
10807  *
10808  * Return: 0 on success; error number otherwise.
10809  */
10810 static int
10811 hdd_tx_latency_set(struct hdd_adapter *adapter,
10812 		   struct cdp_tx_latency_config *config)
10813 {
10814 	int ret;
10815 	struct wlan_hdd_link_info *link_info;
10816 	QDF_STATUS status = QDF_STATUS_E_NOENT;
10817 
10818 	ret = hdd_set_tsf_auto_report(adapter, config->enable,
10819 				      HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY);
10820 	if (ret) {
10821 		hdd_err_rl("failed to %s tsf auto report, ret %d",
10822 			   config->enable ? "enable" : "disable", ret);
10823 		return ret;
10824 	}
10825 
10826 	hdd_adapter_for_each_link_info(adapter, link_info) {
10827 		status = hdd_tx_latency_set_for_link(link_info, config);
10828 		if (QDF_IS_STATUS_ERROR(status))
10829 			break;
10830 	}
10831 
10832 	/* restore TSF auto report config on failure */
10833 	if (QDF_IS_STATUS_ERROR(status))
10834 		hdd_set_tsf_auto_report(adapter, !config->enable,
10835 					HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY);
10836 	else
10837 		qdf_mem_copy(&adapter->tx_latency_cfg, config,
10838 			     sizeof(*config));
10839 	hdd_debug("enable %d status %d", config->enable, status);
10840 	return qdf_status_to_os_return(status);
10841 }
10842 
10843 /**
10844  * hdd_tx_latency_fill_link_stats() - fill tx latency statistics info skb
10845  * @skb: skb to be filled
10846  * @latency: per link tx latency statistics
10847  * @idx: index of the nested attribute
10848  *
10849  * Return: 0 on success; error number otherwise.
10850  */
10851 static int
10852 hdd_tx_latency_fill_link_stats(struct sk_buff *skb,
10853 			       struct cdp_tx_latency *latency, int idx)
10854 {
10855 	struct nlattr *link, *link_stat_buckets, *link_stat_bucket;
10856 	uint32_t type;
10857 	int ret = 0;
10858 
10859 	link = nla_nest_start(skb, idx);
10860 	if (!link) {
10861 		ret = -ENOMEM;
10862 		goto err;
10863 	}
10864 
10865 	if (nla_put(skb, TX_LATENCY_ATTR(LINK_MAC_REMOTE),
10866 		    QDF_MAC_ADDR_SIZE, latency->mac_remote.bytes)) {
10867 		ret = -ENOMEM;
10868 		goto err;
10869 	}
10870 
10871 	hdd_debug_rl("idx %d link mac " QDF_MAC_ADDR_FMT,
10872 		     idx, QDF_MAC_ADDR_REF(latency->mac_remote.bytes));
10873 	link_stat_buckets =
10874 		nla_nest_start(skb, TX_LATENCY_ATTR(LINK_STAT_BUCKETS));
10875 	for (type = 0; type < CDP_TX_LATENCY_TYPE_MAX; type++) {
10876 		link_stat_bucket = nla_nest_start(skb, type);
10877 		if (!link_stat_bucket) {
10878 			ret = -ENOMEM;
10879 			goto err;
10880 		}
10881 
10882 		if (nla_put_u8(skb, TX_LATENCY_ATTR(BUCKET_TYPE), type)) {
10883 			ret = -ENOMEM;
10884 			goto err;
10885 		}
10886 
10887 		if (nla_put_u32(skb, TX_LATENCY_ATTR(BUCKET_GRANULARITY),
10888 				latency->stats[type].granularity)) {
10889 			ret = -ENOMEM;
10890 			goto err;
10891 		}
10892 
10893 		if (nla_put_u32(skb, TX_LATENCY_ATTR(BUCKET_AVERAGE),
10894 				latency->stats[type].average)) {
10895 			ret = -ENOMEM;
10896 			goto err;
10897 		}
10898 
10899 		if (nla_put(skb, TX_LATENCY_ATTR(BUCKET_DISTRIBUTION),
10900 			    TX_LATENCY_BUCKET_DISTRIBUTION_LEN,
10901 			    latency->stats[type].distribution)) {
10902 			ret = -ENOMEM;
10903 			goto err;
10904 		}
10905 
10906 		nla_nest_end(skb, link_stat_bucket);
10907 		hdd_debug_rl("	type %u granularity %u average %u",
10908 			     type, latency->stats[type].granularity,
10909 			     latency->stats[type].average);
10910 	}
10911 
10912 	nla_nest_end(skb, link_stat_buckets);
10913 	nla_nest_end(skb, link);
10914 
10915 err:
10916 	if (ret)
10917 		hdd_err("failed for link " QDF_MAC_ADDR_FMT " ret: %d",
10918 			QDF_MAC_ADDR_REF(latency->mac_remote.bytes), ret);
10919 	return ret;
10920 }
10921 
10922 /**
10923  * hdd_tx_latency_get_skb_len() - get required skb length for vendor command
10924  * response/async event
10925  * @num: required number of entries
10926  *
10927  * Return: the required skb length
10928  */
10929 static uint32_t hdd_tx_latency_get_skb_len(uint32_t num)
10930 {
10931 	int32_t peer_stat_sz = 0, per_bucket_len = 0, len;
10932 
10933 	if (!num)
10934 		return 0;
10935 
10936 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE */
10937 	per_bucket_len += nla_total_size(sizeof(uint8_t));
10938 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_GRANULARITY */
10939 	per_bucket_len += nla_total_size(sizeof(uint32_t));
10940 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_DISTRIBUTION */
10941 	per_bucket_len += nla_total_size(TX_LATENCY_BUCKET_DISTRIBUTION_LEN);
10942 	/* Nested attr */
10943 	per_bucket_len = nla_total_size(per_bucket_len);
10944 
10945 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE */
10946 	peer_stat_sz += nla_total_size(QDF_MAC_ADDR_SIZE);
10947 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_STAT_BUCKETS */
10948 	peer_stat_sz +=
10949 		nla_total_size(per_bucket_len * CDP_TX_LATENCY_TYPE_MAX);
10950 	/* Nested attr */
10951 	peer_stat_sz = nla_total_size(peer_stat_sz);
10952 
10953 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS */
10954 	len = nla_total_size(peer_stat_sz * num);
10955 	len += NLMSG_HDRLEN;
10956 	return len;
10957 }
10958 
10959 /**
10960  * hdd_tx_latency_link_list_free() - free all the nodes in the list
10961  * @list: list of the nodes for link info
10962  *
10963  * Return: None
10964  */
10965 static void hdd_tx_latency_link_list_free(qdf_list_t *list)
10966 {
10967 	struct tx_latency_link_node *entry, *next;
10968 
10969 	qdf_list_for_each_del(list, entry, next, node) {
10970 		qdf_list_remove_node(list, &entry->node);
10971 		qdf_mem_free(entry);
10972 	}
10973 }
10974 
10975 /**
10976  * hdd_tx_latency_link_list_add() - add a new node to the list for tx latency
10977  * links
10978  * @list: list of the nodes for link info
10979  * @vdev_id: Unique value to identify VDEV
10980  * @mac: link mac address of the remote peer
10981  *
10982  * Return: 0 on success; error number otherwise.
10983  */
10984 static int
10985 hdd_tx_latency_link_list_add(qdf_list_t *list, uint8_t vdev_id, uint8_t *mac)
10986 {
10987 	struct tx_latency_link_node *link;
10988 
10989 	link = (struct tx_latency_link_node *)qdf_mem_malloc(sizeof(*link));
10990 	if (!link)
10991 		return -ENOMEM;
10992 
10993 	qdf_mem_copy(link->mac_remote.bytes, mac, QDF_MAC_ADDR_SIZE);
10994 	link->vdev_id = vdev_id;
10995 	qdf_list_insert_back(list, &link->node);
10996 	return 0;
10997 }
10998 
10999 /**
11000  * hdd_tx_latency_get_links_from_attr() - parse information of the links from
11001  * attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11002  * @adapter: pointer to hdd vdev/net_device context
11003  * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11004  * @list: list of the nodes for link info
11005  *
11006  * Return: 0 on success; error number otherwise.
11007  */
11008 static int
11009 hdd_tx_latency_get_links_from_attr(struct hdd_adapter *adapter,
11010 				   struct nlattr *links_attr,
11011 				   qdf_list_t *list)
11012 {
11013 	struct nlattr *attr, *link_mac_remote_attr;
11014 	struct nlattr *tb[TX_LATENCY_ATTR(LINK_MAX) + 1];
11015 	int ret = 0, rem;
11016 	uint8_t vdev_id, *mac;
11017 
11018 	if (!links_attr || !list)
11019 		return -EINVAL;
11020 
11021 	/* links for MLO STA are attached to different vdevs */
11022 	vdev_id = (adapter->device_mode == QDF_STA_MODE ?
11023 		   CDP_VDEV_ALL : adapter->deflink->vdev_id);
11024 
11025 	nla_for_each_nested(attr, links_attr, rem) {
11026 		ret = wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(LINK_MAX),
11027 					      nla_data(attr), nla_len(attr),
11028 					      tx_latency_link_policy);
11029 		if (ret) {
11030 			hdd_err("Attribute parse failed, ret %d", ret);
11031 			ret = -EINVAL;
11032 			goto out;
11033 		}
11034 
11035 		link_mac_remote_attr = tb[TX_LATENCY_ATTR(LINK_MAC_REMOTE)];
11036 		if (!link_mac_remote_attr) {
11037 			hdd_err("Missing link mac remote attribute");
11038 			ret = -EINVAL;
11039 			goto out;
11040 		}
11041 
11042 		if (nla_len(link_mac_remote_attr) < QDF_MAC_ADDR_SIZE) {
11043 			hdd_err("Attribute link mac remote is invalid");
11044 			ret = -EINVAL;
11045 			goto out;
11046 		}
11047 
11048 		mac = (uint8_t *)nla_data(link_mac_remote_attr);
11049 		ret = hdd_tx_latency_link_list_add(list, vdev_id, mac);
11050 		if (ret)
11051 			goto out;
11052 	}
11053 
11054 out:
11055 	if (ret)
11056 		hdd_tx_latency_link_list_free(list);
11057 
11058 	return ret;
11059 }
11060 
11061 /**
11062  * hdd_tx_latency_get_links_for_sap() - get all the active links for SAP mode
11063  * @adapter: pointer to hdd vdev/net_device context
11064  * @list: list of the nodes for link info
11065  *
11066  * Return: 0 on success; error number otherwise.
11067  */
11068 static int
11069 hdd_tx_latency_get_links_for_sap(struct hdd_adapter *adapter, qdf_list_t *list)
11070 {
11071 	struct hdd_station_info *sta, *tmp = NULL;
11072 	int ret = 0;
11073 
11074 	hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta, tmp,
11075 				  STA_INFO_SOFTAP_GET_STA_INFO) {
11076 		if (QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes)) {
11077 			hdd_put_sta_info_ref(&adapter->sta_info_list,
11078 					     &sta, true,
11079 					     STA_INFO_SOFTAP_GET_STA_INFO);
11080 			continue;
11081 		}
11082 
11083 		ret = hdd_tx_latency_link_list_add(list,
11084 						   adapter->deflink->vdev_id,
11085 						   sta->sta_mac.bytes);
11086 		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta, true,
11087 				     STA_INFO_SOFTAP_GET_STA_INFO);
11088 		if (ret)
11089 			goto out;
11090 	}
11091 
11092 out:
11093 	if (ret)
11094 		hdd_tx_latency_link_list_free(list);
11095 
11096 	return ret;
11097 }
11098 
11099 /**
11100  * hdd_tx_latency_get_links_for_sta() - get all the active links for station
11101  * mode
11102  * @adapter: pointer to hdd vdev/net_device context
11103  * @list: list of the nodes for link info
11104  *
11105  * Return: 0 on success; error number otherwise.
11106  */
11107 static int
11108 hdd_tx_latency_get_links_for_sta(struct hdd_adapter *adapter, qdf_list_t *list)
11109 {
11110 	struct wlan_hdd_link_info *link_info;
11111 	struct hdd_station_ctx *ctx;
11112 	int ret = 0;
11113 
11114 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
11115 		if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
11116 			continue;
11117 
11118 		ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
11119 		if (!hdd_cm_is_vdev_associated(link_info))
11120 			continue;
11121 
11122 		ret = hdd_tx_latency_link_list_add(list, link_info->vdev_id,
11123 						   ctx->conn_info.bssid.bytes);
11124 		if (ret)
11125 			goto out;
11126 	}
11127 
11128 out:
11129 	if (ret)
11130 		hdd_tx_latency_link_list_free(list);
11131 
11132 	return ret;
11133 }
11134 
11135 /**
11136  * hdd_tx_latency_get_links() - get all the active links
11137  * @adapter: pointer to hdd vdev/net_device context
11138  * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11139  * @list: list of the nodes for link info
11140  *
11141  * Return: 0 on success; error number otherwise.
11142  */
11143 static int
11144 hdd_tx_latency_get_links(struct hdd_adapter *adapter,
11145 			 struct nlattr *links_attr, qdf_list_t *list)
11146 {
11147 	if (!list)
11148 		return -EINVAL;
11149 
11150 	if (links_attr)
11151 		return hdd_tx_latency_get_links_from_attr(adapter,
11152 							  links_attr, list);
11153 
11154 	if (adapter->device_mode == QDF_SAP_MODE ||
11155 	    adapter->device_mode == QDF_P2P_GO_MODE)
11156 		return hdd_tx_latency_get_links_for_sap(adapter, list);
11157 	else if (adapter->device_mode == QDF_STA_MODE ||
11158 		 adapter->device_mode == QDF_P2P_CLIENT_MODE)
11159 		return hdd_tx_latency_get_links_for_sta(adapter, list);
11160 	else
11161 		return -ENOTSUPP;
11162 }
11163 
11164 /**
11165  * hdd_tx_latency_populate_links() - get per link tx latency stats and fill
11166  * into skb
11167  * @soc: pointer to soc context
11168  * @skb: skb for vendor command response/async event
11169  * @list: list of the nodes for link info
11170  *
11171  * Return: 0 on success; error number otherwise.
11172  */
11173 static inline int
11174 hdd_tx_latency_populate_links(void *soc, struct sk_buff *skb, qdf_list_t *list)
11175 {
11176 	struct nlattr *links;
11177 	struct tx_latency_link_node *entry, *next;
11178 	struct cdp_tx_latency latency = {0};
11179 	int ret, idx = 0;
11180 	uint8_t *mac;
11181 	QDF_STATUS status;
11182 
11183 	links = nla_nest_start(skb, TX_LATENCY_ATTR(LINKS));
11184 	if (!links)
11185 		return -ENOMEM;
11186 
11187 	qdf_list_for_each_del(list, entry, next, node) {
11188 		qdf_list_remove_node(list, &entry->node);
11189 		mac = entry->mac_remote.bytes;
11190 		status = cdp_host_tx_latency_stats_fetch(soc, entry->vdev_id,
11191 							 mac, &latency);
11192 		if (QDF_IS_STATUS_ERROR(status)) {
11193 			qdf_mem_free(entry);
11194 			return qdf_status_to_os_return(status);
11195 		}
11196 
11197 		ret = hdd_tx_latency_fill_link_stats(skb, &latency, idx);
11198 		qdf_mem_free(entry);
11199 		if (ret)
11200 			return ret;
11201 
11202 		idx++;
11203 	}
11204 
11205 	nla_nest_end(skb, links);
11206 	return 0;
11207 }
11208 
11209 /**
11210  * hdd_tx_latency_get() - get per link tx latency stats
11211  * @wiphy: pointer to wiphy
11212  * @adapter: pointer to hdd vdev/net_device context
11213  * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11214  *
11215  * Return: 0 on success; error number otherwise.
11216  */
11217 static int
11218 hdd_tx_latency_get(struct wiphy *wiphy,
11219 		   struct hdd_adapter *adapter, struct nlattr *links_attr)
11220 {
11221 	int ret;
11222 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
11223 	struct sk_buff *reply_skb = NULL;
11224 	uint32_t skb_len, links_num = 0;
11225 	qdf_list_t links_list;
11226 
11227 	if (!soc)
11228 		return -EINVAL;
11229 
11230 	qdf_list_create(&links_list, 0);
11231 	ret = hdd_tx_latency_get_links(adapter, links_attr, &links_list);
11232 	if (ret)
11233 		goto out;
11234 
11235 	links_num = qdf_list_size(&links_list);
11236 	if (!links_num) {
11237 		hdd_err_rl("no valid peers");
11238 		ret = -EINVAL;
11239 		goto out;
11240 	}
11241 
11242 	skb_len = hdd_tx_latency_get_skb_len(links_num);
11243 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
11244 	if (!reply_skb) {
11245 		ret = -ENOMEM;
11246 		goto out;
11247 	}
11248 
11249 	ret = hdd_tx_latency_populate_links(soc, reply_skb, &links_list);
11250 	if (ret)
11251 		goto free_skb;
11252 
11253 	ret = wlan_cfg80211_vendor_cmd_reply(reply_skb);
11254 	/* skb has been consumed regardless of the return value */
11255 	goto out;
11256 
11257 free_skb:
11258 	wlan_cfg80211_vendor_free_skb(reply_skb);
11259 	hdd_tx_latency_link_list_free(&links_list);
11260 out:
11261 	qdf_list_destroy(&links_list);
11262 	hdd_debug_rl("get stats with ret %d", ret);
11263 	return ret;
11264 }
11265 
11266 /**
11267  * hdd_tx_latency_enable() - enable per link tx latency stats
11268  * @adapter: pointer to hdd vdev/net_device context
11269  * @period: statistical period for transmit latency
11270  * @periodic_report: whether driver needs to report transmit latency
11271  * statistics at the end of each period
11272  * @buckets_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKETS
11273  *
11274  * Return: 0 on success; error number otherwise.
11275  */
11276 static int
11277 hdd_tx_latency_enable(struct hdd_adapter *adapter, uint32_t period,
11278 		      bool periodic_report, struct nlattr *buckets_attr)
11279 {
11280 	struct nlattr *tb[TX_LATENCY_ATTR(BUCKET_MAX) + 1];
11281 	struct nlattr *attr, *bucket_type_attr, *bucket_granularity_attr;
11282 	int rem, ret;
11283 	uint8_t bucket_type;
11284 	struct cdp_tx_latency_config config = {0};
11285 
11286 	nla_for_each_nested(attr, buckets_attr, rem) {
11287 		ret = wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(BUCKET_MAX),
11288 					      nla_data(attr), nla_len(attr),
11289 					      tx_latency_bucket_policy);
11290 		if (ret) {
11291 			hdd_err_rl("Attribute parse failed, ret %d", ret);
11292 			return -EINVAL;
11293 		}
11294 
11295 		bucket_type_attr = tb[TX_LATENCY_ATTR(BUCKET_TYPE)];
11296 		if (!bucket_type_attr) {
11297 			hdd_err_rl("Missing bucket type attribute");
11298 			return -EINVAL;
11299 		}
11300 
11301 		bucket_granularity_attr =
11302 			tb[TX_LATENCY_ATTR(BUCKET_GRANULARITY)];
11303 		if (!bucket_granularity_attr) {
11304 			hdd_err_rl("Missing bucket granularity attribute");
11305 			return -EINVAL;
11306 		}
11307 
11308 		bucket_type = nla_get_u8(bucket_type_attr);
11309 		if (bucket_type >= CDP_TX_LATENCY_TYPE_MAX) {
11310 			hdd_err_rl("Invalid bucket type %u", bucket_type);
11311 			return -EINVAL;
11312 		}
11313 
11314 		config.granularity[bucket_type] =
11315 			nla_get_u32(bucket_granularity_attr);
11316 		if (!config.granularity[bucket_type]) {
11317 			hdd_err_rl("Invalid granularity for type %d",
11318 				   bucket_type);
11319 			return -EINVAL;
11320 		}
11321 	}
11322 
11323 	for (rem = 0; rem < CDP_TX_LATENCY_TYPE_MAX; rem++) {
11324 		if (config.granularity[rem])
11325 			continue;
11326 
11327 		hdd_err_rl("Invalid granularity for type %d", rem);
11328 		return -EINVAL;
11329 	}
11330 
11331 	config.enable = true;
11332 	config.report = periodic_report;
11333 	config.period = period;
11334 	return hdd_tx_latency_set(adapter, &config);
11335 }
11336 
11337 /**
11338  * hdd_tx_latency_disable() - disable per link tx latency stats
11339  * @adapter: pointer to hdd vdev/net_device context
11340  *
11341  * Return: 0 on success; error number otherwise.
11342  */
11343 static int hdd_tx_latency_disable(struct hdd_adapter *adapter)
11344 {
11345 	struct cdp_tx_latency_config config = {0};
11346 
11347 	return hdd_tx_latency_set(adapter, &config);
11348 }
11349 
11350 /**
11351  * __wlan_hdd_cfg80211_tx_latency - configure/retrieve per-link transmit
11352  * latency statistics
11353  * @wiphy: wiphy handle
11354  * @wdev: wdev handle
11355  * @data: user layer input
11356  * @data_len: length of user layer input
11357  *
11358  * this function is called in ssr protected environment.
11359  *
11360  * return: 0 success, none zero for failure
11361  */
11362 static int
11363 __wlan_hdd_cfg80211_tx_latency(struct wiphy *wiphy, struct wireless_dev *wdev,
11364 			       const void *data, int data_len)
11365 {
11366 	int ret;
11367 	uint32_t action, period;
11368 	struct nlattr *period_attr, *buckets_attr, *links_attr;
11369 
11370 	struct net_device *dev = wdev->netdev;
11371 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
11372 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
11373 	struct nlattr *tb[TX_LATENCY_ATTR(MAX) + 1];
11374 	bool periodic_report;
11375 
11376 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
11377 		hdd_warn("command not allowed in ftm mode");
11378 		return -EPERM;
11379 	}
11380 
11381 	ret = wlan_hdd_validate_context(hdd_ctx);
11382 	if (ret)
11383 		return -EINVAL;
11384 
11385 	if (wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(MAX),
11386 				    data, data_len,
11387 				    tx_latency_policy)) {
11388 		hdd_err_rl("invalid attribute");
11389 		return -EINVAL;
11390 	}
11391 
11392 	if (!tb[TX_LATENCY_ATTR(ACTION)]) {
11393 		hdd_err_rl("no attr action");
11394 		return -EINVAL;
11395 	}
11396 
11397 	action = nla_get_u32(tb[TX_LATENCY_ATTR(ACTION)]);
11398 	switch (action) {
11399 	case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_DISABLE:
11400 		if (!adapter->tx_latency_cfg.enable) {
11401 			ret = 0;
11402 			break;
11403 		}
11404 
11405 		ret = hdd_tx_latency_disable(adapter);
11406 		break;
11407 	case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_ENABLE:
11408 		period_attr = tb[TX_LATENCY_ATTR(PERIOD)];
11409 		if (!period_attr) {
11410 			hdd_err_rl("no attr period");
11411 			return -EINVAL;
11412 		}
11413 
11414 		buckets_attr = tb[TX_LATENCY_ATTR(BUCKETS)];
11415 		if (!buckets_attr) {
11416 			hdd_err_rl("no attr buckets");
11417 			return -EINVAL;
11418 		}
11419 
11420 		period = nla_get_u32(period_attr);
11421 		if (!period) {
11422 			hdd_err_rl("invalid period");
11423 			return -EINVAL;
11424 		}
11425 
11426 		periodic_report =
11427 			nla_get_flag(tb[TX_LATENCY_ATTR(PERIODIC_REPORT)]);
11428 		ret = hdd_tx_latency_enable(adapter, period,
11429 					    periodic_report, buckets_attr);
11430 		break;
11431 	case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_GET:
11432 		if (!adapter->tx_latency_cfg.enable) {
11433 			hdd_err_rl("please enable the feature first");
11434 			ret = -EINVAL;
11435 			break;
11436 		}
11437 
11438 		links_attr = tb[TX_LATENCY_ATTR(LINKS)];
11439 		ret = hdd_tx_latency_get(wiphy, adapter, links_attr);
11440 		break;
11441 	default:
11442 		ret = -EINVAL;
11443 		break;
11444 	}
11445 
11446 	return ret;
11447 }
11448 
11449 /**
11450  * wlan_hdd_cfg80211_tx_latency - configure/retrieve per-link transmit latency
11451  * statistics
11452  * @wiphy: wiphy handle
11453  * @wdev: wdev handle
11454  * @data: user layer input
11455  * @data_len: length of user layer input
11456  *
11457  * return: 0 success, einval failure
11458  */
11459 int wlan_hdd_cfg80211_tx_latency(struct wiphy *wiphy,
11460 				 struct wireless_dev *wdev,
11461 				 const void *data, int data_len)
11462 {
11463 	int errno;
11464 	struct osif_vdev_sync *vdev_sync;
11465 
11466 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
11467 	if (errno)
11468 		return errno;
11469 
11470 	errno = __wlan_hdd_cfg80211_tx_latency(wiphy, wdev, data, data_len);
11471 	osif_vdev_sync_op_stop(vdev_sync);
11472 	return errno;
11473 }
11474 
11475 /**
11476  * hdd_tx_latency_stats_cb() - callback function for transmit latency stats
11477  * @vdev_id: Unique value to identify VDEV
11478  * @stats_list: list of the nodes for per-link transmit latency statistics
11479  *
11480  * Return: QDF_STATUS
11481  */
11482 static QDF_STATUS
11483 hdd_tx_latency_stats_cb(uint8_t vdev_id, qdf_list_t *stats_list)
11484 {
11485 	uint32_t len, stats_cnt;
11486 	struct sk_buff *vendor_event;
11487 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
11488 	struct wlan_hdd_link_info *link_info;
11489 	struct cdp_tx_latency *entry, *next;
11490 	struct nlattr *links;
11491 	int ret, idx = 0, flags = cds_get_gfp_flags();
11492 	int event_idx = QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY_INDEX;
11493 
11494 	if (!hdd_ctx) {
11495 		hdd_err("HDD context is NULL");
11496 		return QDF_STATUS_E_FAULT;
11497 	}
11498 
11499 	if (!stats_list || qdf_list_empty(stats_list)) {
11500 		hdd_err("invalid stats list");
11501 		return QDF_STATUS_E_INVAL;
11502 	}
11503 
11504 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
11505 	if (!link_info) {
11506 		hdd_err("adapter NULL for vdev id %d", vdev_id);
11507 		return QDF_STATUS_E_INVAL;
11508 	}
11509 
11510 	stats_cnt = qdf_list_size(stats_list);
11511 	len = hdd_tx_latency_get_skb_len(stats_cnt);
11512 	hdd_debug_rl("vdev id %d stats cnt %d", vdev_id, stats_cnt);
11513 	vendor_event =
11514 		wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
11515 						 &link_info->adapter->wdev,
11516 						 len, event_idx, flags);
11517 	if (!vendor_event) {
11518 		hdd_err("event alloc failed vdev id %d, len %d",
11519 			vdev_id, len);
11520 		return QDF_STATUS_E_NOMEM;
11521 	}
11522 
11523 	links = nla_nest_start(vendor_event, TX_LATENCY_ATTR(LINKS));
11524 	if (!links) {
11525 		wlan_cfg80211_vendor_free_skb(vendor_event);
11526 		hdd_err("failed to put peers");
11527 		return QDF_STATUS_E_NOMEM;
11528 	}
11529 
11530 	qdf_list_for_each_del(stats_list, entry, next, node) {
11531 		qdf_list_remove_node(stats_list, &entry->node);
11532 		ret = hdd_tx_latency_fill_link_stats(vendor_event, entry, idx);
11533 		qdf_mem_free(entry);
11534 		if (ret) {
11535 			hdd_err("failed to populate stats for idx %d", idx);
11536 			wlan_cfg80211_vendor_free_skb(vendor_event);
11537 			return QDF_STATUS_E_NOMEM;
11538 		}
11539 
11540 		idx++;
11541 	}
11542 
11543 	nla_nest_end(vendor_event, links);
11544 	wlan_cfg80211_vendor_event(vendor_event, flags);
11545 	return QDF_STATUS_SUCCESS;
11546 }
11547 
11548 /**
11549  * hdd_tx_latency_register_cb() - register callback function for transmit
11550  * latency stats
11551  * @soc: pointer to soc context
11552  *
11553  * Return: QDF_STATUS
11554  */
11555 QDF_STATUS hdd_tx_latency_register_cb(void *soc)
11556 {
11557 	hdd_debug("Register tx latency callback");
11558 	return cdp_host_tx_latency_stats_register_cb(soc,
11559 						     hdd_tx_latency_stats_cb);
11560 }
11561 #endif
11562 
11563 #ifdef WLAN_CHIPSET_STATS
11564 #ifdef CNSS_GENL
11565 static int nl_srv_bcast_cstats(struct sk_buff *skb)
11566 {
11567 	return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG);
11568 }
11569 #else
11570 static int nl_srv_bcast_cstats(struct sk_buff *skb)
11571 {
11572 	return nl_srv_bcast(skb);
11573 }
11574 #endif
11575 
11576 int hdd_cstats_send_data_to_userspace(char *buff, unsigned int len,
11577 				      enum cstats_types type)
11578 {
11579 	struct sk_buff *skb = NULL;
11580 	struct nlmsghdr *nlh;
11581 	tAniNlHdr *wnl;
11582 	static int nlmsg_seq;
11583 	int tot_msg_len;
11584 	int ret = -1;
11585 
11586 	if (type == CSTATS_HOST_TYPE) {
11587 		*(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_HOST_LOG_TYPE;
11588 		*(unsigned short *)(buff + 2) = len - sizeof(tAniHdr);
11589 	} else if (type == CSTATS_FW_TYPE) {
11590 		*(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_FW_LOG_TYPE;
11591 		*(unsigned short *)(buff + 2) = len - sizeof(tAniHdr);
11592 	}
11593 
11594 	skb = dev_alloc_skb(MAX_CSTATS_NODE_LENGTH);
11595 	if (!skb) {
11596 		qdf_err("dev_alloc_skb() failed");
11597 		return -ENOMEM;
11598 	}
11599 
11600 	tot_msg_len = NLMSG_SPACE(len + sizeof(wnl->radio));
11601 
11602 	nlh = nlmsg_put(skb, 0, nlmsg_seq++,
11603 			ANI_NL_MSG_LOG,
11604 			len + sizeof(wnl->radio), NLM_F_REQUEST);
11605 	if (!nlh) {
11606 		qdf_err("nlmsg_put() failed for msg size[%d]", tot_msg_len);
11607 		dev_kfree_skb(skb);
11608 		return -EINVAL;
11609 	}
11610 
11611 	wnl = (tAniNlHdr *)nlh;
11612 	wnl->radio = 0;
11613 
11614 	memcpy(nlmsg_data(nlh) + sizeof(wnl->radio), buff, len);
11615 
11616 	ret = nl_srv_bcast_cstats(skb);
11617 	if (ret < 0)
11618 		qdf_err("Send Failed %d", ret);
11619 
11620 	return ret;
11621 }
11622 
11623 struct cstats_tx_rx_ops cstats_ops = {
11624 	.cstats_send_data_to_usr = hdd_cstats_send_data_to_userspace,
11625 };
11626 
11627 void hdd_register_cstats_ops(void)
11628 {
11629 	ucfg_cp_stats_cstats_register_tx_rx_ops(&cstats_ops);
11630 }
11631 
11632 void
11633 hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev *vdev,
11634 				  uint16_t transaction_id)
11635 {
11636 	struct cstats_nan_ndi_delete_req stat = {0};
11637 
11638 	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_DELETE_EVENT_ID;
11639 	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_delete_req) -
11640 			      sizeof(struct cstats_hdr);
11641 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
11642 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
11643 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
11644 	stat.cmn.time_tick = qdf_get_log_timestamp();
11645 	stat.transaction_id = transaction_id;
11646 
11647 	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_delete_req), &stat);
11648 }
11649 
11650 void
11651 hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info *li,
11652 				   struct nan_datapath_inf_create_rsp *ndi_rsp)
11653 {
11654 	struct cstats_nan_ndi_create_resp stat = {0};
11655 	struct wlan_objmgr_vdev *vdev;
11656 	struct nan_vdev_priv_obj *priv_obj;
11657 
11658 	vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_OSIF_NAN_ID);
11659 	if (!vdev) {
11660 		hdd_err("vdev is NULL");
11661 		return;
11662 	}
11663 
11664 	priv_obj = nan_get_vdev_priv_obj(vdev);
11665 	if (!priv_obj) {
11666 		hdd_err("priv_obj is null");
11667 		return;
11668 	}
11669 
11670 	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_RESP_EVENT_ID;
11671 	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_resp) -
11672 			      sizeof(struct cstats_hdr);
11673 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
11674 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
11675 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
11676 	stat.cmn.time_tick = qdf_get_log_timestamp();
11677 	stat.status = ndi_rsp->status;
11678 	stat.reason = ndi_rsp->reason;
11679 	qdf_spin_lock_bh(&priv_obj->lock);
11680 	stat.transaction_id = priv_obj->ndp_create_transaction_id;
11681 	qdf_spin_unlock_bh(&priv_obj->lock);
11682 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
11683 
11684 	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_resp),
11685 			       &stat);
11686 }
11687 
11688 void hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev *vdev,
11689 				       uint16_t transaction_id)
11690 {
11691 	struct cstats_nan_ndi_create_req stat = {0};
11692 
11693 	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_EVENT_ID;
11694 	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_req) -
11695 			      sizeof(struct cstats_hdr);
11696 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
11697 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
11698 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
11699 	stat.cmn.time_tick = qdf_get_log_timestamp();
11700 	stat.transaction_id = transaction_id;
11701 
11702 	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_req), &stat);
11703 }
11704 #endif /* WLAN_CHIPSET_STATS */
11705