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