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