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