xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_sta.c (revision 37e5a76c071036a1241bb7b07453cabad477452b)
1 /*
2  * Copyright (c) 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 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 STA related api's
20  */
21 
22 #include <wlan_cmn.h>
23 #include <wlan_mlo_mgr_sta.h>
24 #include <wlan_cm_public_struct.h>
25 #include <wlan_mlo_mgr_main.h>
26 #include <wlan_cm_api.h>
27 #include <wlan_mlo_mgr_cmn.h>
28 #include <wlan_scan_api.h>
29 #include <scheduler_api.h>
30 #include <wlan_crypto_global_api.h>
31 #include <utils_mlo.h>
32 #include <wlan_mlme_cmn.h>
33 #include <wlan_scan_utils_api.h>
34 #include <qdf_time.h>
35 #include <wlan_objmgr_peer_obj.h>
36 #include <wlan_scan_api.h>
37 #include <wlan_mlo_mgr_peer.h>
38 #include <qdf_module.h>
39 #include <wlan_mlo_mgr_public_api.h>
40 
41 #ifdef WLAN_FEATURE_11BE_MLO
42 static QDF_STATUS mlo_disconnect_req(struct wlan_objmgr_vdev *vdev,
43 				     enum wlan_cm_source source,
44 				     enum wlan_reason_code reason_code,
45 				     struct qdf_mac_addr *bssid,
46 				     bool validate_req);
47 
48 void
49 mlo_allocate_and_copy_ies(struct wlan_cm_connect_req *target,
50 			  struct wlan_cm_connect_req *source)
51 {
52 	target->assoc_ie.ptr = NULL;
53 	target->scan_ie.ptr = NULL;
54 	target->crypto.wep_keys.key = NULL;
55 	target->crypto.wep_keys.seq = NULL;
56 	target->crypto.wep_keys.key_len = 0;
57 	target->crypto.wep_keys.seq_len = 0;
58 
59 	if (source->scan_ie.ptr) {
60 		target->scan_ie.ptr = qdf_mem_malloc(source->scan_ie.len);
61 		if (!target->scan_ie.ptr)
62 			target->scan_ie.len = 0;
63 		else
64 			qdf_mem_copy(target->scan_ie.ptr,
65 				     source->scan_ie.ptr, source->scan_ie.len);
66 	}
67 
68 	if (source->assoc_ie.ptr) {
69 		target->assoc_ie.ptr = qdf_mem_malloc(source->assoc_ie.len);
70 		if (!target->assoc_ie.ptr)
71 			target->assoc_ie.len = 0;
72 		else
73 			qdf_mem_copy(target->assoc_ie.ptr, source->assoc_ie.ptr,
74 				     source->assoc_ie.len);
75 	}
76 }
77 
78 /*
79  * mlo_get_tdls_link_vdev() - API to get tdls link vdev
80  * @mlo_dev_ctx: pointer to mlo dev context
81  *
82  * Return: MLD tdls link vdev
83  */
84 static inline struct wlan_objmgr_vdev *
85 mlo_get_tdls_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx)
86 {
87 	uint8_t i = 0;
88 
89 	if (!mlo_dev_ctx)
90 		return NULL;
91 
92 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
93 		if (!mlo_dev_ctx->wlan_vdev_list[i])
94 			continue;
95 
96 		if (wlan_vdev_mlme_is_tdls_vdev(mlo_dev_ctx->wlan_vdev_list[i]))
97 			return mlo_dev_ctx->wlan_vdev_list[i];
98 	}
99 	return NULL;
100 }
101 
102 struct wlan_objmgr_vdev *
103 wlan_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev)
104 {
105 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
106 
107 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
108 		return NULL;
109 
110 	return mlo_get_tdls_link_vdev(mlo_dev_ctx);
111 }
112 
113 /*
114  * mlo_get_assoc_link_vdev - API to get assoc link vdev
115  *
116  * @mlo_dev_ctx: pointer to mlo dev context
117  *
118  * Return: MLD assoc link vdev
119  */
120 static inline struct wlan_objmgr_vdev *
121 mlo_get_assoc_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx)
122 {
123 	uint8_t i = 0;
124 
125 	if (!mlo_dev_ctx)
126 		return NULL;
127 
128 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
129 		if (!mlo_dev_ctx->wlan_vdev_list[i])
130 			continue;
131 
132 		if (wlan_vdev_mlme_is_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]) &&
133 		    !wlan_vdev_mlme_is_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i]))
134 			return mlo_dev_ctx->wlan_vdev_list[i];
135 	}
136 	return NULL;
137 }
138 
139 struct wlan_objmgr_vdev *
140 wlan_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev)
141 {
142 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
143 
144 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
145 		return NULL;
146 
147 	return mlo_get_assoc_link_vdev(mlo_dev_ctx);
148 }
149 
150 struct wlan_objmgr_vdev *
151 ucfg_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev)
152 {
153 	return wlan_mlo_get_assoc_link_vdev(vdev);
154 }
155 
156 /**
157  * mlo_is_mld_disconnected - Check whether MLD is disconnected
158  *
159  * @vdev: pointer to vdev
160  *
161  * Return: true if mld is disconnected, false otherwise
162  */
163 static inline
164 bool mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev)
165 {
166 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
167 	uint8_t i = 0;
168 
169 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
170 		return true;
171 
172 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
173 		if (!mlo_dev_ctx->wlan_vdev_list[i])
174 			continue;
175 
176 		if (!wlan_cm_is_vdev_disconnected(mlo_dev_ctx->wlan_vdev_list[i]))
177 			return false;
178 	}
179 	return true;
180 }
181 
182 bool mlo_is_mld_disconnecting_connecting(struct wlan_objmgr_vdev *vdev)
183 {
184 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
185 	uint8_t i = 0;
186 
187 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
188 		return false;
189 
190 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
191 		if (!mlo_dev_ctx->wlan_vdev_list[i])
192 			continue;
193 		if (wlan_cm_is_vdev_disconnecting(mlo_dev_ctx->wlan_vdev_list[i]) ||
194 		    wlan_cm_is_vdev_connecting(mlo_dev_ctx->wlan_vdev_list[i]))
195 			return true;
196 	}
197 	return false;
198 }
199 
200 bool mlo_is_ml_connection_in_progress(struct wlan_objmgr_psoc *psoc,
201 				      uint8_t vdev_id)
202 {
203 	struct wlan_objmgr_vdev *vdev;
204 	struct wlan_mlo_dev_context *mlo_dev_ctx;
205 	uint8_t i = 0;
206 	bool val = false;
207 
208 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
209 						    WLAN_MLO_MGR_ID);
210 
211 	if (!vdev) {
212 		mlo_err("Invalid vdev");
213 		return false;
214 	}
215 
216 	mlo_dev_ctx = vdev->mlo_dev_ctx;
217 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
218 		goto end;
219 
220 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
221 		if (!mlo_dev_ctx->wlan_vdev_list[i])
222 			continue;
223 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
224 			if (!wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) {
225 				val = true;
226 				goto end;
227 			}
228 		}
229 	}
230 
231 end:
232 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
233 	return val;
234 }
235 
236 bool ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev)
237 {
238 	return mlo_is_mld_disconnected(vdev);
239 }
240 
241 /**
242  * mlo_send_link_disconnect- Issue the disconnect request on MLD links
243  *
244  * @vdev: pointer to vdev
245  * @source: disconnect source
246  * @reason_code: disconnect reason
247  * @bssid: bssid of AP to disconnect, can be null if not known
248  *
249  * Return: QDF_STATUS
250  */
251 static QDF_STATUS
252 mlo_send_link_disconnect(struct wlan_objmgr_vdev *vdev,
253 			 enum wlan_cm_source source,
254 			 enum wlan_reason_code reason_code,
255 			 struct qdf_mac_addr *bssid)
256 {
257 	uint8_t i = 0;
258 	enum wlan_cm_source link_source = source;
259 	struct wlan_objmgr_vdev *assoc_vdev =
260 			mlo_get_assoc_link_vdev(vdev->mlo_dev_ctx);
261 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
262 	uint16_t vdev_count = 0;
263 	struct wlan_mlo_sta *sta_ctx = NULL;
264 
265 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
266 	if (!sta_ctx) {
267 		mlo_err("Invalid sta_ctx");
268 		return QDF_STATUS_E_FAILURE;
269 	}
270 
271 	if (!assoc_vdev && mlo_mgr_is_link_switch_supported(vdev)) {
272 		if (!wlan_mlo_mgr_is_link_switch_on_assoc_vdev(vdev))
273 			return QDF_STATUS_E_FAILURE;
274 
275 		assoc_vdev = wlan_mlo_mgr_link_switch_get_assoc_vdev(vdev);
276 		mlo_release_vdev_ref(assoc_vdev);
277 	}
278 
279 	/*
280 	 * Change the source for the link vdev to make sure it's handled as a
281 	 * Northbound disconnect in VDEV/PEER state machine.
282 	 */
283 	if (source != CM_OSIF_DISCONNECT)
284 		link_source = CM_MLO_LINK_VDEV_DISCONNECT;
285 
286 	mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
287 	for (i =  0; i < vdev_count; i++) {
288 		if ((wlan_vdev_list[i] != assoc_vdev) &&
289 		    (qdf_test_bit(i, sta_ctx->wlan_connected_links) ||
290 		    (wlan_cm_is_vdev_connected(wlan_vdev_list[i]) &&
291 		    !wlan_peer_is_mlo(wlan_vdev_get_bsspeer(wlan_vdev_list[i])))))
292 			wlan_cm_disconnect(wlan_vdev_list[i],
293 					   link_source, reason_code,
294 					   NULL);
295 		mlo_release_vdev_ref(wlan_vdev_list[i]);
296 	}
297 
298 	if (assoc_vdev)
299 		wlan_cm_disconnect(assoc_vdev, source, reason_code, NULL);
300 
301 	return QDF_STATUS_SUCCESS;
302 }
303 
304 static void mlo_free_copied_conn_req(struct wlan_mlo_sta *sta_ctx)
305 {
306 	if (sta_ctx) {
307 		mlo_debug("enter");
308 		copied_conn_req_lock_acquire(sta_ctx);
309 		if (sta_ctx->copied_conn_req) {
310 			wlan_cm_free_connect_req(sta_ctx->copied_conn_req);
311 			sta_ctx->copied_conn_req = NULL;
312 		}
313 		copied_conn_req_lock_release(sta_ctx);
314 	}
315 }
316 
317 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
318 static QDF_STATUS
319 mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev,
320 			 struct wlan_mlo_dev_context *mlo_dev_ctx,
321 			 struct wlan_cm_connect_req *req)
322 {
323 /* check back to back connect handling */
324 	return QDF_STATUS_SUCCESS;
325 }
326 
327 static QDF_STATUS
328 mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev,
329 			 enum wlan_cm_source source,
330 			 enum wlan_reason_code reason_code,
331 			 struct qdf_mac_addr *bssid)
332 {
333 	return QDF_STATUS_SUCCESS;
334 }
335 
336 static QDF_STATUS mlo_validate_mlo_cap(struct wlan_objmgr_vdev *vdev)
337 {
338 	return QDF_STATUS_SUCCESS;
339 }
340 
341 static inline
342 void mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
343 { }
344 #else
345 /**
346  * mlo_is_mld_connected - Check whether MLD is connected
347  *
348  * @vdev: pointer to vdev
349  *
350  * Return: true if mld is connected, false otherwise
351  */
352 static inline
353 bool mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev)
354 {
355 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
356 	uint8_t i = 0;
357 
358 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
359 		return true;
360 
361 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
362 		if (!mlo_dev_ctx->wlan_vdev_list[i])
363 			continue;
364 
365 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
366 			if (!wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i]))
367 				return false;
368 		}
369 	}
370 	return true;
371 }
372 
373 bool ucfg_mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev)
374 {
375 	return mlo_is_mld_connected(vdev);
376 }
377 
378 static inline
379 void mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
380 {
381 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
382 	uint8_t i = 0;
383 
384 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
385 		return;
386 
387 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
388 		if (!mlo_dev_ctx->wlan_vdev_list[i])
389 			continue;
390 		wlan_vdev_mlme_clear_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]);
391 		wlan_vdev_mlme_clear_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i]);
392 	}
393 	mlo_clear_bridge_sta_ctx(vdev);
394 }
395 
396 void ucfg_mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
397 {
398 	mlo_mld_clear_mlo_cap(vdev);
399 }
400 
401 static void
402 mlo_cm_handle_connect_in_disconnection_state(struct wlan_objmgr_vdev *vdev,
403 					     struct wlan_cm_connect_req *req)
404 {
405 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
406 	struct wlan_mlo_sta *sta_ctx;
407 
408 	if (!mlo_dev_ctx) {
409 		mlo_err("ML dev ctx is NULL");
410 		return;
411 	}
412 
413 	sta_ctx = mlo_dev_ctx->sta_ctx;
414 	if (!sta_ctx->connect_req)
415 		sta_ctx->connect_req = qdf_mem_malloc(
416 					sizeof(struct wlan_cm_connect_req));
417 
418 	if (sta_ctx->connect_req) {
419 		qdf_mem_copy(sta_ctx->connect_req, req,
420 			     sizeof(struct wlan_cm_connect_req));
421 		mlo_allocate_and_copy_ies(sta_ctx->connect_req, req);
422 	} else {
423 		mlo_err("Failed to allocate connect req");
424 	}
425 }
426 
427 static QDF_STATUS
428 mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev,
429 			 enum wlan_cm_source source,
430 			 enum wlan_reason_code reason_code,
431 			 struct qdf_mac_addr *bssid)
432 {
433 	struct wlan_mlo_dev_context *mlo_dev = vdev->mlo_dev_ctx;
434 	struct wlan_mlo_sta *sta_ctx = mlo_dev->sta_ctx;
435 	uint8_t i = 0;
436 
437 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
438 		if (!mlo_dev->wlan_vdev_list[i])
439 			continue;
440 
441 		if (wlan_cm_is_vdev_connecting(mlo_dev->wlan_vdev_list[i])) {
442 			if (!wlan_vdev_mlme_is_mlo_link_vdev(
443 						mlo_dev->wlan_vdev_list[i]))
444 				return QDF_STATUS_SUCCESS;
445 
446 			if (!sta_ctx->disconn_req)
447 				sta_ctx->disconn_req =
448 					qdf_mem_malloc(
449 					sizeof(struct wlan_cm_disconnect_req));
450 
451 			if (!sta_ctx->disconn_req)
452 				return QDF_STATUS_SUCCESS;
453 
454 			sta_ctx->disconn_req->vdev_id =
455 						wlan_vdev_get_id(vdev);
456 			sta_ctx->disconn_req->source = source;
457 			sta_ctx->disconn_req->reason_code = reason_code;
458 			if (bssid)
459 				qdf_copy_macaddr(&sta_ctx->disconn_req->bssid,
460 						 bssid);
461 			return QDF_STATUS_E_BUSY;
462 		} else if (wlan_cm_is_vdev_connected(mlo_dev->wlan_vdev_list[i]) &&
463 			   !wlan_vdev_mlme_is_mlo_link_vdev(
464 				mlo_dev->wlan_vdev_list[i]) &&
465 			   wlan_peer_is_mlo(wlan_vdev_get_bsspeer(
466 						mlo_dev->wlan_vdev_list[i]))) {
467 				/* If the vdev is moved to connected state but
468 				 * MLO mgr is not yet notified, defer disconnect
469 				 * as it can cause race between connect complete
470 				 * and disconnect initiation
471 				 */
472 			if (!qdf_test_bit(i, sta_ctx->wlan_connected_links)) {
473 				if (!sta_ctx->disconn_req)
474 					sta_ctx->disconn_req =
475 						qdf_mem_malloc(
476 						sizeof(struct wlan_cm_disconnect_req));
477 
478 				if (!sta_ctx->disconn_req)
479 					return QDF_STATUS_SUCCESS;
480 
481 				sta_ctx->disconn_req->vdev_id =
482 					wlan_vdev_get_id(vdev);
483 				sta_ctx->disconn_req->source = source;
484 				sta_ctx->disconn_req->reason_code = reason_code;
485 				if (bssid)
486 					qdf_copy_macaddr(&sta_ctx->disconn_req->bssid,
487 							 bssid);
488 
489 				return QDF_STATUS_E_BUSY;
490 			}
491 		}
492 	}
493 	return QDF_STATUS_SUCCESS;
494 }
495 
496 static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
497 					 enum wlan_cm_source source,
498 					 enum wlan_reason_code reason_code,
499 					 struct qdf_mac_addr *bssid)
500 {
501 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
502 	struct wlan_mlo_sta *sta_ctx = NULL;
503 	QDF_STATUS status = QDF_STATUS_SUCCESS;
504 	struct wlan_objmgr_vdev *assoc_vdev = NULL;
505 	uint8_t i = 0;
506 
507 	if (mlo_dev_ctx)
508 		sta_ctx = mlo_dev_ctx->sta_ctx;
509 	if (sta_ctx) {
510 		mlo_free_copied_conn_req(sta_ctx);
511 	} else {
512 		return QDF_STATUS_E_FAILURE;
513 	}
514 
515 	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
516 		sta_ctx = mlo_dev_ctx->sta_ctx;
517 		if (!sta_ctx)
518 			return QDF_STATUS_E_FAILURE;
519 
520 		assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
521 
522 		if (sta_ctx->connect_req) {
523 			wlan_cm_free_connect_req(sta_ctx->connect_req);
524 			sta_ctx->connect_req = NULL;
525 		}
526 
527 		status = mlo_validate_disconn_req(vdev, source,
528 						  reason_code, bssid);
529 		if (QDF_IS_STATUS_ERROR(status)) {
530 			mlo_err("Connect in progress, deferring disconnect");
531 			return status;
532 		}
533 
534 		for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
535 			if (!mlo_dev_ctx->wlan_vdev_list[i])
536 				continue;
537 
538 			if ((mlo_dev_ctx->wlan_vdev_list[i] != assoc_vdev) &&
539 			    (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links) ||
540 			    (wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i]) &&
541 			     !wlan_peer_is_mlo(wlan_vdev_get_bsspeer(mlo_dev_ctx->wlan_vdev_list[i])))))
542 				wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
543 						   source, reason_code,
544 						   NULL);
545 		}
546 
547 		if (assoc_vdev)
548 			wlan_cm_disconnect(assoc_vdev, source,
549 					   reason_code, NULL);
550 	}
551 
552 	return status;
553 }
554 
555 static void
556 mlo_cm_handle_connect_in_connection_state(struct wlan_objmgr_vdev *vdev,
557 					  struct wlan_cm_connect_req *req)
558 {
559 	mlo_disconnect_no_lock(vdev, CM_INTERNAL_DISCONNECT,
560 			       REASON_UNSPEC_FAILURE, NULL);
561 	mlo_cm_handle_connect_in_disconnection_state(vdev, req);
562 }
563 
564 static QDF_STATUS
565 mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev,
566 			 struct wlan_mlo_dev_context *mlo_dev_ctx,
567 			 struct wlan_cm_connect_req *req)
568 {
569 	uint8_t i = 0;
570 	QDF_STATUS status = QDF_STATUS_SUCCESS;
571 
572 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
573 		return QDF_STATUS_SUCCESS;
574 
575 	// Handle connect in various states
576 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
577 		if (!mlo_dev_ctx->wlan_vdev_list[i])
578 			continue;
579 
580 		if ((wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) ||
581 		    (wlan_cm_is_vdev_connecting(mlo_dev_ctx->wlan_vdev_list[i])) ||
582 		    (wlan_cm_is_vdev_roaming(mlo_dev_ctx->wlan_vdev_list[i]))) {
583 			mlo_cm_handle_connect_in_connection_state(mlo_dev_ctx->wlan_vdev_list[i], req);
584 			return QDF_STATUS_E_BUSY;
585 		} else if (wlan_cm_is_vdev_disconnecting(mlo_dev_ctx->wlan_vdev_list[i])) {
586 			mlo_cm_handle_connect_in_disconnection_state(mlo_dev_ctx->wlan_vdev_list[i], req);
587 			return QDF_STATUS_E_BUSY;
588 		}
589 
590 		/*
591 		 * mlo_connect: update wlan_connect_req_links in
592 		 * wlan_cfg80211_conect on osif_cm_connect,
593 		 * Validate pre checks for connection
594 		 */
595 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connect_req_links)) {
596 			status = mlo_mlme_validate_conn_req(
597 					mlo_dev_ctx->wlan_vdev_list[i], NULL);
598 			if (status != QDF_STATUS_SUCCESS)
599 				return status;
600 			/*
601 			 * clone security params in all partner sta vaps
602 			 */
603 			mlo_mlme_clone_sta_security(
604 				mlo_dev_ctx->wlan_vdev_list[i], req);
605 		}
606 	}
607 	return status;
608 }
609 
610 static QDF_STATUS mlo_validate_mlo_cap(struct wlan_objmgr_vdev *vdev)
611 {
612 	if (wlan_vdev_mlme_is_mlo_vdev(vdev))
613 		return QDF_STATUS_SUCCESS;
614 
615 	return QDF_STATUS_E_FAILURE;
616 }
617 #endif
618 
619 QDF_STATUS mlo_set_cu_bpcc(struct wlan_objmgr_vdev *vdev,
620 			   uint8_t vdev_id, uint8_t bpcc)
621 {
622 	struct wlan_mlo_dev_context *mlo_dev_ctx;
623 	struct mlo_sta_cu_params *cu_param;
624 	uint8_t i;
625 
626 	mlo_dev_ctx = vdev->mlo_dev_ctx;
627 	if (!mlo_dev_ctx) {
628 		mlo_err("ML dev ctx is NULL");
629 		return QDF_STATUS_E_INVAL;
630 	}
631 
632 	cu_param = &mlo_dev_ctx->sta_ctx->mlo_cu_param[0];
633 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
634 		if (cu_param[i].initialized && cu_param[i].vdev_id == vdev_id) {
635 			cu_param[i].bpcc = bpcc;
636 			return QDF_STATUS_SUCCESS;
637 		}
638 	}
639 
640 	return QDF_STATUS_E_INVAL;
641 }
642 
643 QDF_STATUS mlo_get_cu_bpcc(struct wlan_objmgr_vdev *vdev,
644 			   uint8_t vdev_id, uint8_t *bpcc)
645 {
646 	struct wlan_mlo_dev_context *mlo_dev_ctx;
647 	struct mlo_sta_cu_params *cu_param;
648 	uint8_t i;
649 
650 	mlo_dev_ctx = vdev->mlo_dev_ctx;
651 	if (!mlo_dev_ctx) {
652 		mlo_err("ML dev ctx is NULL");
653 		return QDF_STATUS_E_INVAL;
654 	}
655 
656 	cu_param = &mlo_dev_ctx->sta_ctx->mlo_cu_param[0];
657 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
658 		if (cu_param[i].initialized &&
659 		    cu_param[i].vdev_id == vdev_id) {
660 			*bpcc = cu_param[i].bpcc;
661 			return QDF_STATUS_SUCCESS;
662 		}
663 	}
664 
665 	return QDF_STATUS_E_INVAL;
666 }
667 
668 void mlo_init_cu_bpcc(struct wlan_mlo_dev_context *mlo_dev_ctx,
669 		      uint8_t vdev_id)
670 {
671 	uint8_t i;
672 	struct mlo_sta_cu_params *cu_param;
673 	uint8_t empty_slot = 0xff;
674 
675 	cu_param = &mlo_dev_ctx->sta_ctx->mlo_cu_param[0];
676 
677 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
678 		if (cu_param[i].initialized &&
679 		    cu_param[i].vdev_id == vdev_id) {
680 			cu_param[i].bpcc = 0;
681 			return;
682 		}
683 
684 		if (!cu_param[i].initialized && empty_slot == 0xff)
685 			empty_slot = i;
686 	}
687 
688 	if (empty_slot != 0xff) {
689 		cu_param[empty_slot].bpcc = 0;
690 		cu_param[empty_slot].vdev_id = vdev_id;
691 		cu_param[empty_slot].initialized = true;
692 		mlo_debug("init cu bpcc idx %d, vdev_id %d",
693 			  empty_slot, vdev_id);
694 	} else {
695 		mlo_debug("No bpcc idx for vdev_id %d", vdev_id);
696 	}
697 }
698 
699 void mlo_clear_cu_bpcc(struct wlan_objmgr_vdev *vdev)
700 {
701 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
702 	struct wlan_mlo_sta *sta_ctx = NULL;
703 	uint32_t size;
704 
705 	if (!vdev)
706 		return;
707 
708 	mlo_dev_ctx = vdev->mlo_dev_ctx;
709 	if (!mlo_dev_ctx)
710 		return;
711 
712 	sta_ctx = mlo_dev_ctx->sta_ctx;
713 	if (!sta_ctx)
714 		return;
715 
716 	size = sizeof(sta_ctx->mlo_cu_param);
717 	qdf_mem_zero(sta_ctx->mlo_cu_param, size);
718 }
719 
720 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
721 static void mlo_clear_sta_key_mgmt(struct wlan_objmgr_vdev *vdev)
722 {
723 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
724 	struct wlan_mlo_sta *sta_ctx = NULL;
725 
726 	if (!vdev)
727 		return;
728 
729 	mlo_dev_ctx = vdev->mlo_dev_ctx;
730 	if (!mlo_dev_ctx)
731 		return;
732 
733 	sta_ctx = mlo_dev_ctx->sta_ctx;
734 	if (!sta_ctx)
735 		return;
736 
737 	qdf_mem_zero(sta_ctx->key_mgmt, sizeof(sta_ctx->key_mgmt));
738 
739 	mlo_debug("clear sta_key_mgmt");
740 }
741 
742 #else
743 static void mlo_clear_sta_key_mgmt(struct wlan_objmgr_vdev *vdev)
744 {
745 }
746 #endif
747 
748 QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev,
749 		       struct wlan_cm_connect_req *req)
750 {
751 	struct wlan_mlo_dev_context *mlo_dev_ctx;
752 	struct wlan_mlo_sta *sta_ctx = NULL;
753 	QDF_STATUS status = QDF_STATUS_SUCCESS;
754 
755 	mlo_dev_ctx = vdev->mlo_dev_ctx;
756 	if (mlo_dev_ctx)
757 		sta_ctx = mlo_dev_ctx->sta_ctx;
758 	if (sta_ctx) {
759 		status = mlo_validate_mlo_cap(vdev);
760 		if (QDF_IS_STATUS_ERROR(status))
761 			return wlan_cm_start_connect(vdev, req);
762 
763 		mlo_dev_lock_acquire(mlo_dev_ctx);
764 		status = mlo_validate_connect_req(vdev, mlo_dev_ctx, req);
765 		copied_conn_req_lock_acquire(sta_ctx);
766 		if (!sta_ctx->copied_conn_req)
767 			sta_ctx->copied_conn_req = qdf_mem_malloc(
768 					sizeof(struct wlan_cm_connect_req));
769 		else
770 			wlan_cm_free_connect_req_param(sta_ctx->copied_conn_req);
771 
772 		if (sta_ctx->copied_conn_req) {
773 			qdf_mem_copy(sta_ctx->copied_conn_req, req,
774 				     sizeof(struct wlan_cm_connect_req));
775 			mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req,
776 						  req);
777 			copied_conn_req_lock_release(sta_ctx);
778 		} else {
779 			mlo_err("Failed to allocate orig connect req");
780 			copied_conn_req_lock_release(sta_ctx);
781 			mlo_dev_lock_release(mlo_dev_ctx);
782 
783 			return QDF_STATUS_E_NOMEM;
784 		}
785 
786 		if (QDF_IS_STATUS_SUCCESS(status)) {
787 			mlo_clear_cu_bpcc(vdev);
788 			mlo_clear_connected_links_bmap(vdev);
789 			mlo_clear_sta_key_mgmt(vdev);
790 			mlo_dev_lock_release(mlo_dev_ctx);
791 
792 			status = wlan_cm_start_connect(vdev, req);
793 			if (QDF_IS_STATUS_ERROR(status))
794 				mlo_mld_clear_mlo_cap(vdev);
795 			return status;
796 		}
797 
798 		mlo_dev_lock_release(mlo_dev_ctx);
799 
800 		return status;
801 	}
802 
803 	return wlan_cm_start_connect(vdev, req);
804 }
805 
806 static inline void
807 mlo_update_connect_req_chan_info(struct wlan_cm_connect_req *req)
808 {
809 	req->chan_freq = 0;
810 	req->chan_freq_hint = 0;
811 }
812 
813 /**
814  * mlo_prepare_and_send_connect- Prepare and send the connect req
815  *
816  * @vdev: vdev pointer
817  * @ml_parnter_info: ml partner link info
818  * @link_info: link info on which connect req will be sent
819  * @ssid: ssid to connect
820  *
821  * Return: none
822  */
823 
824 static void
825 mlo_prepare_and_send_connect(struct wlan_objmgr_vdev *vdev,
826 			     struct mlo_partner_info ml_parnter_info,
827 			     struct mlo_link_info link_info,
828 			     struct wlan_ssid ssid)
829 {
830 	struct wlan_cm_connect_req req = {0};
831 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
832 	struct wlan_mlo_sta *sta_ctx;
833 
834 	if (!mlo_dev_ctx) {
835 		mlo_err("ML dev ctx is NULL");
836 		return;
837 	}
838 
839 	sta_ctx = mlo_dev_ctx->sta_ctx;
840 
841 	mlo_debug("Partner link connect mac:" QDF_MAC_ADDR_FMT
842 		  " bssid:" QDF_MAC_ADDR_FMT " vdev_id:%d",
843 		  QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
844 		  QDF_MAC_ADDR_REF(link_info.link_addr.bytes),
845 		  wlan_vdev_get_id(vdev));
846 
847 	if (sta_ctx->copied_conn_req)
848 		qdf_mem_copy(&req, sta_ctx->copied_conn_req,
849 			     sizeof(struct wlan_cm_connect_req));
850 	else
851 		mlo_err("Invalid copied_conn_req");
852 
853 	mlo_update_connect_req_chan_info(&req);
854 
855 	qdf_mem_copy(req.bssid.bytes,
856 		     link_info.link_addr.bytes,
857 		     QDF_MAC_ADDR_SIZE);
858 
859 	qdf_mem_copy(&req.ml_parnter_info,
860 		     &ml_parnter_info,
861 		     sizeof(struct mlo_partner_info));
862 
863 	req.ssid.length = ssid.length;
864 	qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length);
865 
866 	if (sta_ctx->copied_conn_req)
867 		mlo_allocate_and_copy_ies(&req, sta_ctx->copied_conn_req);
868 
869 	if (!req.assoc_ie.ptr)
870 		mlo_err("Failed to allocate assoc IEs");
871 
872 	if (!req.scan_ie.ptr)
873 		mlo_err("Failed to allocate scan IEs");
874 
875 	/* Reset crypto auth type for partner link.
876 	 * It will be set based on partner scan cache entry
877 	 */
878 	req.crypto.auth_type = 0;
879 
880 	wlan_cm_start_connect(vdev, &req);
881 	wlan_cm_free_connect_req_param(&req);
882 }
883 
884 /**
885  * mlo_send_link_connect- Create/Issue the connection on secondary link
886  *
887  * @vdev: vdev pointer
888  * @mlo_dev_ctx: ml dev context
889  * @assoc_rsp: assoc response
890  * @ml_parnter_info: ml partner link info
891  *
892  * Return: none
893  */
894 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
895 static void
896 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev,
897 		      struct wlan_mlo_dev_context *mlo_dev_ctx,
898 		      struct element_info *assoc_rsp,
899 		      struct mlo_partner_info *ml_parnter_info)
900 {
901 	/* Create the secondary interface, Send keys if the last link */
902 	uint8_t i, partner_idx = 0;
903 	struct wlan_ssid ssid = {0};
904 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
905 	uint16_t vdev_count = 0;
906 
907 	mlo_debug("Sending link connect on partner interface");
908 	wlan_vdev_mlme_get_ssid(
909 			vdev, ssid.ssid,
910 			&ssid.length);
911 
912 	if (!ml_parnter_info->num_partner_links) {
913 		mlo_err("No partner info in connect resp");
914 		return;
915 	}
916 
917 	if(wlan_vdev_mlme_is_mlo_link_vdev(vdev))
918 		return;
919 
920 	mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
921 	for (i = 0; i < vdev_count; i++) {
922 		if (wlan_vdev_list[i] == vdev) {
923 			mlo_release_vdev_ref(wlan_vdev_list[i]);
924 			continue;
925 		}
926 		wlan_vdev_mlme_set_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]);
927 		wlan_vdev_mlme_set_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i]);
928 		wlan_vdev_set_link_id(
929 		      wlan_vdev_list[i],
930 		      ml_parnter_info->partner_link_info[partner_idx].link_id);
931 		ml_parnter_info->partner_link_info[partner_idx].vdev_id =
932 			       wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
933 		wlan_crypto_free_vdev_key(wlan_vdev_list[i]);
934 		mlo_prepare_and_send_connect(
935 				wlan_vdev_list[i],
936 				*ml_parnter_info,
937 				ml_parnter_info->partner_link_info[partner_idx],
938 				ssid);
939 		mlo_update_connected_links(wlan_vdev_list[i], 1);
940 		partner_idx++;
941 		mlo_release_vdev_ref(wlan_vdev_list[i]);
942 	}
943 }
944 #else
945 static void
946 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev,
947 		      struct wlan_mlo_dev_context *mlo_dev_ctx,
948 		      struct element_info *assoc_rsp,
949 		      struct mlo_partner_info *ml_parnter_info)
950 {
951 	struct wlan_ssid ssid = {0};
952 	uint8_t i = 0;
953 	uint8_t j = 0;
954 
955 	if (!ml_parnter_info->num_partner_links) {
956 		mlo_err("No partner info in connect resp");
957 		return;
958 	}
959 
960 	mlo_dev_lock_acquire(mlo_dev_ctx);
961 	if (!wlan_cm_is_vdev_connected(vdev)) {
962 		mlo_dev_lock_release(mlo_dev_ctx);
963 		return;
964 	}
965 
966 	for (j = 0; j < ml_parnter_info->num_partner_links; j++) {
967 		for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
968 			if (!mlo_dev_ctx->wlan_vdev_list[i])
969 				continue;
970 			/*
971 			* mlo_connect: update wlan_connected_links bitmap from
972 			* assoc resp parsing
973 			*/
974 			if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
975 				if (wlan_cm_is_vdev_disconnected(
976 					mlo_dev_ctx->wlan_vdev_list[i])) {
977 					if (mlo_dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id
978 						== ml_parnter_info->partner_link_info[j].link_id) {
979 						wlan_vdev_mlme_get_ssid(
980 							vdev, ssid.ssid,
981 							&ssid.length);
982 						mlo_prepare_and_send_connect(
983 							mlo_dev_ctx->wlan_vdev_list[i],
984 							*ml_parnter_info,
985 							ml_parnter_info->partner_link_info[j],
986 							ssid);
987 						mlo_dev_lock_release(mlo_dev_ctx);
988 						return;
989 					}
990 				}
991 			}
992 		}
993 	}
994 	mlo_dev_lock_release(mlo_dev_ctx);
995 }
996 #endif
997 
998 void
999 mlo_update_connected_links_bmap(struct wlan_mlo_dev_context *mlo_dev_ctx,
1000 				struct mlo_partner_info ml_parnter_info)
1001 {
1002 	uint8_t i = 0;
1003 	uint8_t j = 0;
1004 
1005 	if (!mlo_dev_ctx) {
1006 		mlo_err("ML dev ctx is NULL");
1007 		return;
1008 	}
1009 
1010 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1011 		if (!mlo_dev_ctx->wlan_vdev_list[i])
1012 			continue;
1013 
1014 		for (j = 0; j < ml_parnter_info.num_partner_links; j++) {
1015 			if (wlan_vdev_get_link_id(mlo_dev_ctx->wlan_vdev_list[i]) ==
1016 			    ml_parnter_info.partner_link_info[j].link_id)
1017 				mlo_update_connected_links(
1018 					mlo_dev_ctx->wlan_vdev_list[i], 1);
1019 		}
1020 	}
1021 }
1022 
1023 void mlo_clear_connected_links_bmap(struct wlan_objmgr_vdev *vdev)
1024 {
1025 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1026 	struct wlan_mlo_sta *sta_ctx = NULL;
1027 
1028 	if (!vdev)
1029 		return;
1030 
1031 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1032 	if (!mlo_dev_ctx)
1033 		return;
1034 
1035 	sta_ctx = mlo_dev_ctx->sta_ctx;
1036 	if (!sta_ctx)
1037 		return;
1038 
1039 	qdf_mem_zero(sta_ctx->wlan_connected_links,
1040 		     sizeof(sta_ctx->wlan_connected_links));
1041 }
1042 
1043 static QDF_STATUS ml_activate_disconnect_req_sched_cb(struct scheduler_msg *msg)
1044 {
1045 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1046 
1047 	if (!vdev) {
1048 		mlme_err("Null input vdev");
1049 		return QDF_STATUS_E_INVAL;
1050 	}
1051 
1052 	mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
1053 		       REASON_UNSPEC_FAILURE, NULL);
1054 
1055 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1056 	return QDF_STATUS_SUCCESS;
1057 }
1058 
1059 static QDF_STATUS ml_activate_disconnect_req_flush_cb(struct scheduler_msg *msg)
1060 {
1061 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1062 
1063 	if (!vdev) {
1064 		mlme_err("Null input vdev");
1065 		return QDF_STATUS_E_INVAL;
1066 	}
1067 
1068 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1069 	return QDF_STATUS_SUCCESS;
1070 }
1071 
1072 static QDF_STATUS ml_activate_pend_disconn_req_cb(struct scheduler_msg *msg)
1073 {
1074 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1075 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1076 	struct wlan_mlo_sta *sta_ctx = NULL;
1077 
1078 	if (!vdev) {
1079 		mlme_err("Null input vdev");
1080 		return QDF_STATUS_E_INVAL;
1081 	}
1082 
1083 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1084 	sta_ctx = mlo_dev_ctx->sta_ctx;
1085 	if (!sta_ctx || !sta_ctx->disconn_req)
1086 		goto release_ref;
1087 
1088 	mlo_disconnect_req(vdev, sta_ctx->disconn_req->source,
1089 			   sta_ctx->disconn_req->reason_code,
1090 			   &sta_ctx->disconn_req->bssid, false);
1091 
1092 	qdf_mem_free(sta_ctx->disconn_req);
1093 	sta_ctx->disconn_req = NULL;
1094 
1095 release_ref:
1096 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1097 
1098 	return QDF_STATUS_SUCCESS;
1099 }
1100 
1101 static QDF_STATUS ml_activate_pend_disconn_req_flush_cb(
1102 					struct scheduler_msg *msg)
1103 {
1104 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1105 
1106 	if (!vdev) {
1107 		mlme_err("Null input vdev");
1108 		return QDF_STATUS_E_INVAL;
1109 	}
1110 
1111 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1112 	return QDF_STATUS_SUCCESS;
1113 }
1114 
1115 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1116 static inline
1117 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
1118 {
1119 	return scheduler_post_message(
1120 			QDF_MODULE_ID_OS_IF,
1121 			QDF_MODULE_ID_SCAN,
1122 			QDF_MODULE_ID_OS_IF,
1123 			msg);
1124 }
1125 #else
1126 static inline
1127 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
1128 {
1129 	return scheduler_post_message(
1130 			QDF_MODULE_ID_MLME,
1131 			QDF_MODULE_ID_MLME,
1132 			QDF_MODULE_ID_MLME,
1133 			msg);
1134 }
1135 #endif
1136 
1137 void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev,
1138 					 struct wlan_cm_connect_resp *rsp)
1139 {
1140 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1141 	struct scheduler_msg msg = {0};
1142 	QDF_STATUS ret;
1143 	struct wlan_objmgr_vdev *assoc_vdev;
1144 
1145 	if (!mlo_dev_ctx) {
1146 		mlo_err("ML dev ctx is NULL");
1147 		return;
1148 	}
1149 
1150 	assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
1151 	if (!assoc_vdev) {
1152 		mlo_err("Assoc Vdev is NULL");
1153 		return;
1154 	}
1155 
1156 	if (vdev != assoc_vdev) {
1157 		mlo_update_connected_links(vdev, 0);
1158 		if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
1159 		    rsp->reason == CM_HW_MODE_FAILURE ||
1160 		    rsp->reason == CM_SER_FAILURE) {
1161 			ret = wlan_objmgr_vdev_try_get_ref(
1162 					assoc_vdev, WLAN_MLO_MGR_ID);
1163 			if (QDF_IS_STATUS_ERROR(ret)) {
1164 				mlo_err("Failed to get ref vdev_id %d",
1165 					wlan_vdev_get_id(assoc_vdev));
1166 				return;
1167 			}
1168 			/* Since these failures happen in same context. use
1169 			 * scheduler to avoid deadlock by deferring context
1170 			 */
1171 			msg.bodyptr = assoc_vdev;
1172 			msg.callback = ml_activate_disconnect_req_sched_cb;
1173 			msg.flush_callback =
1174 				ml_activate_disconnect_req_flush_cb;
1175 			ret = mlo_post_disconnect_msg(&msg);
1176 			if (QDF_IS_STATUS_ERROR(ret)) {
1177 				wlan_objmgr_vdev_release_ref(
1178 						assoc_vdev,
1179 						WLAN_MLO_MGR_ID);
1180 				return;
1181 			}
1182 		} else {
1183 			mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
1184 				       REASON_UNSPEC_FAILURE, NULL);
1185 		}
1186 	}
1187 }
1188 
1189 void mlo_handle_pending_disconnect(struct wlan_objmgr_vdev *vdev)
1190 {
1191 	struct scheduler_msg msg = {0};
1192 	QDF_STATUS ret;
1193 
1194 	ret = wlan_objmgr_vdev_try_get_ref(
1195 			vdev, WLAN_MLO_MGR_ID);
1196 	if (QDF_IS_STATUS_ERROR(ret)) {
1197 		mlo_err("Failed to get ref vdev_id %d",
1198 			wlan_vdev_get_id(vdev));
1199 		return;
1200 	}
1201 
1202 	msg.bodyptr = vdev;
1203 	msg.callback = ml_activate_pend_disconn_req_cb;
1204 	msg.flush_callback =
1205 		ml_activate_pend_disconn_req_flush_cb;
1206 	ret = mlo_post_disconnect_msg(&msg);
1207 	if (QDF_IS_STATUS_ERROR(ret)) {
1208 		mlo_err("Failed to post scheduler msg");
1209 		wlan_objmgr_vdev_release_ref(
1210 				vdev,
1211 				WLAN_MLO_MGR_ID);
1212 		QDF_BUG(0);
1213 		return;
1214 	}
1215 }
1216 
1217 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1218 static bool
1219 mlo_sta_ignore_link_connect_fail(struct wlan_objmgr_vdev *vdev)
1220 {
1221 	if (wlan_cm_is_vdev_disconnected(vdev)) {
1222 		if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
1223 			return false;
1224 		else
1225 			return true;
1226 	}
1227 
1228 	return false;
1229 }
1230 #else
1231 static inline bool
1232 mlo_sta_ignore_link_connect_fail(struct wlan_objmgr_vdev *vdev)
1233 {
1234 	return false;
1235 }
1236 #endif
1237 
1238 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
1239 				 struct wlan_cm_connect_resp *rsp)
1240 {
1241 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1242 	struct wlan_mlo_sta *sta_ctx = NULL;
1243 
1244 	if (mlo_dev_ctx) {
1245 		sta_ctx = mlo_dev_ctx->sta_ctx;
1246 	} else {
1247 		mlo_debug_rl("mlo_dev_ctx is NULL");
1248 		return;
1249 	}
1250 
1251 	if (sta_ctx && sta_ctx->disconn_req) {
1252 		mlo_debug("Handle pending disocnnect for vdev %d",
1253 			  wlan_vdev_get_id(vdev));
1254 		mlo_handle_pending_disconnect(vdev);
1255 		return;
1256 	}
1257 
1258 	if (wlan_cm_is_link_switch_connect_resp(rsp)) {
1259 		mlo_info("Skip for link switch connect request");
1260 		return;
1261 	}
1262 
1263 	if (mlo_sta_ignore_link_connect_fail(vdev))
1264 		return;
1265 
1266 	if (wlan_cm_is_vdev_disconnected(vdev))
1267 		mlo_free_copied_conn_req(sta_ctx);
1268 
1269 	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1270 		mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev));
1271 		if (wlan_cm_is_vdev_disconnected(vdev)) {
1272 			mlo_handle_sta_link_connect_failure(vdev, rsp);
1273 			return;
1274 		} else if (!wlan_cm_is_vdev_connected(vdev)) {
1275 			/* If vdev is not in disconnected or connected state,
1276 			 * then the event is received due to connect req being
1277 			 * flushed. Hence, ignore this event
1278 			 */
1279 			return;
1280 		}
1281 
1282 		if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) && sta_ctx) {
1283 			if (sta_ctx->assoc_rsp.ptr) {
1284 				qdf_mem_free(sta_ctx->assoc_rsp.ptr);
1285 				sta_ctx->assoc_rsp.ptr = NULL;
1286 			}
1287 			sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len;
1288 			sta_ctx->assoc_rsp.ptr =
1289 				qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len);
1290 			if (!sta_ctx->assoc_rsp.ptr) {
1291 				QDF_ASSERT(0);
1292 				return;
1293 			}
1294 			if (rsp->connect_ies.assoc_rsp.ptr)
1295 				qdf_mem_copy(sta_ctx->assoc_rsp.ptr,
1296 					     rsp->connect_ies.assoc_rsp.ptr,
1297 					     rsp->connect_ies.assoc_rsp.len);
1298 			sta_ctx->ml_partner_info = rsp->ml_parnter_info;
1299 			/* Update connected_links_bmap for all vdev taking
1300 			 * part in association
1301 			 */
1302 			mlo_update_connected_links(vdev, 1);
1303 			mlo_update_connected_links_bmap(mlo_dev_ctx,
1304 							rsp->ml_parnter_info);
1305 		}
1306 		mlo_send_link_connect(vdev, mlo_dev_ctx,
1307 				      &rsp->connect_ies.assoc_rsp,
1308 				      &rsp->ml_parnter_info);
1309 	}
1310 }
1311 
1312 /**
1313  * mlo_send_link_disconnect_sync- Issue sync the disconnect request on MLD links
1314  *
1315  * @mlo_dev_ctx: pointer to mlo dev context
1316  * @source: disconnect source
1317  * @reason_code: disconnect reason
1318  * @bssid: bssid of AP to disconnect, can be null if not known
1319  *
1320  * Return: QDF_STATUS
1321  */
1322 static QDF_STATUS
1323 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
1324 			      enum wlan_cm_source source,
1325 			      enum wlan_reason_code reason_code,
1326 			      struct qdf_mac_addr *bssid)
1327 {
1328 	uint8_t i;
1329 	struct wlan_objmgr_vdev *sync_vdev =
1330 		mlo_get_assoc_link_vdev(mlo_dev_ctx);
1331 
1332 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1333 		if (!mlo_dev_ctx->wlan_vdev_list[i] ||
1334 		    mlo_dev_ctx->wlan_vdev_list[i] == sync_vdev) {
1335 			continue;
1336 		}
1337 
1338 		/**
1339 		 * If the assoc vdev isn't present, use the first link dev as
1340 		 * sync candidate.
1341 		 */
1342 		if (!sync_vdev) {
1343 			sync_vdev = mlo_dev_ctx->wlan_vdev_list[i];
1344 			continue;
1345 		}
1346 
1347 		/**
1348 		 * To initiate disconnect on all links at once, no need to use
1349 		 * sync API for all link vdevs.
1350 		 */
1351 		wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
1352 				   source, reason_code, NULL);
1353 	}
1354 
1355 	if (sync_vdev)
1356 		wlan_cm_disconnect_sync(sync_vdev, source, reason_code);
1357 
1358 	return QDF_STATUS_SUCCESS;
1359 }
1360 
1361 static QDF_STATUS mlo_disconnect_req(struct wlan_objmgr_vdev *vdev,
1362 				     enum wlan_cm_source source,
1363 				     enum wlan_reason_code reason_code,
1364 				     struct qdf_mac_addr *bssid,
1365 				     bool validate_req)
1366 {
1367 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1368 	struct wlan_mlo_sta *sta_ctx = NULL;
1369 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1370 
1371 	if (!vdev)
1372 		return QDF_STATUS_E_FAILURE;
1373 
1374 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1375 	if (mlo_dev_ctx)
1376 		sta_ctx = mlo_dev_ctx->sta_ctx;
1377 	if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1378 		mlo_dev_lock_acquire(mlo_dev_ctx);
1379 		if (sta_ctx && sta_ctx->connect_req &&
1380 		    source != CM_INTERNAL_DISCONNECT) {
1381 			wlan_cm_free_connect_req(sta_ctx->connect_req);
1382 			sta_ctx->connect_req = NULL;
1383 		}
1384 
1385 		if (validate_req) {
1386 			status = mlo_validate_disconn_req(vdev, source,
1387 							  reason_code, bssid);
1388 			if (QDF_IS_STATUS_ERROR(status)) {
1389 				mlo_err("Connect in progress, deferring disconnect");
1390 				mlo_dev_lock_release(mlo_dev_ctx);
1391 				return status;
1392 			}
1393 		}
1394 
1395 		mlo_dev_lock_release(mlo_dev_ctx);
1396 
1397 		status = mlo_send_link_disconnect(vdev, source,
1398 						  reason_code, bssid);
1399 		if (QDF_IS_STATUS_SUCCESS(status))
1400 			mlo_free_copied_conn_req(sta_ctx);
1401 
1402 		return status;
1403 	}
1404 	status = wlan_cm_disconnect(vdev, source,
1405 				    reason_code, NULL);
1406 	if (QDF_IS_STATUS_SUCCESS(status))
1407 		mlo_free_copied_conn_req(sta_ctx);
1408 
1409 	return status;
1410 }
1411 
1412 QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
1413 			  enum wlan_cm_source source,
1414 			  enum wlan_reason_code reason_code,
1415 			  struct qdf_mac_addr *bssid)
1416 {
1417 	return mlo_disconnect_req(vdev, source, reason_code, bssid, true);
1418 }
1419 
1420 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1421 /**
1422  * mlo_wait_for_mld_disconnection - API to wait for sync mld disconnection
1423  * @vdev: pointer to vdev
1424  *
1425  * Return: none
1426  */
1427 static inline
1428 void mlo_wait_for_mld_disconnection(struct wlan_objmgr_vdev *vdev)
1429 { }
1430 #else
1431 #define ML_DISCONNECT_CMD_TIMEOUT 1000
1432 #define ML_DISCONNECT_CMD_TIMEOUT_CNT 30 /* 30*1000 ms */
1433 
1434 static void mlo_wait_for_mld_disconnection(struct wlan_objmgr_vdev *vdev)
1435 {
1436 	int waitcnt = 0;
1437 	qdf_event_t wait_event;
1438 
1439 	qdf_mem_zero(&wait_event, sizeof(wait_event));
1440 	qdf_event_create(&wait_event);
1441 	qdf_event_reset(&wait_event);
1442 
1443 	while (!mlo_is_mld_disconnected(vdev) &&
1444 	       waitcnt < ML_DISCONNECT_CMD_TIMEOUT_CNT) {
1445 		qdf_wait_single_event(&wait_event, ML_DISCONNECT_CMD_TIMEOUT);
1446 		waitcnt++;
1447 	}
1448 	qdf_event_destroy(&wait_event);
1449 }
1450 #endif
1451 QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev,
1452 			       enum wlan_cm_source source,
1453 			       enum wlan_reason_code reason_code,
1454 			       struct qdf_mac_addr *bssid)
1455 {
1456 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1457 	struct wlan_mlo_sta *sta_ctx = NULL;
1458 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1459 
1460 	if (!vdev)
1461 		return QDF_STATUS_E_FAILURE;
1462 
1463 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1464 	if (mlo_dev_ctx)
1465 		sta_ctx = mlo_dev_ctx->sta_ctx;
1466 	if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1467 		if (sta_ctx && sta_ctx->connect_req) {
1468 			wlan_cm_free_connect_req(sta_ctx->connect_req);
1469 			sta_ctx->connect_req = NULL;
1470 		}
1471 
1472 		status = mlo_validate_disconn_req(vdev, source,
1473 						  reason_code, bssid);
1474 		if (QDF_IS_STATUS_ERROR(status)) {
1475 			mlo_err("Connect in progress, deferring disconnect");
1476 			return status;
1477 		}
1478 
1479 		status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source,
1480 						       reason_code, bssid);
1481 		if (QDF_IS_STATUS_SUCCESS(status)) {
1482 			mlo_free_copied_conn_req(sta_ctx);
1483 			mlo_wait_for_mld_disconnection(vdev);
1484 		}
1485 
1486 		return status;
1487 	}
1488 	status = wlan_cm_disconnect_sync(vdev, source,
1489 					 reason_code);
1490 	if (QDF_IS_STATUS_SUCCESS(status))
1491 		mlo_free_copied_conn_req(sta_ctx);
1492 
1493 	return status;
1494 }
1495 
1496 /**
1497  * mlo_handle_disconnect_resp- Issue desired actions on partner link vdev
1498  *
1499  * @vdev: pointer to vdev
1500  * @resp: disconnect resp
1501  *
1502  * Return: none
1503  */
1504 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1505 static
1506 void mlo_handle_disconnect_resp(struct wlan_objmgr_vdev *vdev,
1507 				struct wlan_cm_discon_rsp *resp)
1508 {
1509 /* If it is secondary link then delete vdev object from mlo device. */
1510 	enum wlan_cm_source source;
1511 	enum wlan_reason_code reason_code;
1512 	uint8_t i = 0;
1513 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
1514 	uint16_t vdev_count = 0;
1515 
1516 	mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
1517 	for (i =  0; i < vdev_count; i++) {
1518 		if (wlan_cm_is_vdev_connected(wlan_vdev_list[i])) {
1519 			if (wlan_vdev_mlme_is_mlo_link_vdev(
1520 					wlan_vdev_list[i])) {
1521 				source = resp->req.req.source;
1522 				reason_code = resp->req.req.reason_code;
1523 				wlan_cm_disconnect(
1524 						wlan_vdev_list[i],
1525 						source, reason_code, NULL);
1526 			}
1527 		}
1528 		mlo_release_vdev_ref(wlan_vdev_list[i]);
1529 	}
1530 }
1531 #else
1532 static
1533 void mlo_handle_disconnect_resp(struct wlan_objmgr_vdev *vdev,
1534 				struct wlan_cm_discon_rsp *resp)
1535 { }
1536 
1537 static QDF_STATUS ml_activate_connect_req_sched_cb(struct scheduler_msg *msg)
1538 {
1539 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1540 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1541 	struct wlan_mlo_sta *sta_ctx = NULL;
1542 	uint8_t i = 0;
1543 	struct mlo_partner_info partner_info;
1544 	struct mlo_link_info partner_link_info;
1545 	struct wlan_objmgr_vdev *tmp_vdev;
1546 
1547 	if (!vdev) {
1548 		mlme_err("Null input vdev");
1549 		return QDF_STATUS_E_INVAL;
1550 	}
1551 
1552 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1553 	if (!mlo_dev_ctx) {
1554 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1555 		return QDF_STATUS_E_INVAL;
1556 	}
1557 
1558 	sta_ctx = mlo_dev_ctx->sta_ctx;
1559 	if (!sta_ctx || !sta_ctx->connect_req) {
1560 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1561 		return QDF_STATUS_E_INVAL;
1562 	}
1563 
1564 	if (sta_ctx->connect_req->ml_parnter_info.num_partner_links) {
1565 		partner_info = sta_ctx->connect_req->ml_parnter_info;
1566 		wlan_vdev_mlme_set_mlo_vdev(vdev);
1567 		wlan_vdev_mlme_clear_mlo_link_vdev(vdev);
1568 		mlo_clear_connect_req_links_bmap(vdev);
1569 		mlo_update_connect_req_links(vdev, 1);
1570 		for (i = 0; i < partner_info.num_partner_links; i++) {
1571 			partner_link_info = partner_info.partner_link_info[i];
1572 			tmp_vdev = mlo_get_ml_vdev_by_mac(
1573 					vdev,
1574 					&partner_link_info.link_addr);
1575 			if (tmp_vdev) {
1576 				mlo_update_connect_req_links(tmp_vdev, 1);
1577 				wlan_vdev_mlme_set_mlo_vdev(tmp_vdev);
1578 				wlan_vdev_mlme_set_mlo_link_vdev(tmp_vdev);
1579 				wlan_vdev_set_link_id(
1580 					tmp_vdev,
1581 					partner_link_info.link_id);
1582 			}
1583 		}
1584 	}
1585 
1586 	mlo_connect(vdev, sta_ctx->connect_req);
1587 	wlan_cm_free_connect_req(sta_ctx->connect_req);
1588 	sta_ctx->connect_req = NULL;
1589 
1590 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1591 	return QDF_STATUS_SUCCESS;
1592 }
1593 
1594 static QDF_STATUS ml_activate_connect_req_flush_cb(struct scheduler_msg *msg)
1595 {
1596 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1597 
1598 	if (!vdev) {
1599 		mlme_err("Null input vdev");
1600 		return QDF_STATUS_E_INVAL;
1601 	}
1602 
1603 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1604 	return QDF_STATUS_SUCCESS;
1605 }
1606 #endif
1607 
1608 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1609 static inline
1610 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
1611 { }
1612 #else
1613 static inline
1614 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
1615 {
1616 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1617 	struct scheduler_msg msg = {0};
1618 	QDF_STATUS ret;
1619 	struct wlan_mlo_sta *sta_ctx = NULL;
1620 
1621 	if (!mlo_dev_ctx) {
1622 		mlo_err("ML dev ctx is null");
1623 		return;
1624 	}
1625 	sta_ctx = mlo_dev_ctx->sta_ctx;
1626 	ret = wlan_objmgr_vdev_try_get_ref(
1627 			vdev,
1628 			WLAN_MLO_MGR_ID);
1629 	if (QDF_IS_STATUS_ERROR(ret)) {
1630 		wlan_cm_free_connect_req(sta_ctx->connect_req);
1631 		sta_ctx->connect_req = NULL;
1632 		return;
1633 	}
1634 	msg.bodyptr = vdev;
1635 	msg.callback = ml_activate_connect_req_sched_cb;
1636 	msg.flush_callback = ml_activate_connect_req_flush_cb;
1637 
1638 	ret = scheduler_post_message(QDF_MODULE_ID_MLME,
1639 				     QDF_MODULE_ID_MLME,
1640 				     QDF_MODULE_ID_MLME, &msg);
1641 	if (QDF_IS_STATUS_ERROR(ret)) {
1642 		wlan_cm_free_connect_req(sta_ctx->connect_req);
1643 		sta_ctx->connect_req = NULL;
1644 		wlan_objmgr_vdev_release_ref(vdev,
1645 					     WLAN_MLO_MGR_ID);
1646 		return;
1647 	}
1648 }
1649 #endif
1650 
1651 void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev,
1652 				 struct wlan_cm_discon_rsp *resp)
1653 {
1654 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1655 	struct wlan_mlo_sta *sta_ctx = NULL;
1656 	struct wlan_objmgr_vdev *assoc_vdev = NULL;
1657 
1658 	if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev)))
1659 		return;
1660 
1661 	sta_ctx = mlo_dev_ctx->sta_ctx;
1662 	if (!sta_ctx)
1663 		return;
1664 
1665 	if (!wlan_cm_is_vdev_disconnected(vdev))
1666 		return;
1667 
1668 	mlo_update_connected_links(vdev, 0);
1669 	if (mlo_is_mld_disconnected(vdev)) {
1670 		if (sta_ctx->connect_req) {
1671 			assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
1672 			if (!assoc_vdev)
1673 				return;
1674 			mlo_sta_link_handle_pending_connect(assoc_vdev);
1675 		}
1676 	}
1677 
1678 	if (!wlan_cm_is_link_switch_disconnect_resp(resp))
1679 		mlo_handle_disconnect_resp(vdev, resp);
1680 }
1681 
1682 bool mlo_is_mld_sta(struct wlan_objmgr_vdev *vdev)
1683 {
1684 	if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) &&
1685 	    wlan_vdev_mlme_is_mlo_vdev(vdev))
1686 		return true;
1687 
1688 	return false;
1689 }
1690 
1691 qdf_export_symbol(mlo_is_mld_sta);
1692 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1693 struct wlan_objmgr_vdev *
1694 mlo_get_ml_vdev_by_mac(struct wlan_objmgr_vdev *vdev,
1695 		       struct qdf_mac_addr *macaddr)
1696 {
1697 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1698 	uint8_t i = 0;
1699 
1700 	if (!mlo_dev_ctx)
1701 		return NULL;
1702 
1703 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1704 		if (!mlo_dev_ctx->wlan_vdev_list[i])
1705 			continue;
1706 
1707 		if(qdf_mem_cmp(macaddr,
1708 			       wlan_vdev_mlme_get_macaddr(mlo_dev_ctx->wlan_vdev_list[i]),
1709 			       QDF_MAC_ADDR_SIZE) == 0) {
1710 			return mlo_dev_ctx->wlan_vdev_list[i];
1711 		}
1712 	}
1713 	return NULL;
1714 }
1715 #endif
1716 
1717 qdf_freq_t
1718 mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev *pdev,
1719 			   struct qdf_mac_addr *bssid)
1720 {
1721 	struct scan_filter *scan_filter;
1722 	int8_t ch_freq = 0;
1723 	qdf_list_t *list = NULL;
1724 	struct scan_cache_node *first_node = NULL;
1725 	qdf_list_node_t *cur_node = NULL;
1726 
1727 	scan_filter = qdf_mem_malloc(sizeof(*scan_filter));
1728 	if (!scan_filter)
1729 		return ch_freq;
1730 
1731 	scan_filter->num_of_bssid = 1;
1732 	qdf_mem_copy(scan_filter->bssid_list[0].bytes,
1733 		     bssid, sizeof(struct qdf_mac_addr));
1734 	list = wlan_scan_get_result(pdev, scan_filter);
1735 	qdf_mem_free(scan_filter);
1736 
1737 	if (!list || (list && !qdf_list_size(list))) {
1738 		mlo_debug("scan list empty");
1739 		goto error;
1740 	}
1741 
1742 	qdf_list_peek_front(list, &cur_node);
1743 	first_node = qdf_container_of(cur_node,
1744 				      struct scan_cache_node,
1745 				      node);
1746 	if (first_node && first_node->entry)
1747 		ch_freq = first_node->entry->channel.chan_freq;
1748 error:
1749 	if (list)
1750 		wlan_scan_purge_results(list);
1751 
1752 	return ch_freq;
1753 }
1754 
1755 void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev,
1756 		       struct element_info *assoc_rsp_frame)
1757 {
1758 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1759 	struct wlan_mlo_sta *sta_ctx = NULL;
1760 
1761 	if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx)
1762 		return;
1763 
1764 	sta_ctx = mlo_dev_ctx->sta_ctx;
1765 
1766 	if (!sta_ctx->assoc_rsp.len || !sta_ctx->assoc_rsp.ptr) {
1767 		mlo_err("Assoc Resp info is empty");
1768 		return;
1769 	}
1770 
1771 	*assoc_rsp_frame = sta_ctx->assoc_rsp;
1772 }
1773 
1774 QDF_STATUS mlo_sta_save_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
1775 				     uint8_t link_id,
1776 				     bool quiet_status)
1777 {
1778 	struct wlan_mlo_sta *sta_ctx;
1779 	int i;
1780 	bool find_free_buffer = false;
1781 	int free_idx;
1782 
1783 	if (!mlo_dev_ctx) {
1784 		mlo_err("invalid mlo_dev_ctx");
1785 		return QDF_STATUS_E_INVAL;
1786 	}
1787 
1788 	mlo_dev_lock_acquire(mlo_dev_ctx);
1789 	sta_ctx = mlo_dev_ctx->sta_ctx;
1790 	if (!sta_ctx) {
1791 		mlo_err("invalid sta_ctx");
1792 		mlo_dev_lock_release(mlo_dev_ctx);
1793 		return QDF_STATUS_E_INVAL;
1794 	}
1795 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) {
1796 		if (!sta_ctx->mlo_quiet_status[i].valid_status) {
1797 			if (!find_free_buffer) {
1798 				free_idx = i;
1799 				find_free_buffer = true;
1800 			}
1801 		} else if (link_id == sta_ctx->mlo_quiet_status[i].link_id) {
1802 			sta_ctx->mlo_quiet_status[i].quiet_status =
1803 							quiet_status;
1804 			mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d quiet status update %d",
1805 				  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
1806 				  link_id, quiet_status);
1807 			mlo_dev_lock_release(mlo_dev_ctx);
1808 			return QDF_STATUS_SUCCESS;
1809 		}
1810 	}
1811 	if (!find_free_buffer) {
1812 		mlo_err("no free buffer for link id %d to save quiet_status",
1813 			link_id);
1814 		mlo_dev_lock_release(mlo_dev_ctx);
1815 		return QDF_STATUS_E_INVAL;
1816 	}
1817 	sta_ctx->mlo_quiet_status[free_idx].quiet_status = quiet_status;
1818 	sta_ctx->mlo_quiet_status[free_idx].link_id = link_id;
1819 	sta_ctx->mlo_quiet_status[free_idx].valid_status = true;
1820 
1821 	mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d in quiet status %d",
1822 		  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
1823 		  link_id, quiet_status);
1824 	mlo_dev_lock_release(mlo_dev_ctx);
1825 
1826 	return QDF_STATUS_SUCCESS;
1827 }
1828 
1829 bool mlo_is_sta_in_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
1830 				uint8_t link_id)
1831 {
1832 	struct wlan_mlo_sta *sta_ctx;
1833 	int i;
1834 	bool quiet_status = false;
1835 
1836 	if (!mlo_dev_ctx) {
1837 		mlo_err("invalid mlo_dev_ctx");
1838 		return quiet_status;
1839 	}
1840 
1841 	mlo_dev_lock_acquire(mlo_dev_ctx);
1842 	sta_ctx = mlo_dev_ctx->sta_ctx;
1843 	if (!sta_ctx) {
1844 		mlo_err("invalid sta_ctx");
1845 		mlo_dev_lock_release(mlo_dev_ctx);
1846 		return quiet_status;
1847 	}
1848 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) {
1849 		if (sta_ctx->mlo_quiet_status[i].valid_status &&
1850 		    link_id == sta_ctx->mlo_quiet_status[i].link_id) {
1851 			quiet_status =
1852 				sta_ctx->mlo_quiet_status[i].quiet_status;
1853 			break;
1854 		}
1855 	}
1856 	mlo_dev_lock_release(mlo_dev_ctx);
1857 
1858 	return quiet_status;
1859 }
1860 
1861 bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc,
1862 					      uint8_t *vdev_id_list,
1863 					      uint8_t num_mlo, uint8_t *mlo_idx,
1864 					      uint8_t affected_links,
1865 					      uint8_t *affected_list)
1866 {
1867 	uint8_t i, j;
1868 	struct wlan_objmgr_vdev *vdev;
1869 	bool allowed = false;
1870 
1871 	for (i = 0; i < num_mlo; i++) {
1872 		for (j = 0; j < affected_links; j++) {
1873 			if (vdev_id_list[mlo_idx[i]] == affected_list[j])
1874 				break;
1875 		}
1876 		if (j != affected_links)
1877 			continue;
1878 		/* find vdev not in affected_list */
1879 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
1880 				psoc, vdev_id_list[mlo_idx[i]],
1881 				WLAN_IF_MGR_ID);
1882 		if (!vdev) {
1883 			mlo_err("invalid vdev for id %d",
1884 				vdev_id_list[mlo_idx[i]]);
1885 			continue;
1886 		}
1887 
1888 		/* for not affected vdev, check the vdev is in quiet or not*/
1889 		allowed = !mlo_is_sta_in_quiet_status(
1890 				vdev->mlo_dev_ctx, wlan_vdev_get_link_id(vdev));
1891 		wlan_objmgr_vdev_release_ref(vdev, WLAN_IF_MGR_ID);
1892 		if (allowed) {
1893 			mlo_debug("vdev id %d link id %d is not in quiet, allow partner link to trigger inactivity",
1894 				  wlan_vdev_get_id(vdev),
1895 				  wlan_vdev_get_link_id(vdev));
1896 			break;
1897 		}
1898 	}
1899 
1900 	return allowed;
1901 }
1902 
1903 bool mlo_is_sta_csa_synced(struct wlan_mlo_dev_context *mlo_dev_ctx,
1904 			   uint8_t link_id)
1905 {
1906 	struct wlan_mlo_sta *sta_ctx;
1907 	int i;
1908 	bool sta_csa_synced = false;
1909 
1910 	if (!mlo_dev_ctx) {
1911 		mlo_err("invalid mlo_dev_ctx");
1912 		return sta_csa_synced;
1913 	}
1914 
1915 	mlo_dev_lock_acquire(mlo_dev_ctx);
1916 	sta_ctx = mlo_dev_ctx->sta_ctx;
1917 	if (!sta_ctx) {
1918 		mlo_err("invalid sta_ctx");
1919 		mlo_dev_lock_release(mlo_dev_ctx);
1920 		return sta_csa_synced;
1921 	}
1922 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
1923 		if (link_id == sta_ctx->mlo_csa_param[i].link_id &&
1924 		    (sta_ctx->mlo_csa_param[i].valid_csa_param ||
1925 		     sta_ctx->mlo_csa_param[i].mlo_csa_synced)) {
1926 			sta_csa_synced =
1927 				sta_ctx->mlo_csa_param[i].mlo_csa_synced;
1928 			break;
1929 		}
1930 	}
1931 	mlo_dev_lock_release(mlo_dev_ctx);
1932 
1933 	return sta_csa_synced;
1934 }
1935 
1936 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1937 QDF_STATUS mlo_sta_handle_csa_standby_link(
1938 			struct wlan_mlo_dev_context *mlo_dev_ctx,
1939 			uint8_t link_id,
1940 			struct csa_offload_params *csa_param,
1941 			struct wlan_objmgr_vdev *vdev)
1942 {
1943 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1944 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
1945 	struct mlo_link_info *link_info;
1946 	struct mlo_link_bss_params params = {0};
1947 	struct wlan_objmgr_psoc *psoc;
1948 
1949 	if (!mlo_dev_ctx) {
1950 		mlo_err("invalid mlo_dev_ctx");
1951 		return QDF_STATUS_E_NULL_VALUE;
1952 	}
1953 
1954 	psoc = wlan_vdev_get_psoc(vdev);
1955 	if (!psoc) {
1956 		mlo_err("null psoc");
1957 		return QDF_STATUS_E_NULL_VALUE;
1958 	}
1959 
1960 	mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
1961 
1962 	link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx, link_id);
1963 	if (!link_info) {
1964 		mlo_err("link info null");
1965 		return QDF_STATUS_E_NULL_VALUE;
1966 	}
1967 
1968 	if (link_info->vdev_id != WLAN_INVALID_VDEV_ID) {
1969 		mlo_debug("vdev id %d link id %d ", link_info->vdev_id,
1970 			  link_id);
1971 		return QDF_STATUS_E_NULL_VALUE;
1972 	}
1973 
1974 	mlo_mgr_update_csa_link_info(mlo_dev_ctx, csa_param, link_id);
1975 
1976 	params.link_id = link_info->link_id;
1977 	params.chan = qdf_mem_malloc(sizeof(struct wlan_channel));
1978 	if (!params.chan) {
1979 		mlo_err("no mem allocated");
1980 		return QDF_STATUS_E_NOMEM;
1981 	}
1982 
1983 	wlan_vdev_get_bss_peer_mld_mac(
1984 				vdev,
1985 				(struct qdf_mac_addr *)&params.ap_mld_mac[0]);
1986 
1987 	params.chan->ch_freq = link_info->link_chan_info->ch_freq;
1988 	params.chan->ch_cfreq1 = link_info->link_chan_info->ch_cfreq1;
1989 	params.chan->ch_cfreq2 = link_info->link_chan_info->ch_cfreq2;
1990 	params.chan->ch_phymode = link_info->link_chan_info->ch_phymode;
1991 
1992 	mlo_debug("link id %d chan freq %d cfreq1 %d cfreq2 %d host phymode %d ap mld mac " QDF_MAC_ADDR_FMT,
1993 		  link_info->link_id, link_info->link_chan_info->ch_freq,
1994 		  link_info->link_chan_info->ch_cfreq1,
1995 		  link_info->link_chan_info->ch_cfreq2,
1996 		  link_info->link_chan_info->ch_phymode,
1997 		  QDF_MAC_ADDR_REF(&params.ap_mld_mac[0]));
1998 
1999 	if (!mlo_tx_ops->send_link_set_bss_params_cmd) {
2000 		mlo_err("handler is not registered");
2001 		qdf_mem_free(params.chan);
2002 		return QDF_STATUS_E_NULL_VALUE;
2003 	}
2004 
2005 	status = mlo_tx_ops->send_link_set_bss_params_cmd(psoc, &params);
2006 
2007 	if (QDF_IS_STATUS_ERROR(status)) {
2008 		mlo_err("failed to send link set bss request command to FW");
2009 		qdf_mem_free(params.chan);
2010 		return QDF_STATUS_E_NULL_VALUE;
2011 	}
2012 	qdf_mem_free(params.chan);
2013 	return status;
2014 }
2015 
2016 static void mlo_sta_handle_link_reconfig_standby_link(
2017 			struct wlan_objmgr_vdev *vdev,
2018 			struct ml_rv_info *reconfig_info)
2019 {
2020 	struct vdev_mlme_obj *vdev_mlme;
2021 
2022 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
2023 	if (!vdev_mlme)
2024 		return;
2025 	if (vdev_mlme->ops &&
2026 	    vdev_mlme->ops->mlme_vdev_reconfig_notify_standby) {
2027 		vdev_mlme->ops->mlme_vdev_reconfig_notify_standby(
2028 				vdev_mlme,
2029 				reconfig_info);
2030 	}
2031 }
2032 #else
2033 static void mlo_sta_handle_link_reconfig_standby_link(
2034 			struct wlan_objmgr_vdev *vdev,
2035 			struct ml_rv_info *reconfig_info)
2036 {
2037 }
2038 #endif
2039 
2040 QDF_STATUS mlo_sta_csa_save_params(struct wlan_mlo_dev_context *mlo_dev_ctx,
2041 				   uint8_t link_id,
2042 				   struct csa_offload_params *csa_param)
2043 {
2044 	struct wlan_mlo_sta *sta_ctx;
2045 	int i;
2046 	bool find_free_buffer = false;
2047 	int free_idx;
2048 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2049 
2050 	if (!mlo_dev_ctx) {
2051 		mlo_err("invalid mlo_dev_ctx");
2052 		status = QDF_STATUS_E_INVAL;
2053 		goto done;
2054 	}
2055 
2056 	mlo_dev_lock_acquire(mlo_dev_ctx);
2057 	sta_ctx = mlo_dev_ctx->sta_ctx;
2058 	if (!sta_ctx) {
2059 		mlo_err("invalid sta_ctx");
2060 		status = QDF_STATUS_E_INVAL;
2061 		goto rel_lock;
2062 	}
2063 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
2064 		if (!sta_ctx->mlo_csa_param[i].valid_csa_param &&
2065 		    !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
2066 			if (!find_free_buffer) {
2067 				free_idx = i;
2068 				find_free_buffer = true;
2069 			}
2070 		} else if (link_id == sta_ctx->mlo_csa_param[i].link_id) {
2071 			qdf_mem_copy(&sta_ctx->mlo_csa_param[i].csa_param,
2072 				     csa_param, sizeof(*csa_param));
2073 			mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d update csa",
2074 				  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
2075 				  link_id);
2076 			goto rel_lock;
2077 		}
2078 	}
2079 	if (!find_free_buffer) {
2080 		mlo_err("no free buffer of csa param for link %d in sta_ctx",
2081 			link_id);
2082 		status = QDF_STATUS_E_INVAL;
2083 		goto rel_lock;
2084 	}
2085 	qdf_mem_copy(&sta_ctx->mlo_csa_param[free_idx].csa_param,
2086 		     csa_param, sizeof(*csa_param));
2087 	sta_ctx->mlo_csa_param[free_idx].link_id = link_id;
2088 	sta_ctx->mlo_csa_param[free_idx].valid_csa_param = true;
2089 	mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d RX csa",
2090 		  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
2091 		  link_id);
2092 
2093 rel_lock:
2094 	mlo_dev_lock_release(mlo_dev_ctx);
2095 
2096 done:
2097 
2098 	return status;
2099 }
2100 
2101 QDF_STATUS mlo_sta_up_active_notify(struct wlan_objmgr_vdev *vdev)
2102 {
2103 	struct wlan_mlo_sta *sta_ctx;
2104 	struct wlan_mlo_dev_context *mlo_dev_ctx;
2105 	uint8_t link_id;
2106 	int i;
2107 	bool find_free_buffer = false;
2108 	int free_idx;
2109 	struct csa_offload_params csa_param;
2110 	struct wlan_channel *chan;
2111 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2112 
2113 	if (!vdev) {
2114 		mlo_err("invalid vdev");
2115 		status = QDF_STATUS_E_INVAL;
2116 		goto done;
2117 	}
2118 	link_id = wlan_vdev_get_link_id(vdev);
2119 	mlo_dev_ctx = vdev->mlo_dev_ctx;
2120 	if (!mlo_dev_ctx) {
2121 		mlo_err("invalid mlo_dev_ctx");
2122 		status = QDF_STATUS_E_INVAL;
2123 		goto done;
2124 	}
2125 	mlo_dev_lock_acquire(mlo_dev_ctx);
2126 	sta_ctx = mlo_dev_ctx->sta_ctx;
2127 	if (!sta_ctx) {
2128 		mlo_err("invalid sta_ctx");
2129 		status = QDF_STATUS_E_INVAL;
2130 		goto rel_lock;
2131 	}
2132 
2133 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
2134 		if (!sta_ctx->mlo_csa_param[i].valid_csa_param &&
2135 		    !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
2136 			if (!find_free_buffer) {
2137 				free_idx = i;
2138 				find_free_buffer = true;
2139 			}
2140 		} else if (link_id == sta_ctx->mlo_csa_param[i].link_id) {
2141 			if (sta_ctx->mlo_csa_param[i].valid_csa_param &&
2142 			    !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
2143 				mlo_debug("mld mac " QDF_MAC_ADDR_FMT " vdev id %d link id %d handle csa",
2144 					  QDF_MAC_ADDR_REF(
2145 						mlo_dev_ctx->mld_addr.bytes),
2146 					  wlan_vdev_get_id(vdev), link_id);
2147 				csa_param = sta_ctx->mlo_csa_param[i].csa_param;
2148 				sta_ctx->mlo_csa_param[i].mlo_csa_synced = true;
2149 				mlo_dev_lock_release(mlo_dev_ctx);
2150 				chan = wlan_vdev_mlme_get_bss_chan(vdev);
2151 				if (csa_param.csa_chan_freq && chan &&
2152 				    csa_param.csa_chan_freq != chan->ch_freq)
2153 					mlo_mlme_handle_sta_csa_param(
2154 						vdev, &csa_param);
2155 				goto done;
2156 			}
2157 			sta_ctx->mlo_csa_param[i].mlo_csa_synced = true;
2158 			goto rel_lock;
2159 		}
2160 	}
2161 	if (!find_free_buffer) {
2162 		mlo_err("no free buffer of csa param for link %d in sta_ctx",
2163 			link_id);
2164 		goto rel_lock;
2165 	}
2166 	sta_ctx->mlo_csa_param[free_idx].mlo_csa_synced = true;
2167 	sta_ctx->mlo_csa_param[free_idx].link_id = link_id;
2168 	mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d UP Active",
2169 		  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
2170 		  link_id);
2171 
2172 rel_lock:
2173 	mlo_dev_lock_release(mlo_dev_ctx);
2174 
2175 done:
2176 
2177 	return status;
2178 }
2179 
2180 bool mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev *vdev,
2181 				  struct csa_offload_params *csa_param)
2182 {
2183 	struct wlan_mlo_sta *sta_ctx;
2184 	struct wlan_mlo_dev_context *mlo_dev_ctx;
2185 	uint8_t link_id;
2186 	int i;
2187 	bool handled = false;
2188 
2189 	if (!vdev) {
2190 		mlo_err("invalid vdev");
2191 		goto done;
2192 	}
2193 	link_id = wlan_vdev_get_link_id(vdev);
2194 	mlo_dev_ctx = vdev->mlo_dev_ctx;
2195 	if (!mlo_dev_ctx) {
2196 		mlo_err("invalid mlo_dev_ctx");
2197 		goto done;
2198 	}
2199 	mlo_dev_lock_acquire(mlo_dev_ctx);
2200 	sta_ctx = mlo_dev_ctx->sta_ctx;
2201 	if (!sta_ctx) {
2202 		mlo_err("invalid sta_ctx");
2203 		goto rel_lock;
2204 	}
2205 
2206 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
2207 		if (link_id == sta_ctx->mlo_csa_param[i].link_id &&
2208 		    (sta_ctx->mlo_csa_param[i].valid_csa_param ||
2209 		     sta_ctx->mlo_csa_param[i].mlo_csa_synced))
2210 			break;
2211 	}
2212 
2213 	if (i >= QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param)) {
2214 		mlo_debug("mlo csa synced does not happen before csa FW event");
2215 		goto rel_lock;
2216 	}
2217 	if (!sta_ctx->mlo_csa_param[i].csa_offload_event_recvd) {
2218 		sta_ctx->mlo_csa_param[i].csa_offload_event_recvd = true;
2219 		if (sta_ctx->mlo_csa_param[i].valid_csa_param &&
2220 		    !qdf_mem_cmp(&sta_ctx->mlo_csa_param[i].csa_param,
2221 				 csa_param, sizeof(*csa_param)))
2222 			handled = true;
2223 	}
2224 
2225 rel_lock:
2226 	mlo_dev_lock_release(mlo_dev_ctx);
2227 
2228 done:
2229 
2230 	return handled;
2231 }
2232 
2233 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
2234 void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev)
2235 {
2236 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
2237 	struct wlan_mlo_sta *sta_ctx = NULL;
2238 	uint8_t i;
2239 	struct wlan_objmgr_vdev *assoc_vdev;
2240 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
2241 	uint16_t vdev_count = 0;
2242 
2243 	if (!vdev)
2244 		return;
2245 
2246 	if (!wlan_vdev_mlme_is_assoc_sta_vdev(vdev) &&
2247 	    !wlan_mlo_mgr_is_link_switch_on_assoc_vdev(vdev)) {
2248 		mlo_debug("Not an assoc vdev, so ignore disconnect req");
2249 		return;
2250 	}
2251 
2252 	mlo_dev_ctx = vdev->mlo_dev_ctx;
2253 	if (mlo_dev_ctx) {
2254 		sta_ctx = mlo_dev_ctx->sta_ctx;
2255 	} else {
2256 		mlo_err("Invalid mlo_dev_ctx");
2257 		return;
2258 	}
2259 
2260 	if (sta_ctx) {
2261 		mlo_free_copied_conn_req(sta_ctx);
2262 	} else {
2263 		mlo_err("Invalid sta_ctx");
2264 		return;
2265 	}
2266 
2267 	if (sta_ctx->connect_req) {
2268 		wlan_cm_free_connect_req(sta_ctx->connect_req);
2269 		sta_ctx->connect_req = NULL;
2270 	}
2271 
2272 	assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
2273 	if (!assoc_vdev) {
2274 		assoc_vdev = wlan_mlo_mgr_link_switch_get_assoc_vdev(vdev);
2275 		if (!assoc_vdev) {
2276 			mlo_debug("Couldn't get assoc vdev");
2277 			return;
2278 		}
2279 		mlo_release_vdev_ref(assoc_vdev);
2280 	}
2281 
2282 	mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
2283 	for (i =  0; i < vdev_count; i++) {
2284 		if (wlan_vdev_list[i] != assoc_vdev &&
2285 		    (wlan_cm_is_vdev_connected(wlan_vdev_list[i]) ||
2286 		     wlan_cm_is_vdev_connecting(wlan_vdev_list[i])))
2287 			wlan_cm_disconnect(wlan_vdev_list[i],
2288 					   CM_MLO_LINK_VDEV_DISCONNECT,
2289 					   REASON_UNSPEC_FAILURE,
2290 					   NULL);
2291 		mlo_release_vdev_ref(wlan_vdev_list[i]);
2292 	}
2293 }
2294 #else
2295 void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev)
2296 {
2297 }
2298 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
2299 
2300 void mlo_sta_get_vdev_list(struct wlan_objmgr_vdev *vdev, uint16_t *vdev_count,
2301 			   struct wlan_objmgr_vdev **wlan_vdev_list)
2302 {
2303 	struct wlan_mlo_dev_context *dev_ctx;
2304 	int i;
2305 	QDF_STATUS status;
2306 
2307 	*vdev_count = 0;
2308 
2309 	if (!vdev || !vdev->mlo_dev_ctx) {
2310 		mlo_err("Invalid input");
2311 		return;
2312 	}
2313 
2314 	dev_ctx = vdev->mlo_dev_ctx;
2315 
2316 	mlo_dev_lock_acquire(dev_ctx);
2317 	*vdev_count = 0;
2318 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
2319 		if (dev_ctx->wlan_vdev_list[i]) {
2320 			status =
2321 			wlan_objmgr_vdev_try_get_ref(dev_ctx->wlan_vdev_list[i],
2322 						     WLAN_MLO_MGR_ID);
2323 			if (QDF_IS_STATUS_ERROR(status))
2324 				break;
2325 			wlan_vdev_list[*vdev_count] =
2326 				dev_ctx->wlan_vdev_list[i];
2327 			(*vdev_count) += 1;
2328 		}
2329 	}
2330 	mlo_dev_lock_release(dev_ctx);
2331 }
2332 
2333 bool mlo_sta_vdev_get_reconfig_timer_state(struct wlan_objmgr_vdev *vdev)
2334 {
2335 	struct vdev_mlme_obj *vdev_mlme;
2336 
2337 	if (!vdev || !mlo_is_mld_sta(vdev))
2338 		return false;
2339 
2340 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
2341 	if (!vdev_mlme) {
2342 		mlo_err("vdev mlme is null");
2343 		return false;
2344 	}
2345 
2346 	return vdev_mlme->ml_reconfig_started;
2347 }
2348 
2349 void mlo_sta_stop_reconfig_timer_by_vdev(struct wlan_objmgr_vdev *vdev)
2350 {
2351 	struct vdev_mlme_obj *vdev_mlme;
2352 
2353 	if (!vdev || !mlo_is_mld_sta(vdev))
2354 		return;
2355 
2356 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
2357 	if (!vdev_mlme) {
2358 		mlo_err("vdev mlme is null");
2359 		return;
2360 	}
2361 
2362 	if (!vdev_mlme->ml_reconfig_started)
2363 		return;
2364 
2365 	qdf_timer_stop(&vdev_mlme->ml_reconfig_timer);
2366 
2367 	mlo_debug("vdev %d reconfig timer active to stop",
2368 		  wlan_vdev_get_id(vdev));
2369 	vdev_mlme->ml_reconfig_started = false;
2370 }
2371 
2372 void mlo_sta_stop_reconfig_timer(struct wlan_objmgr_vdev *vdev)
2373 {
2374 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0};
2375 	uint16_t vdev_count = 0;
2376 	uint8_t i;
2377 
2378 	if (!vdev || !mlo_is_mld_sta(vdev))
2379 		return;
2380 
2381 	mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
2382 	if (!vdev_count) {
2383 		mlo_err("vdev num 0 in mld dev");
2384 		return;
2385 	}
2386 
2387 	for (i = 0; i < vdev_count; i++) {
2388 		if (!wlan_vdev_list[i]) {
2389 			mlo_err("vdev is null in mld");
2390 			goto release_ref;
2391 		}
2392 		mlo_sta_stop_reconfig_timer_by_vdev(wlan_vdev_list[i]);
2393 	}
2394 
2395 release_ref:
2396 	for (i = 0; i < vdev_count; i++)
2397 		mlo_release_vdev_ref(wlan_vdev_list[i]);
2398 }
2399 
2400 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
2401 void mlo_defer_set_keys(struct wlan_objmgr_vdev *vdev,
2402 			uint8_t link_id, bool value)
2403 {
2404 	struct wlan_mlo_sta *sta_ctx;
2405 	uint8_t link_iter;
2406 
2407 	if (!vdev || !vdev->mlo_dev_ctx)
2408 		return;
2409 
2410 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
2411 	if (!sta_ctx)
2412 		return;
2413 	if (value) {
2414 		for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS;
2415 		     link_iter++) {
2416 			if (sta_ctx->key_mgmt[link_iter].keys_saved &&
2417 			    sta_ctx->key_mgmt[link_iter].link_id == link_id)
2418 				return;
2419 		}
2420 
2421 		for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS;
2422 		     link_iter++) {
2423 			if (!sta_ctx->key_mgmt[link_iter].keys_saved) {
2424 				sta_ctx->key_mgmt[link_iter].link_id = link_id;
2425 				sta_ctx->key_mgmt[link_iter].keys_saved = true;
2426 				mlo_debug("set key link id %d value %d iter %d",
2427 					  link_id, value, link_iter);
2428 				return;
2429 			}
2430 		}
2431 	} else {
2432 		for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS;
2433 		     link_iter++) {
2434 			if (sta_ctx->key_mgmt[link_iter].link_id == link_id) {
2435 				sta_ctx->key_mgmt[link_iter].keys_saved = false;
2436 				mlo_debug("set key link id %d value %d iter %d",
2437 					  link_id, value, link_iter);
2438 				return;
2439 			}
2440 		}
2441 	}
2442 }
2443 
2444 bool mlo_is_set_key_defered(struct wlan_objmgr_vdev *vdev,
2445 			    uint8_t link_id)
2446 {
2447 	struct wlan_mlo_sta *sta_ctx;
2448 	uint8_t link_iter;
2449 
2450 	if (!vdev || !vdev->mlo_dev_ctx)
2451 		return false;
2452 
2453 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
2454 	if (!sta_ctx)
2455 		return false;
2456 
2457 	for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS;
2458 	     link_iter++) {
2459 		if (sta_ctx->key_mgmt[link_iter].link_id == link_id)
2460 			return sta_ctx->key_mgmt[link_iter].keys_saved;
2461 	}
2462 	return false;
2463 }
2464 #endif
2465 
2466 static uint16_t
2467 mlo_get_bcn_interval_by_bssid(struct wlan_objmgr_pdev *pdev,
2468 			      uint8_t *bssid)
2469 {
2470 	struct scan_filter *scan_filter;
2471 	uint16_t bcn_int = 0;
2472 	qdf_list_t *list = NULL;
2473 	struct scan_cache_node *first_node = NULL;
2474 	qdf_list_node_t *cur_node = NULL;
2475 
2476 	scan_filter = qdf_mem_malloc(sizeof(*scan_filter));
2477 	if (!scan_filter)
2478 		return bcn_int;
2479 
2480 	scan_filter->num_of_bssid = 1;
2481 	qdf_mem_copy(scan_filter->bssid_list[0].bytes,
2482 		     bssid, sizeof(struct qdf_mac_addr));
2483 	list = wlan_scan_get_result(pdev, scan_filter);
2484 	qdf_mem_free(scan_filter);
2485 
2486 	if (!list || (list && !qdf_list_size(list))) {
2487 		mlo_debug("scan list empty");
2488 		goto error;
2489 	}
2490 
2491 	qdf_list_peek_front(list, &cur_node);
2492 	first_node = qdf_container_of(cur_node,
2493 				      struct scan_cache_node,
2494 				      node);
2495 	if (first_node && first_node->entry)
2496 		bcn_int = first_node->entry->bcn_int;
2497 error:
2498 	if (list)
2499 		wlan_scan_purge_results(list);
2500 
2501 	return bcn_int;
2502 }
2503 
2504 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE
2505 static QDF_STATUS
2506 mlo_sta_handle_ptqm_migration(struct wlan_objmgr_vdev *removal_vdev)
2507 {
2508 	struct wlan_objmgr_peer *bss_peer;
2509 
2510 	if (!wlan_cm_is_vdev_connected(removal_vdev))
2511 		return QDF_STATUS_E_INVAL;
2512 
2513 	bss_peer = wlan_vdev_get_bsspeer(removal_vdev);
2514 	if (!bss_peer)
2515 		return QDF_STATUS_E_INVAL;
2516 
2517 	/* Invoke migration only if the link being removed is the primary */
2518 	if (wlan_mlo_peer_get_primary_peer_link_id(bss_peer)
2519 		!= wlan_vdev_get_link_id(removal_vdev))
2520 		return QDF_STATUS_SUCCESS;
2521 
2522 	return wlan_mlo_set_ptqm_migration(removal_vdev, bss_peer->mlo_peer_ctx,
2523 					   false, WLAN_LINK_ID_INVALID, true);
2524 }
2525 #else
2526 static QDF_STATUS
2527 mlo_sta_handle_ptqm_migration(struct wlan_objmgr_vdev *removal_vdev)
2528 {
2529 	return QDF_STATUS_SUCCESS;
2530 }
2531 #endif
2532 
2533 static void mlo_process_link_remove(struct wlan_objmgr_vdev *vdev,
2534 				    struct ml_rv_partner_link_info *link_info)
2535 {
2536 	struct vdev_mlme_obj *vdev_mlme = NULL;
2537 	struct wlan_objmgr_peer *bss_peer = NULL;
2538 	uint16_t bcn_int = 0;
2539 	uint16_t tbtt_count = 0;
2540 	QDF_STATUS status;
2541 
2542 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
2543 	if (!vdev_mlme)
2544 		return;
2545 
2546 	bss_peer = wlan_vdev_get_bsspeer(vdev);
2547 	if (!bss_peer)
2548 		return;
2549 
2550 	/* Link delete triggered from AP,
2551 	 * start timer with tbtt count * beacon interval
2552 	 */
2553 	tbtt_count = link_info->ap_removal_timer;
2554 	bcn_int = mlo_get_bcn_interval_by_bssid(
2555 			wlan_vdev_get_pdev(vdev),
2556 			wlan_peer_get_macaddr(bss_peer));
2557 	if (!bcn_int)
2558 		return;
2559 
2560 	if (vdev_mlme->ops &&
2561 	    vdev_mlme->ops->mlme_vdev_reconfig_notify) {
2562 		status = vdev_mlme->ops->mlme_vdev_reconfig_notify(
2563 				vdev_mlme, &tbtt_count, bcn_int);
2564 		if (QDF_IS_STATUS_ERROR(status))
2565 			return;
2566 	}
2567 
2568 	/* Handle PTQM migration upon seeing AP removal for the first time */
2569 	if (!vdev_mlme->ml_reconfig_started)
2570 		mlo_sta_handle_ptqm_migration(vdev);
2571 
2572 	vdev_mlme->ml_reconfig_started = true;
2573 	qdf_timer_mod(&vdev_mlme->ml_reconfig_timer,
2574 		      qdf_time_uint_to_ms(tbtt_count * bcn_int));
2575 }
2576 
2577 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
2578 static inline
2579 QDF_STATUS mlo_process_link_add(struct wlan_objmgr_psoc *psoc,
2580 				struct wlan_objmgr_vdev *vdev,
2581 				struct mlo_partner_info *cache_partner_info,
2582 				struct mlo_partner_info *partner_info,
2583 				uint16_t vdev_count)
2584 {
2585 	return QDF_STATUS_E_INVAL;
2586 }
2587 #else
2588 static
2589 QDF_STATUS mlo_process_link_add(struct wlan_objmgr_psoc *psoc,
2590 				struct wlan_objmgr_vdev *vdev,
2591 				struct mlo_partner_info *cache_partner_info,
2592 				struct mlo_partner_info *partner_info,
2593 				uint16_t vdev_count)
2594 {
2595 	struct wlan_mlo_dev_context *ml_ctx = vdev->mlo_dev_ctx;
2596 
2597 	/* Check if ini to support dynamic link add is enable
2598 	 * or not
2599 	 */
2600 	if (!mlme_mlo_is_reconfig_reassoc_enable(psoc)) {
2601 		mlo_debug("ML Reconfig link add support disabled");
2602 		return QDF_STATUS_E_INVAL;
2603 	}
2604 
2605 	if (vdev_count == ml_ctx->wlan_vdev_count) {
2606 		/* All links are participating in current ML connection */
2607 		return QDF_STATUS_E_INVAL;
2608 	}
2609 
2610 	/* check if any new link in scan entry */
2611 	if (partner_info->num_partner_links ==
2612 	    cache_partner_info->num_partner_links) {
2613 		if (!qdf_mem_cmp(cache_partner_info, partner_info,
2614 				 sizeof(struct mlo_partner_info))) {
2615 			mlo_debug("No new link found");
2616 			return QDF_STATUS_E_INVAL;
2617 		}
2618 	}
2619 
2620 	/* mlo connected on all links already */
2621 	if (partner_info->num_partner_links <= (vdev_count - 1))
2622 		return QDF_STATUS_E_INVAL;
2623 
2624 	/* Partner info changed compared to the cached scan entry.
2625 	 * Process link add
2626 	 */
2627 	mlo_err("Link addition detected, issue disconnect");
2628 	mlo_disconnect(vdev, CM_SB_DISCONNECT,
2629 		       REASON_UNSPEC_FAILURE, NULL);
2630 	return QDF_STATUS_SUCCESS;
2631 }
2632 #endif
2633 
2634 void mlo_process_ml_reconfig_ie(struct wlan_objmgr_vdev *vdev,
2635 				struct scan_cache_entry *scan_entry,
2636 				uint8_t *ml_ie, qdf_size_t ml_ie_len,
2637 				struct mlo_partner_info *partner_info)
2638 {
2639 	struct wlan_objmgr_psoc *psoc = NULL;
2640 	struct wlan_objmgr_pdev *pdev = NULL;
2641 	struct wlan_objmgr_vdev *co_mld_vdev = NULL;
2642 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
2643 	uint16_t vdev_count = 0;
2644 	uint8_t idx = 0;
2645 	uint8_t i = 0;
2646 	uint8_t link_ix = 0;
2647 	struct ml_rv_info reconfig_info = {0};
2648 	struct mlo_partner_info ml_partner_info = {0};
2649 	uint8_t *ml_rv_ie = NULL;
2650 	qdf_size_t ml_rv_ie_len = 0;
2651 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2652 
2653 	if (!vdev || !mlo_is_mld_sta(vdev))
2654 		return;
2655 
2656 	pdev = wlan_vdev_get_pdev(vdev);
2657 	if (!pdev)
2658 		return;
2659 
2660 	psoc = wlan_pdev_get_psoc(pdev);
2661 	if (!psoc)
2662 		return;
2663 
2664 	mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
2665 	if (!vdev_count) {
2666 		mlo_debug("Number of VDEVs under MLD is reported as 0");
2667 		return;
2668 	}
2669 
2670 	if (!scan_entry ||
2671 	    QDF_IS_STATUS_ERROR(util_scan_get_ml_partner_info(scan_entry,
2672 							      &ml_partner_info))) {
2673 		mlo_debug("Unable to fetch the partner info in scan db");
2674 		goto check_ml_rv;
2675 	}
2676 
2677 	/* Processing for link add */
2678 	if (QDF_IS_STATUS_SUCCESS(mlo_process_link_add(psoc, vdev,
2679 						       partner_info,
2680 						       &ml_partner_info,
2681 						       vdev_count))) {
2682 		mlo_err("Issued MLD disconnect for link add");
2683 		goto err_release_refs;
2684 	}
2685 
2686 check_ml_rv:
2687 	/* Processing for ML Reconfig IE */
2688 	if (vdev_count == 1) {
2689 		/* Single link MLO, no need to process link delete */
2690 		goto err_release_refs;
2691 	}
2692 
2693 	status = util_find_mlie_by_variant(ml_ie,
2694 					   ml_ie_len,
2695 					   &ml_rv_ie,
2696 					   &ml_rv_ie_len,
2697 					   WLAN_ML_VARIANT_RECONFIG);
2698 	if (QDF_IS_STATUS_ERROR(status) || !ml_rv_ie) {
2699 		mlo_debug("ML IE for reconfig variant not found");
2700 		goto err_release_refs;
2701 	}
2702 
2703 	status = util_get_rvmlie_persta_link_info(ml_rv_ie, ml_rv_ie_len,
2704 						  &reconfig_info);
2705 	if (QDF_IS_STATUS_ERROR(status)) {
2706 		mlo_err("Unable to get persta link info from ML RV IE");
2707 		goto err_release_refs;
2708 	}
2709 
2710 	if (!reconfig_info.num_links) {
2711 		mlo_err("No. of links is 0 in ML reconfig IE");
2712 		goto err_release_refs;
2713 	}
2714 
2715 	for (idx = 0; idx < vdev_count; idx++) {
2716 		co_mld_vdev = wlan_vdev_list[idx];
2717 		if (!co_mld_vdev) {
2718 			mlo_debug("VDEV in MLD VDEV list is NULL");
2719 			goto err_release_refs;
2720 		}
2721 
2722 		link_ix = wlan_vdev_get_link_id(co_mld_vdev);
2723 		for (i = 0; i < reconfig_info.num_links; i++) {
2724 			if (link_ix == reconfig_info.link_info[i].link_id)
2725 				mlo_process_link_remove(co_mld_vdev,
2726 							&reconfig_info.link_info[i]);
2727 		}
2728 	}
2729 
2730 	mlo_sta_handle_link_reconfig_standby_link(vdev, &reconfig_info);
2731 
2732 err_release_refs:
2733 
2734 	for (i = 0; i < vdev_count; i++)
2735 		mlo_release_vdev_ref(wlan_vdev_list[i]);
2736 }
2737 
2738 QDF_STATUS
2739 mlo_get_link_state_context(struct wlan_objmgr_psoc *psoc,
2740 			   get_ml_link_state_cb *resp_cb,
2741 			   void **context, uint8_t vdev_id)
2742 {
2743 	struct wlan_mlo_dev_context *mlo_ctx;
2744 	struct wlan_mlo_sta *sta_ctx = NULL;
2745 	struct wlan_objmgr_vdev *vdev;
2746 
2747 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
2748 						    WLAN_MLO_MGR_ID);
2749 	if (!vdev)
2750 		return QDF_STATUS_E_NULL_VALUE;
2751 
2752 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
2753 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
2754 		return QDF_STATUS_E_NULL_VALUE;
2755 	}
2756 
2757 	mlo_ctx = vdev->mlo_dev_ctx;
2758 
2759 	if (!mlo_ctx) {
2760 		mlo_err("null mlo_dev_ctx");
2761 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
2762 		return QDF_STATUS_E_NULL_VALUE;
2763 	}
2764 
2765 	sta_ctx = mlo_ctx->sta_ctx;
2766 
2767 	if (!sta_ctx) {
2768 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
2769 		return QDF_STATUS_E_INVAL;
2770 	}
2771 
2772 	mlo_dev_lock_acquire(mlo_ctx);
2773 	*resp_cb = sta_ctx->ml_link_state.ml_link_state_resp_cb;
2774 	*context = sta_ctx->ml_link_state.ml_link_state_req_context;
2775 
2776 	mlo_dev_lock_release(mlo_ctx);
2777 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
2778 	return QDF_STATUS_SUCCESS;
2779 }
2780 
2781 void
2782 wlan_mlo_send_vdev_pause(struct wlan_objmgr_psoc *psoc,
2783 			 struct wlan_objmgr_vdev *vdev,
2784 			 uint16_t session_id,
2785 			 uint16_t vdev_pause_dur)
2786 {
2787 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
2788 	struct mlo_vdev_pause vdev_pause_info;
2789 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
2790 
2791 	mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
2792 	if (!mlo_tx_ops) {
2793 		mlo_err("tx_ops is null!");
2794 		return;
2795 	}
2796 
2797 	if (!mlo_tx_ops->send_vdev_pause) {
2798 		mlo_err("send_vdev_pause is null");
2799 		return;
2800 	}
2801 
2802 	vdev_pause_info.vdev_id = session_id;
2803 	vdev_pause_info.vdev_pause_duration = vdev_pause_dur;
2804 	status = mlo_tx_ops->send_vdev_pause(psoc, &vdev_pause_info);
2805 	if (QDF_IS_STATUS_ERROR(status))
2806 		mlo_err("Failed to send vdev pause to FW");
2807 }
2808 
2809 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
2810 bool mlo_is_any_link_disconnecting(struct wlan_objmgr_vdev *vdev)
2811 {
2812 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
2813 	uint16_t vdev_count = 0, i;
2814 	bool status = false;
2815 
2816 	if (!vdev)
2817 		return status;
2818 
2819 	mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
2820 	for (i =  0; i < vdev_count; i++) {
2821 		if (!status && wlan_cm_is_vdev_disconnecting(wlan_vdev_list[i]))
2822 			status = true;
2823 		mlo_release_vdev_ref(wlan_vdev_list[i]);
2824 	}
2825 
2826 	return status;
2827 }
2828 #endif
2829 #endif
2830