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