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