xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_cmn.c (revision c753fff3818bf35e70281a057d975bdb1a79ecca)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /*
19  * DOC: contains MLO manager ap related functionality
20  */
21 #include "wlan_mlo_mgr_cmn.h"
22 #include "wlan_mlo_mgr_main.h"
23 #include "wlan_mlo_mgr_sta.h"
24 #ifdef WLAN_MLO_MULTI_CHIP
25 #include "wlan_lmac_if_def.h"
26 #endif
27 #include "wlan_serialization_api.h"
28 #include <target_if_mlo_mgr.h>
29 #include <cdp_txrx_cmn.h>
30 #include <wlan_cfg.h>
31 #include "wlan_utility.h"
32 
33 void mlo_get_link_information(struct qdf_mac_addr *mld_addr,
34 			      struct mlo_link_info *info)
35 {
36 /* Pass the partner link information*/
37 }
38 
39 void is_mlo_all_links_up(struct wlan_mlo_dev_context *mldev)
40 {
41 /* Loop through all the vdev's part of the ML device*/
42 /* STA: Loop through all the associated vdev status. */
43 }
44 
45 struct wlan_objmgr_vdev *mlo_get_vdev_by_link_id(struct wlan_objmgr_vdev *vdev,
46 						 uint8_t link_id,
47 						 wlan_objmgr_ref_dbgid id)
48 {
49 	struct wlan_mlo_dev_context *dev_ctx;
50 	int i;
51 	struct wlan_objmgr_vdev *partner_vdev = NULL;
52 
53 	if (!vdev || !vdev->mlo_dev_ctx) {
54 		mlo_err("Invalid input");
55 		return partner_vdev;
56 	}
57 
58 	dev_ctx = vdev->mlo_dev_ctx;
59 
60 	mlo_dev_lock_acquire(dev_ctx);
61 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
62 		if (dev_ctx->wlan_vdev_list[i] &&
63 		    wlan_vdev_mlme_is_mlo_vdev(dev_ctx->wlan_vdev_list[i]) &&
64 		    dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id ==
65 		    link_id) {
66 			if (wlan_objmgr_vdev_try_get_ref(
67 						dev_ctx->wlan_vdev_list[i],
68 						id) == QDF_STATUS_SUCCESS)
69 				partner_vdev = dev_ctx->wlan_vdev_list[i];
70 
71 			break;
72 		}
73 	}
74 	mlo_dev_lock_release(dev_ctx);
75 
76 	return partner_vdev;
77 }
78 
79 void mlo_release_vdev_ref(struct wlan_objmgr_vdev *vdev)
80 {
81 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
82 }
83 
84 QDF_STATUS mlo_reg_mlme_ext_cb(struct mlo_mgr_context *ctx,
85 			       struct mlo_mlme_ext_ops *ops)
86 {
87 	if (!ctx)
88 		return QDF_STATUS_E_FAILURE;
89 
90 	ctx->mlme_ops = ops;
91 	return QDF_STATUS_SUCCESS;
92 }
93 
94 QDF_STATUS mlo_unreg_mlme_ext_cb(struct mlo_mgr_context *ctx)
95 {
96 	if (!ctx)
97 		return QDF_STATUS_E_FAILURE;
98 
99 	ctx->mlme_ops = NULL;
100 	return QDF_STATUS_SUCCESS;
101 }
102 
103 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
104 QDF_STATUS wlan_mlo_mgr_register_osif_ext_ops(struct mlo_mgr_context *mlo_ctx,
105 					      struct mlo_osif_ext_ops *ops)
106 {
107 	if (!ops || !mlo_ctx)
108 		return QDF_STATUS_E_FAILURE;
109 
110 	mlo_ctx->osif_ops = ops;
111 	return QDF_STATUS_SUCCESS;
112 }
113 
114 QDF_STATUS wlan_mlo_mgr_unregister_osif_ext_ops(struct mlo_mgr_context *mlo_ctx)
115 {
116 	if (!mlo_ctx)
117 		return QDF_STATUS_E_FAILURE;
118 
119 	mlo_ctx->osif_ops = NULL;
120 	return QDF_STATUS_SUCCESS;
121 }
122 #endif
123 
124 QDF_STATUS mlo_mlme_clone_sta_security(struct wlan_objmgr_vdev *vdev,
125 				       struct wlan_cm_connect_req *req)
126 {
127 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
128 	struct vdev_mlme_obj *vdev_mlme;
129 	QDF_STATUS status = QDF_STATUS_SUCCESS;
130 
131 	if (!req || !mlo_ctx || !mlo_ctx->mlme_ops ||
132 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req)
133 		return QDF_STATUS_E_FAILURE;
134 
135 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
136 	if (!vdev_mlme)
137 		return QDF_STATUS_E_FAILURE;
138 
139 	if (mlo_ctx->mlme_ops->mlo_mlme_ext_clone_security_param) {
140 		status =
141 			mlo_ctx->mlme_ops->mlo_mlme_ext_clone_security_param(
142 				vdev_mlme, req);
143 	}
144 
145 	return status;
146 }
147 
148 QDF_STATUS mlo_mlme_sta_op_class(struct wlan_objmgr_vdev *vdev,
149 				 uint8_t *ml_ie)
150 {
151 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
152 	struct vdev_mlme_obj *vdev_mlme;
153 	QDF_STATUS status = QDF_STATUS_SUCCESS;
154 
155 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
156 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req)
157 		return QDF_STATUS_E_FAILURE;
158 
159 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
160 	if (!vdev_mlme)
161 		return QDF_STATUS_E_FAILURE;
162 
163 	if (mlo_ctx->mlme_ops->mlo_mlme_ext_sta_op_class)
164 		status =
165 			mlo_ctx->mlme_ops->mlo_mlme_ext_sta_op_class(
166 				vdev_mlme, ml_ie);
167 
168 	return status;
169 }
170 
171 QDF_STATUS mlo_mlme_validate_conn_req(struct wlan_objmgr_vdev *vdev,
172 				      void *ext_data)
173 {
174 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
175 	struct vdev_mlme_obj *vdev_mlme;
176 	QDF_STATUS status;
177 
178 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
179 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req)
180 		return QDF_STATUS_E_FAILURE;
181 
182 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
183 	if (!vdev_mlme)
184 		return QDF_STATUS_E_FAILURE;
185 
186 	status =
187 		mlo_ctx->mlme_ops->mlo_mlme_ext_validate_conn_req(vdev_mlme,
188 								  ext_data);
189 	return status;
190 }
191 
192 QDF_STATUS mlo_mlme_create_link_vdev(struct wlan_objmgr_vdev *vdev,
193 				     void *ext_data)
194 {
195 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
196 	struct vdev_mlme_obj *vdev_mlme;
197 	QDF_STATUS status;
198 
199 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
200 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_create_link_vdev)
201 		return QDF_STATUS_E_FAILURE;
202 
203 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
204 	if (!vdev_mlme)
205 		return QDF_STATUS_E_FAILURE;
206 
207 	status =
208 		mlo_ctx->mlme_ops->mlo_mlme_ext_create_link_vdev(vdev_mlme,
209 								 ext_data);
210 	return status;
211 }
212 
213 void mlo_mlme_peer_create(struct wlan_objmgr_vdev *vdev,
214 			  struct wlan_mlo_peer_context *ml_peer,
215 			  struct qdf_mac_addr *addr,
216 			  qdf_nbuf_t frm_buf)
217 {
218 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
219 
220 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
221 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_create)
222 		return;
223 
224 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_create(vdev, ml_peer,
225 						    addr, frm_buf);
226 }
227 
228 void mlo_mlme_bridge_peer_create(struct wlan_objmgr_vdev *vdev,
229 				 struct wlan_mlo_peer_context *ml_peer,
230 				 struct qdf_mac_addr *addr,
231 				 qdf_nbuf_t frm_buf)
232 {
233 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
234 
235 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
236 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_bridge_peer_create)
237 		return;
238 
239 	mlo_ctx->mlme_ops->mlo_mlme_ext_bridge_peer_create(vdev, ml_peer,
240 							   addr, frm_buf);
241 }
242 
243 void mlo_mlme_peer_assoc(struct wlan_objmgr_peer *peer)
244 {
245 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
246 
247 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
248 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc)
249 		return;
250 
251 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc(peer);
252 }
253 
254 void mlo_mlme_peer_assoc_fail(struct wlan_objmgr_peer *peer)
255 {
256 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
257 
258 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
259 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc_fail)
260 		return;
261 
262 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_assoc_fail(peer);
263 }
264 
265 void mlo_mlme_peer_delete(struct wlan_objmgr_peer *peer)
266 {
267 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
268 
269 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
270 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_delete)
271 		return;
272 
273 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_delete(peer);
274 }
275 
276 void mlo_mlme_peer_assoc_resp(struct wlan_objmgr_peer *peer)
277 {
278 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
279 
280 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
281 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp)
282 		return;
283 
284 	mlo_ctx->mlme_ops->mlo_mlme_ext_assoc_resp(peer);
285 }
286 
287 qdf_nbuf_t mlo_mlme_get_link_assoc_req(struct wlan_objmgr_peer *peer,
288 				       uint8_t link_ix)
289 {
290 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
291 
292 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
293 	    !mlo_ctx->mlme_ops->mlo_mlme_get_link_assoc_req)
294 		return NULL;
295 
296 	return mlo_ctx->mlme_ops->mlo_mlme_get_link_assoc_req(peer, link_ix);
297 }
298 
299 void mlo_mlme_peer_deauth(struct wlan_objmgr_peer *peer, uint8_t is_disassoc)
300 {
301 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
302 
303 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
304 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_deauth)
305 		return;
306 
307 	mlo_ctx->mlme_ops->mlo_mlme_ext_deauth(peer, is_disassoc);
308 }
309 
310 #ifdef UMAC_MLO_AUTH_DEFER
311 void mlo_mlme_peer_process_auth(struct mlpeer_auth_params *auth_param)
312 {
313 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
314 
315 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
316 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_process_auth)
317 		return;
318 
319 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_process_auth(auth_param);
320 }
321 #endif
322 
323 void mlo_mlme_peer_reassoc(struct wlan_objmgr_vdev *vdev,
324 			   struct wlan_mlo_peer_context *ml_peer,
325 			   struct qdf_mac_addr *addr,
326 			   qdf_nbuf_t frm_buf)
327 {
328 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
329 
330 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
331 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_peer_reassoc)
332 		return;
333 
334 	mlo_ctx->mlme_ops->mlo_mlme_ext_peer_reassoc(vdev, ml_peer, addr,
335 						     frm_buf);
336 }
337 
338 uint8_t mlo_get_link_vdev_ix(struct wlan_mlo_dev_context *ml_dev,
339 			     struct wlan_objmgr_vdev *vdev)
340 {
341 	uint8_t i;
342 
343 	mlo_dev_lock_acquire(ml_dev);
344 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
345 		if (vdev == ml_dev->wlan_vdev_list[i]) {
346 			mlo_dev_lock_release(ml_dev);
347 			return i;
348 		}
349 	}
350 	mlo_dev_lock_release(ml_dev);
351 
352 	return (uint8_t)-1;
353 }
354 
355 #ifdef WLAN_MLO_MULTI_CHIP
356 int8_t wlan_mlo_get_max_num_links(uint8_t grp_id)
357 {
358 	struct mlo_mgr_context *mlo_ctx;
359 
360 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
361 	if (!mlo_ctx)
362 		return WLAN_MLO_INVALID_NUM_LINKS;
363 
364 	if (grp_id >= mlo_ctx->total_grp) {
365 		mlo_err("Invalid grp id %d, total no of groups %d",
366 			grp_id, mlo_ctx->total_grp);
367 		return WLAN_MLO_INVALID_NUM_LINKS;
368 	}
369 
370 	return (mlo_ctx->setup_info[grp_id].tot_socs *
371 		WLAN_MAX_MLO_LINKS_PER_SOC);
372 }
373 
374 int8_t wlan_mlo_get_num_active_links(uint8_t grp_id)
375 {
376 	struct mlo_mgr_context *mlo_ctx;
377 
378 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
379 
380 	if (!mlo_ctx)
381 		return WLAN_MLO_INVALID_NUM_LINKS;
382 
383 	if (grp_id >= mlo_ctx->total_grp) {
384 		qdf_err("Invalid grp id %d, total no of groups %d",
385 			grp_id, mlo_ctx->total_grp);
386 		return WLAN_MLO_INVALID_NUM_LINKS;
387 	}
388 
389 	return mlo_ctx->setup_info[grp_id].tot_links;
390 }
391 
392 uint16_t wlan_mlo_get_valid_link_bitmap(uint8_t grp_id)
393 {
394 	struct mlo_mgr_context *mlo_ctx;
395 
396 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
397 	if (!mlo_ctx)
398 		return 0;
399 
400 	if (grp_id >= mlo_ctx->total_grp) {
401 		qdf_err("Invalid grp id %d, total no of groups %d",
402 			grp_id, mlo_ctx->total_grp);
403 		return 0;
404 	}
405 
406 	return mlo_ctx->setup_info[grp_id].valid_link_bitmap;
407 }
408 
409 uint8_t wlan_mlo_get_psoc_mlo_chip_id(struct wlan_objmgr_psoc *psoc)
410 {
411 	struct wlan_lmac_if_tx_ops *tx_ops;
412 	uint8_t mlo_chip_id = WLAN_MLO_CHIP_ID_INVALID;
413 
414 	if (!psoc) {
415 		qdf_err("PSOC is NULL");
416 		return mlo_chip_id;
417 	}
418 
419 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
420 	if (tx_ops && tx_ops->mops.get_psoc_mlo_chip_id)
421 		mlo_chip_id = tx_ops->mops.get_psoc_mlo_chip_id(psoc);
422 
423 	return mlo_chip_id;
424 }
425 
426 qdf_export_symbol(wlan_mlo_get_psoc_mlo_chip_id);
427 
428 uint8_t wlan_mlo_get_psoc_group_id(struct wlan_objmgr_psoc *psoc)
429 {
430 	struct wlan_lmac_if_tx_ops *tx_ops;
431 	uint8_t ml_grp_id = WLAN_MLO_GROUP_INVALID;
432 
433 	if (!psoc) {
434 		qdf_err("PSOC is NULL");
435 		return -EINVAL;
436 	}
437 
438 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
439 	if (tx_ops && tx_ops->mops.get_psoc_mlo_group_id)
440 		ml_grp_id = tx_ops->mops.get_psoc_mlo_group_id(psoc);
441 
442 	return ml_grp_id;
443 }
444 
445 qdf_export_symbol(wlan_mlo_get_psoc_group_id);
446 
447 bool wlan_mlo_get_psoc_capable(struct wlan_objmgr_psoc *psoc)
448 {
449 	struct target_psoc_info *tgt_hdl;
450 
451 	if (!psoc) {
452 		qdf_err("PSOC is NULL");
453 		return false;
454 	}
455 
456 	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
457 	if (!tgt_hdl) {
458 		target_if_err("target_psoc_info is null");
459 		return false;
460 	}
461 
462 	if ((tgt_hdl->tif_ops) &&
463 	    (tgt_hdl->tif_ops->mlo_capable))
464 		return tgt_hdl->tif_ops->mlo_capable(psoc);
465 
466 	return false;
467 }
468 
469 uint16_t wlan_mlo_get_pdev_hw_link_id(struct wlan_objmgr_pdev *pdev)
470 {
471 	struct wlan_objmgr_psoc *psoc;
472 	struct wlan_lmac_if_tx_ops *tx_ops;
473 	uint16_t hw_link_id = INVALID_HW_LINK_ID;
474 
475 	psoc = wlan_pdev_get_psoc(pdev);
476 	if (psoc) {
477 		tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
478 		if (tx_ops && tx_ops->mops.get_hw_link_id)
479 			hw_link_id = tx_ops->mops.get_hw_link_id(pdev);
480 	}
481 
482 	return hw_link_id;
483 }
484 
485 qdf_export_symbol(wlan_mlo_get_pdev_hw_link_id);
486 
487 static void wlan_pdev_hw_link_iterator(struct wlan_objmgr_psoc *psoc,
488 				       void *obj, void *arg)
489 {
490 	struct hw_link_id_iterator *itr = (struct hw_link_id_iterator *)arg;
491 	struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)obj;
492 	uint16_t hw_link_id;
493 	uint8_t ml_grp_id;
494 
495 	if (itr->pdev)
496 		return;
497 
498 	ml_grp_id = wlan_mlo_get_psoc_group_id(psoc);
499 	if (ml_grp_id > WLAN_MAX_MLO_GROUPS)
500 		return;
501 
502 	if (ml_grp_id != itr->mlo_grp_id)
503 		return;
504 
505 	hw_link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
506 	if (hw_link_id == itr->hw_link_id) {
507 		if (wlan_objmgr_pdev_try_get_ref(pdev, itr->dbgid) ==
508 							QDF_STATUS_SUCCESS)
509 			itr->pdev = pdev;
510 	}
511 }
512 
513 static void wlan_mlo_find_hw_link_id(struct wlan_objmgr_psoc *psoc,
514 				     void *arg,
515 				     uint8_t index)
516 {
517 	struct hw_link_id_iterator *itr = (struct hw_link_id_iterator *)arg;
518 
519 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
520 				     wlan_pdev_hw_link_iterator,
521 				     arg, false, itr->dbgid);
522 }
523 
524 struct wlan_objmgr_pdev *
525 wlan_mlo_get_pdev_by_hw_link_id(uint16_t hw_link_id, uint8_t ml_grp_id,
526 				wlan_objmgr_ref_dbgid refdbgid)
527 {
528 	struct hw_link_id_iterator itr;
529 
530 	itr.hw_link_id = hw_link_id;
531 	itr.pdev = NULL;
532 	itr.mlo_grp_id = ml_grp_id;
533 	itr.dbgid = refdbgid;
534 
535 	wlan_objmgr_iterate_psoc_list(wlan_mlo_find_hw_link_id,
536 				      &itr, refdbgid);
537 
538 	return itr.pdev;
539 }
540 
541 qdf_export_symbol(wlan_mlo_get_pdev_by_hw_link_id);
542 #endif /*WLAN_MLO_MULTI_CHIP*/
543 
544 void mlo_get_ml_vdev_list(struct wlan_objmgr_vdev *vdev,
545 			  uint16_t *vdev_count,
546 			  struct wlan_objmgr_vdev **wlan_vdev_list)
547 {
548 	struct wlan_mlo_dev_context *dev_ctx;
549 	int i;
550 	QDF_STATUS status;
551 
552 	*vdev_count = 0;
553 
554 	if (!vdev || !vdev->mlo_dev_ctx) {
555 		mlo_err("Invalid input");
556 		return;
557 	}
558 
559 	dev_ctx = vdev->mlo_dev_ctx;
560 
561 	mlo_dev_lock_acquire(dev_ctx);
562 	*vdev_count = 0;
563 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
564 		if (dev_ctx->wlan_vdev_list[i] &&
565 		    wlan_vdev_mlme_is_mlo_vdev(dev_ctx->wlan_vdev_list[i])) {
566 			status = wlan_objmgr_vdev_try_get_ref(
567 						dev_ctx->wlan_vdev_list[i],
568 						WLAN_MLO_MGR_ID);
569 			if (QDF_IS_STATUS_ERROR(status))
570 				break;
571 			wlan_vdev_list[*vdev_count] =
572 				dev_ctx->wlan_vdev_list[i];
573 			(*vdev_count) += 1;
574 		}
575 	}
576 	mlo_dev_lock_release(dev_ctx);
577 }
578 
579 /**
580  * mlo_link_set_active() - send MLO link set active command
581  * @psoc: PSOC object
582  * @req: MLO link set active request
583  *
584  * Return: QDF_STATUS
585  */
586 static QDF_STATUS
587 mlo_link_set_active(struct wlan_objmgr_psoc *psoc,
588 		    struct mlo_link_set_active_req *req)
589 {
590 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
591 	struct mlo_link_set_active_param *param = &req->param;
592 	QDF_STATUS status;
593 	struct mlo_link_set_active_resp rsp_evt;
594 
595 	if (!psoc) {
596 		mlo_err("psoc is null");
597 		return QDF_STATUS_E_NULL_VALUE;
598 	}
599 
600 	mlo_tx_ops = target_if_mlo_get_tx_ops(psoc);
601 	if (!mlo_tx_ops) {
602 		mlo_err("tx_ops is null!");
603 		return QDF_STATUS_E_NULL_VALUE;
604 	}
605 
606 	if (!mlo_tx_ops->link_set_active) {
607 		mlo_err("link_set_active function is null!");
608 		return QDF_STATUS_E_NULL_VALUE;
609 	}
610 
611 	if (req->ctx.validate_set_mlo_link_cb) {
612 		status = req->ctx.validate_set_mlo_link_cb(psoc, param);
613 		if (QDF_IS_STATUS_ERROR(status)) {
614 			qdf_mem_zero(&rsp_evt, sizeof(rsp_evt));
615 			rsp_evt.status = status;
616 			if (req->ctx.set_mlo_link_cb)
617 				req->ctx.set_mlo_link_cb(req->ctx.vdev,
618 							 req->ctx.cb_arg,
619 							 &rsp_evt);
620 			return status;
621 		}
622 	}
623 
624 	return mlo_tx_ops->link_set_active(psoc, param);
625 }
626 
627 /**
628  * mlo_release_ser_link_set_active_cmd() - releases serialization command for
629  *  forcing MLO link active/inactive
630  * @vdev: Object manager vdev
631  *
632  * Return: None
633  */
634 static void
635 mlo_release_ser_link_set_active_cmd(struct wlan_objmgr_vdev *vdev)
636 {
637 	struct wlan_serialization_queued_cmd_info cmd = {0};
638 
639 	cmd.cmd_type = WLAN_SER_CMD_SET_MLO_LINK;
640 	cmd.requestor = WLAN_UMAC_COMP_MLO_MGR;
641 	cmd.cmd_id = 0;
642 	cmd.vdev = vdev;
643 
644 	mlo_debug("release serialization command");
645 	wlan_serialization_remove_cmd(&cmd);
646 }
647 
648 /**
649  * mlo_link_set_active_resp_vdev_handler() - vdev handler for mlo link set
650  * active response event.
651  * @psoc: psoc object
652  * @obj: vdev object
653  * @arg: mlo link set active response
654  *
655  * Return: None
656  */
657 static void
658 mlo_link_set_active_resp_vdev_handler(struct wlan_objmgr_psoc *psoc,
659 				      void *obj, void *arg)
660 {
661 	struct mlo_link_set_active_req *req;
662 	struct wlan_objmgr_vdev *vdev = obj;
663 	struct mlo_link_set_active_resp *event = arg;
664 
665 	if (event->evt_handled)
666 		return;
667 	req = wlan_serialization_get_active_cmd(wlan_vdev_get_psoc(vdev),
668 						wlan_vdev_get_id(vdev),
669 						WLAN_SER_CMD_SET_MLO_LINK);
670 	if (!req)
671 		return;
672 
673 	if (req->ctx.set_mlo_link_cb)
674 		req->ctx.set_mlo_link_cb(vdev, req->ctx.cb_arg, event);
675 
676 	mlo_release_ser_link_set_active_cmd(vdev);
677 	event->evt_handled = true;
678 }
679 
680 QDF_STATUS
681 mlo_process_link_set_active_resp(struct wlan_objmgr_psoc *psoc,
682 				 struct mlo_link_set_active_resp *event)
683 {
684 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
685 				     mlo_link_set_active_resp_vdev_handler,
686 				     event, true, WLAN_MLO_MGR_ID);
687 	if (!event->evt_handled)
688 		mlo_debug("link set resp evt not handled");
689 
690 	return QDF_STATUS_SUCCESS;
691 }
692 
693 /**
694  * mlo_ser_set_link_cb() - Serialization callback function
695  * @cmd: Serialization command info
696  * @reason: Serialization reason for callback execution
697  *
698  * Return: Status of callback execution
699  */
700 static QDF_STATUS
701 mlo_ser_set_link_cb(struct wlan_serialization_command *cmd,
702 		    enum wlan_serialization_cb_reason reason)
703 {
704 	QDF_STATUS status = QDF_STATUS_SUCCESS;
705 	struct wlan_objmgr_vdev *vdev;
706 	struct wlan_objmgr_psoc *psoc;
707 	struct mlo_link_set_active_req *req;
708 	struct mlo_mgr_context *mlo_ctx;
709 
710 	if (!cmd || !cmd->vdev)
711 		return QDF_STATUS_E_FAILURE;
712 
713 	mlo_ctx = wlan_objmgr_get_mlo_ctx();
714 	if (!mlo_ctx)
715 		return QDF_STATUS_E_FAILURE;
716 
717 	psoc = wlan_vdev_get_psoc(cmd->vdev);
718 	if (!psoc) {
719 		mlo_err("psoc is NULL, reason: %d", reason);
720 		return QDF_STATUS_E_NULL_VALUE;
721 	}
722 
723 	req = cmd->umac_cmd;
724 	if (!req)
725 		return QDF_STATUS_E_INVAL;
726 
727 	vdev = cmd->vdev;
728 	switch (reason) {
729 	case WLAN_SER_CB_ACTIVATE_CMD:
730 		status = mlo_link_set_active(psoc, req);
731 		break;
732 	case WLAN_SER_CB_CANCEL_CMD:
733 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
734 		mlo_err("vdev %d command not execute: %d",
735 			wlan_vdev_get_id(vdev), reason);
736 		if (req->ctx.set_mlo_link_cb)
737 			req->ctx.set_mlo_link_cb(vdev, req->ctx.cb_arg, NULL);
738 		break;
739 	case WLAN_SER_CB_RELEASE_MEM_CMD:
740 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
741 		qdf_mem_free(req);
742 		break;
743 	default:
744 		QDF_ASSERT(0);
745 		status = QDF_STATUS_E_INVAL;
746 		break;
747 	}
748 
749 	return status;
750 }
751 
752 #define MLO_SER_CMD_TIMEOUT_MS 5000
753 QDF_STATUS mlo_ser_set_link_req(struct mlo_link_set_active_req *req)
754 {
755 	struct wlan_serialization_command cmd = {0, };
756 	enum wlan_serialization_status ser_cmd_status;
757 	QDF_STATUS status;
758 	struct wlan_objmgr_vdev *vdev;
759 
760 	if (!req)
761 		return QDF_STATUS_E_INVAL;
762 
763 	vdev = req->ctx.vdev;
764 	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_MLO_MGR_ID);
765 	if (QDF_IS_STATUS_ERROR(status)) {
766 		mlo_err("vdev %d unable to get reference",
767 			wlan_vdev_get_id(vdev));
768 		return status;
769 	}
770 
771 	cmd.cmd_type = WLAN_SER_CMD_SET_MLO_LINK;
772 	cmd.cmd_id = 0;
773 	cmd.cmd_cb = mlo_ser_set_link_cb;
774 	cmd.source = WLAN_UMAC_COMP_MLO_MGR;
775 	cmd.is_high_priority = false;
776 	cmd.cmd_timeout_duration = MLO_SER_CMD_TIMEOUT_MS;
777 	cmd.vdev = vdev;
778 	cmd.is_blocking = true;
779 	cmd.umac_cmd = (void *)req;
780 
781 	ser_cmd_status = wlan_serialization_request(&cmd);
782 	switch (ser_cmd_status) {
783 	case WLAN_SER_CMD_PENDING:
784 		/* command moved to pending list.Do nothing */
785 		break;
786 	case WLAN_SER_CMD_ACTIVE:
787 		/* command moved to active list. Do nothing */
788 		break;
789 	default:
790 		mlo_err("vdev %d ser cmd status %d",
791 			wlan_vdev_get_id(vdev), ser_cmd_status);
792 		status = QDF_STATUS_E_FAILURE;
793 	}
794 
795 	if (QDF_IS_STATUS_SUCCESS(status))
796 		return status;
797 
798 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
799 
800 	return status;
801 }
802 
803 void mlo_mlme_handle_sta_csa_param(struct wlan_objmgr_vdev *vdev,
804 				   struct csa_offload_params *csa_param)
805 {
806 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
807 
808 	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
809 	    !mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param)
810 		return;
811 
812 	mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param(vdev, csa_param);
813 }
814 
815 QDF_STATUS
816 mlo_get_mlstats_vdev_params(struct wlan_objmgr_psoc *psoc,
817 			    struct mlo_stats_vdev_params *info,
818 			    uint8_t vdev_id)
819 {
820 	struct wlan_objmgr_vdev *ml_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0};
821 	struct wlan_objmgr_vdev *vdev;
822 	int i;
823 	uint16_t ml_vdev_cnt = 0;
824 
825 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
826 						    WLAN_MLO_MGR_ID);
827 	if (!vdev) {
828 		mlo_err("vdev object is NULL for vdev %d", vdev_id);
829 		return QDF_STATUS_E_INVAL;
830 	}
831 
832 	mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, ml_vdev_list);
833 	for (i = 0; i < ml_vdev_cnt; i++) {
834 		info->ml_vdev_id[i] = wlan_vdev_get_id(ml_vdev_list[i]);
835 		mlo_release_vdev_ref(ml_vdev_list[i]);
836 	}
837 	info->ml_vdev_count = ml_vdev_cnt;
838 	mlo_release_vdev_ref(vdev);
839 
840 	return QDF_STATUS_SUCCESS;
841 }
842 
843 static void ml_extract_link_state(struct wlan_objmgr_psoc *psoc,
844 				  struct ml_link_state_info_event *event)
845 {
846 	QDF_STATUS status;
847 	get_ml_link_state_cb resp_cb = NULL;
848 	void *context = NULL;
849 	uint8_t vdev_id;
850 
851 	vdev_id = event->vdev_id;
852 
853 	status = mlo_get_link_state_context(psoc,
854 					    &resp_cb, &context, vdev_id);
855 
856 	if (QDF_IS_STATUS_ERROR(status))
857 		return;
858 
859 	if (resp_cb)
860 		resp_cb(event, context);
861 }
862 
863 QDF_STATUS
864 wlan_handle_ml_link_state_info_event(struct wlan_objmgr_psoc *psoc,
865 				     struct ml_link_state_info_event *event)
866 {
867 	if (!event)
868 		return QDF_STATUS_E_NULL_VALUE;
869 
870 	ml_extract_link_state(psoc, event);
871 
872 	return QDF_STATUS_SUCCESS;
873 }
874 
875 static QDF_STATUS ml_get_link_state_req_cb(struct scheduler_msg *msg)
876 {
877 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
878 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
879 	struct mlo_link_state_cmd_params cmd = {0};
880 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
881 	struct wlan_objmgr_psoc *psoc;
882 	int status = 0;
883 
884 	if (!vdev) {
885 		mlo_err("null input vdev");
886 		return QDF_STATUS_E_INVAL;
887 	}
888 
889 	psoc = wlan_vdev_get_psoc(vdev);
890 
891 	if (!psoc) {
892 		mlo_err("null psoc");
893 		return QDF_STATUS_E_NULL_VALUE;
894 	}
895 
896 	mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
897 
898 	if (!mlo_tx_ops) {
899 		mlo_err("tx_ops is null!");
900 		return QDF_STATUS_E_NULL_VALUE;
901 	}
902 
903 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
904 		mlo_err("vdev is not MLO vdev");
905 		return status;
906 	}
907 
908 	mlo_dev_ctx = vdev->mlo_dev_ctx;
909 	cmd.vdev_id = vdev->vdev_objmgr.vdev_id;
910 	qdf_mem_copy(&cmd.mld_mac[0], &mlo_dev_ctx->mld_addr,
911 		     QDF_MAC_ADDR_SIZE);
912 
913 	if (!mlo_tx_ops->request_link_state_info_cmd) {
914 		mlo_err("handler is not registered");
915 		return QDF_STATUS_E_NULL_VALUE;
916 	}
917 
918 	status = mlo_tx_ops->request_link_state_info_cmd(psoc, &cmd);
919 
920 	if (QDF_IS_STATUS_ERROR(status))
921 		mlo_err("failed to send ml link info command to FW");
922 
923 	return QDF_STATUS_SUCCESS;
924 }
925 
926 QDF_STATUS
927 mlo_get_link_state_register_resp_cb(struct wlan_objmgr_vdev *vdev,
928 				    struct ml_link_state_cmd_info *req)
929 {
930 	struct wlan_mlo_dev_context *mlo_ctx;
931 	struct wlan_mlo_sta *sta_ctx = NULL;
932 
933 	if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev))
934 		return QDF_STATUS_E_NULL_VALUE;
935 	mlo_ctx = vdev->mlo_dev_ctx;
936 
937 	if (!mlo_ctx) {
938 		mlo_err("null mlo_dev_ctx");
939 		return QDF_STATUS_E_NULL_VALUE;
940 	}
941 
942 	sta_ctx = mlo_ctx->sta_ctx;
943 
944 	if (!sta_ctx)
945 		return QDF_STATUS_E_INVAL;
946 
947 	mlo_dev_lock_acquire(mlo_ctx);
948 
949 	sta_ctx->ml_link_state.ml_link_state_resp_cb =
950 		req->ml_link_state_resp_cb;
951 	sta_ctx->ml_link_state.ml_link_state_req_context =
952 		req->request_cookie;
953 	mlo_dev_lock_release(mlo_ctx);
954 
955 	return QDF_STATUS_SUCCESS;
956 }
957 
958 static QDF_STATUS ml_get_link_state_req_flush_cb(struct scheduler_msg *msg)
959 {
960 	mlo_debug("ml_get_link_state_req flush callback");
961 	return QDF_STATUS_SUCCESS;
962 }
963 
964 QDF_STATUS ml_post_get_link_state_msg(struct wlan_objmgr_vdev *vdev)
965 {
966 	struct scheduler_msg msg = {0};
967 	QDF_STATUS qdf_status = 0;
968 
969 	msg.bodyptr = vdev;
970 	msg.callback = ml_get_link_state_req_cb;
971 	msg.flush_callback = ml_get_link_state_req_flush_cb;
972 
973 	qdf_status = scheduler_post_message(
974 				QDF_MODULE_ID_OS_IF,
975 				QDF_MODULE_ID_MLME,
976 				QDF_MODULE_ID_OS_IF,
977 				&msg);
978 	return qdf_status;
979 }
980 
981 bool
982 wlan_mlo_is_csa_allow(struct wlan_objmgr_vdev *vdev, uint16_t csa_freq)
983 {
984 	struct wlan_channel *chan;
985 	struct wlan_objmgr_vdev *ml_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0};
986 	uint16_t ml_vdev_cnt = 0;
987 	struct wlan_objmgr_vdev *t_vdev;
988 	int i;
989 	bool is_allow = true;
990 
991 	if (!vdev) {
992 		mlo_err("vdev is NULL");
993 		return false;
994 	}
995 
996 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
997 		return true;
998 
999 	mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, ml_vdev_list);
1000 	for (i = 0; i < ml_vdev_cnt; i++) {
1001 		t_vdev = ml_vdev_list[i];
1002 		if (t_vdev == vdev)
1003 			goto next;
1004 		chan = wlan_vdev_get_active_channel(t_vdev);
1005 		if (!chan)
1006 			goto next;
1007 
1008 		if (csa_freq == chan->ch_freq) {
1009 			mlo_err("vdev %d will SCC with vdev %d on freq %d",
1010 				wlan_vdev_get_id(vdev),
1011 				wlan_vdev_get_id(t_vdev), csa_freq);
1012 			is_allow = false;
1013 		}
1014 next:
1015 		mlo_release_vdev_ref(t_vdev);
1016 	}
1017 
1018 	return is_allow;
1019 }
1020 
1021