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