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