xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_sta.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
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 " vdev_id:%d",
531 		  QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
532 		  wlan_vdev_get_id(vdev));
533 
534 	qdf_mem_copy(&req, sta_ctx->copied_conn_req,
535 		     sizeof(struct wlan_cm_connect_req));
536 
537 	mlo_update_connect_req_chan_info(&req);
538 
539 	qdf_mem_copy(req.bssid.bytes,
540 		     link_info.link_addr.bytes,
541 		     QDF_MAC_ADDR_SIZE);
542 
543 	qdf_mem_copy(&req.ml_parnter_info,
544 		     &ml_parnter_info,
545 		     sizeof(struct mlo_partner_info));
546 
547 	req.ssid.length = ssid.length;
548 	qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length);
549 
550 	mlo_allocate_and_copy_ies(&req, sta_ctx->copied_conn_req);
551 	if (!req.assoc_ie.ptr)
552 		mlo_err("Failed to allocate assoc IEs");
553 
554 	if (!req.scan_ie.ptr)
555 		mlo_err("Failed to allocate scan IEs");
556 
557 	/* Reset crypto auth type for partner link.
558 	 * It will be set based on partner scan cache entry
559 	 */
560 	req.crypto.auth_type = 0;
561 
562 	wlan_cm_start_connect(vdev, &req);
563 	mlo_free_connect_ies(&req);
564 }
565 
566 /**
567  * mlo_send_link_connect- Create/Issue the connection on secondary link
568  *
569  * @vdev: vdev pointer
570  * @mlo_dev_ctx: ml dev context
571  * @assoc_rsp: assoc response
572  * @ml_parnter_info: ml partner link info
573  *
574  * Return: none
575  */
576 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
577 static void
578 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev,
579 		      struct wlan_mlo_dev_context *mlo_dev_ctx,
580 		      struct element_info *assoc_rsp,
581 		      struct mlo_partner_info *ml_parnter_info)
582 {
583 	/* Create the secondary interface, Send keys if the last link */
584 	uint8_t i, partner_idx = 0;
585 	struct wlan_ssid ssid = {0};
586 
587 	mlo_debug("Sending link connect on partner interface");
588 	wlan_vdev_mlme_get_ssid(
589 			vdev, ssid.ssid,
590 			&ssid.length);
591 
592 	if (!ml_parnter_info->num_partner_links) {
593 		mlo_err("No partner info in connect resp");
594 		return;
595 	}
596 
597 	if(wlan_vdev_mlme_is_mlo_link_vdev(vdev))
598 		return;
599 
600 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
601 		if (!mlo_dev_ctx->wlan_vdev_list[i] ||
602 		    (mlo_dev_ctx->wlan_vdev_list[i] == vdev))
603 			continue;
604 		wlan_vdev_mlme_set_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]);
605 		wlan_vdev_mlme_feat_ext2_cap_set(mlo_dev_ctx->wlan_vdev_list[i],
606 						 WLAN_VDEV_FEXT2_MLO_STA_LINK);
607 		wlan_vdev_set_link_id(
608 		      mlo_dev_ctx->wlan_vdev_list[i],
609 		      ml_parnter_info->partner_link_info[partner_idx].link_id);
610 		ml_parnter_info->partner_link_info[partner_idx].vdev_id =
611 			       wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
612 		mlo_prepare_and_send_connect(
613 				mlo_dev_ctx->wlan_vdev_list[i],
614 				*ml_parnter_info,
615 				ml_parnter_info->partner_link_info[partner_idx],
616 				ssid);
617 		mlo_update_connected_links(mlo_dev_ctx->wlan_vdev_list[i], 1);
618 		partner_idx++;
619 	}
620 }
621 #else
622 static void
623 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev,
624 		      struct wlan_mlo_dev_context *mlo_dev_ctx,
625 		      struct element_info *assoc_rsp,
626 		      struct mlo_partner_info *ml_parnter_info)
627 {
628 	struct wlan_ssid ssid = {0};
629 	uint8_t i = 0;
630 	uint8_t j = 0;
631 
632 	if (!ml_parnter_info->num_partner_links) {
633 		mlo_err("No partner info in connect resp");
634 		return;
635 	}
636 
637 	mlo_dev_lock_acquire(mlo_dev_ctx);
638 	if (wlan_cm_is_vdev_connected(vdev)) {
639 		for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
640 			if (!mlo_dev_ctx->wlan_vdev_list[i])
641 				continue;
642 			/*
643 			 * mlo_connect: update wlan_connected_links bitmap from
644 			 * assoc resp parsing
645 			 */
646 			if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
647 				if (wlan_cm_is_vdev_disconnected(
648 					mlo_dev_ctx->wlan_vdev_list[i])) {
649 					for (j = 0; j < ml_parnter_info->num_partner_links; j++) {
650 						if (mlo_dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id ==
651 							ml_parnter_info->partner_link_info[j].link_id)
652 							break;
653 					}
654 					if (j < ml_parnter_info->num_partner_links) {
655 						wlan_vdev_mlme_get_ssid(
656 							vdev, ssid.ssid,
657 							&ssid.length);
658 						mlo_prepare_and_send_connect(
659 							mlo_dev_ctx->wlan_vdev_list[i],
660 							*ml_parnter_info,
661 							ml_parnter_info->partner_link_info[j],
662 							ssid);
663 					}
664 					mlo_dev_lock_release(mlo_dev_ctx);
665 					return;
666 				}
667 			}
668 		}
669 	}
670 	mlo_dev_lock_release(mlo_dev_ctx);
671 }
672 #endif
673 
674 void
675 mlo_update_connected_links_bmap(struct wlan_mlo_dev_context *mlo_dev_ctx,
676 				struct mlo_partner_info ml_parnter_info)
677 {
678 	uint8_t i = 0;
679 	uint8_t j = 0;
680 
681 	if (!mlo_dev_ctx) {
682 		mlo_err("ML dev ctx is NULL");
683 		return;
684 	}
685 
686 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
687 		if (!mlo_dev_ctx->wlan_vdev_list[i])
688 			continue;
689 
690 		for (j = 0; j < ml_parnter_info.num_partner_links; j++) {
691 			if (wlan_vdev_get_link_id(mlo_dev_ctx->wlan_vdev_list[i]) ==
692 			    ml_parnter_info.partner_link_info[j].link_id)
693 				mlo_update_connected_links(
694 					mlo_dev_ctx->wlan_vdev_list[i], 1);
695 		}
696 	}
697 }
698 
699 static QDF_STATUS ml_activate_disconnect_req_sched_cb(struct scheduler_msg *msg)
700 {
701 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
702 
703 	if (!vdev) {
704 		mlme_err("Null input vdev");
705 		return QDF_STATUS_E_INVAL;
706 	}
707 
708 	mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
709 		       REASON_UNSPEC_FAILURE, NULL);
710 
711 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
712 	return QDF_STATUS_SUCCESS;
713 }
714 
715 static QDF_STATUS ml_activate_disconnect_req_flush_cb(struct scheduler_msg *msg)
716 {
717 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
718 
719 	if (!vdev) {
720 		mlme_err("Null input vdev");
721 		return QDF_STATUS_E_INVAL;
722 	}
723 
724 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
725 	return QDF_STATUS_SUCCESS;
726 }
727 
728 static QDF_STATUS ml_activate_pend_disconn_req_cb(struct scheduler_msg *msg)
729 {
730 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
731 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
732 	struct wlan_mlo_sta *sta_ctx = NULL;
733 
734 	if (!vdev) {
735 		mlme_err("Null input vdev");
736 		return QDF_STATUS_E_INVAL;
737 	}
738 
739 	mlo_dev_ctx = vdev->mlo_dev_ctx;
740 	sta_ctx = mlo_dev_ctx->sta_ctx;
741 	mlo_disconnect(vdev, sta_ctx->disconn_req->source,
742 		       sta_ctx->disconn_req->reason_code,
743 		       &sta_ctx->disconn_req->bssid);
744 
745 	qdf_mem_free(sta_ctx->disconn_req);
746 	sta_ctx->disconn_req = NULL;
747 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
748 	return QDF_STATUS_SUCCESS;
749 }
750 
751 static QDF_STATUS ml_activate_pend_disconn_req_flush_cb(
752 					struct scheduler_msg *msg)
753 {
754 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
755 
756 	if (!vdev) {
757 		mlme_err("Null input vdev");
758 		return QDF_STATUS_E_INVAL;
759 	}
760 
761 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
762 	return QDF_STATUS_SUCCESS;
763 }
764 
765 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
766 static inline
767 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
768 {
769 	return scheduler_post_message(
770 			QDF_MODULE_ID_OS_IF,
771 			QDF_MODULE_ID_SCAN,
772 			QDF_MODULE_ID_OS_IF,
773 			msg);
774 }
775 #else
776 static inline
777 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
778 {
779 	return scheduler_post_message(
780 			QDF_MODULE_ID_MLME,
781 			QDF_MODULE_ID_MLME,
782 			QDF_MODULE_ID_MLME,
783 			msg);
784 }
785 #endif
786 
787 static inline
788 void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev,
789 					 struct wlan_cm_connect_resp *rsp)
790 {
791 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
792 	struct scheduler_msg msg = {0};
793 	QDF_STATUS ret;
794 	struct wlan_objmgr_vdev *assoc_vdev;
795 
796 	if (!mlo_dev_ctx) {
797 		mlo_err("ML dev ctx is NULL");
798 		return;
799 	}
800 
801 	assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
802 	if (!assoc_vdev) {
803 		mlo_err("Assoc Vdev is NULL");
804 		return;
805 	}
806 
807 	if (vdev != assoc_vdev) {
808 		mlo_update_connected_links(vdev, 0);
809 		if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
810 		    rsp->reason == CM_HW_MODE_FAILURE ||
811 		    rsp->reason == CM_SER_FAILURE) {
812 			ret = wlan_objmgr_vdev_try_get_ref(
813 					assoc_vdev, WLAN_MLO_MGR_ID);
814 			if (QDF_IS_STATUS_ERROR(ret)) {
815 				mlo_err("Failed to get ref vdev_id %d",
816 					wlan_vdev_get_id(assoc_vdev));
817 				return;
818 			}
819 			/* Since these failures happen in same context. use
820 			 * scheduler to avoid deadlock by deferring context
821 			 */
822 			msg.bodyptr = assoc_vdev;
823 			msg.callback = ml_activate_disconnect_req_sched_cb;
824 			msg.flush_callback =
825 				ml_activate_disconnect_req_flush_cb;
826 			mlo_post_disconnect_msg(&msg);
827 			if (QDF_IS_STATUS_ERROR(ret)) {
828 				wlan_objmgr_vdev_release_ref(
829 						assoc_vdev,
830 						WLAN_MLO_MGR_ID);
831 				return;
832 			}
833 		} else {
834 			mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
835 				       REASON_UNSPEC_FAILURE, NULL);
836 		}
837 	}
838 }
839 
840 static inline
841 void mlo_handle_pending_disconnect(struct wlan_objmgr_vdev *vdev)
842 {
843 	struct scheduler_msg msg = {0};
844 	QDF_STATUS ret;
845 
846 	ret = wlan_objmgr_vdev_try_get_ref(
847 			vdev, WLAN_MLO_MGR_ID);
848 	if (QDF_IS_STATUS_ERROR(ret)) {
849 		mlo_err("Failed to get ref vdev_id %d",
850 			wlan_vdev_get_id(vdev));
851 		return;
852 	}
853 
854 	msg.bodyptr = vdev;
855 	msg.callback = ml_activate_pend_disconn_req_cb;
856 	msg.flush_callback =
857 		ml_activate_pend_disconn_req_flush_cb;
858 	ret = mlo_post_disconnect_msg(&msg);
859 	if (QDF_IS_STATUS_ERROR(ret)) {
860 		mlo_err("Failed to post scheduler msg");
861 		wlan_objmgr_vdev_release_ref(
862 				vdev,
863 				WLAN_MLO_MGR_ID);
864 		QDF_BUG(0);
865 		return;
866 	}
867 }
868 
869 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
870 				 struct wlan_cm_connect_resp *rsp)
871 {
872 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
873 	struct wlan_mlo_sta *sta_ctx = NULL;
874 
875 	if (mlo_dev_ctx) {
876 		sta_ctx = mlo_dev_ctx->sta_ctx;
877 	} else {
878 		mlo_debug_rl("mlo_dev_ctx is NULL");
879 		return;
880 	}
881 
882 	if (sta_ctx && sta_ctx->disconn_req) {
883 		mlo_debug("Handle pending disocnnect for vdev %d",
884 			  wlan_vdev_get_id(vdev));
885 		mlo_handle_pending_disconnect(vdev);
886 		return;
887 	}
888 
889 	if (wlan_cm_is_vdev_disconnected(vdev)) {
890 		if (sta_ctx) {
891 			copied_conn_req_lock_acquire(sta_ctx);
892 			if (sta_ctx->copied_conn_req) {
893 				mlo_free_connect_ies(sta_ctx->copied_conn_req);
894 				qdf_mem_free(sta_ctx->copied_conn_req);
895 				sta_ctx->copied_conn_req = NULL;
896 			}
897 			copied_conn_req_lock_release(sta_ctx);
898 		}
899 	}
900 
901 	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
902 		mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev));
903 		if (wlan_cm_is_vdev_disconnected(vdev)) {
904 			mlo_handle_sta_link_connect_failure(vdev, rsp);
905 			return;
906 		} else if (!wlan_cm_is_vdev_connected(vdev)) {
907 			/* If vdev is not in disconnected or connected state,
908 			 * then the event is received due to connect req being
909 			 * flushed. Hence, ignore this event
910 			 */
911 			return;
912 		}
913 
914 		if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) && sta_ctx) {
915 			if (sta_ctx->assoc_rsp.ptr) {
916 				qdf_mem_free(sta_ctx->assoc_rsp.ptr);
917 				sta_ctx->assoc_rsp.ptr = NULL;
918 			}
919 			sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len;
920 			sta_ctx->assoc_rsp.ptr =
921 				qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len);
922 			if (!sta_ctx->assoc_rsp.ptr) {
923 				QDF_ASSERT(0);
924 				return;
925 			}
926 			if (rsp->connect_ies.assoc_rsp.ptr)
927 				qdf_mem_copy(sta_ctx->assoc_rsp.ptr,
928 					     rsp->connect_ies.assoc_rsp.ptr,
929 					     rsp->connect_ies.assoc_rsp.len);
930 			/* Update connected_links_bmap for all vdev taking
931 			 * part in association
932 			 */
933 			mlo_update_connected_links(vdev, 1);
934 			mlo_update_connected_links_bmap(mlo_dev_ctx,
935 							rsp->ml_parnter_info);
936 		}
937 		mlo_send_link_connect(vdev, mlo_dev_ctx,
938 				      &rsp->connect_ies.assoc_rsp,
939 				      &rsp->ml_parnter_info);
940 	}
941 }
942 
943 /**
944  * mlo_send_link_disconnect_sync- Issue sync the disconnect request on MLD links
945  *
946  * @mlo_dev_ctx: pointer to mlo dev context
947  * @source: disconnect source
948  * @reason_code: disconnect reason
949  * @bssid: bssid of AP to disconnect, can be null if not known
950  *
951  * Return: QDF_STATUS
952  */
953 static QDF_STATUS
954 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
955 			      enum wlan_cm_source source,
956 			      enum wlan_reason_code reason_code,
957 			      struct qdf_mac_addr *bssid)
958 {
959 	uint8_t i = 0;
960 	struct wlan_objmgr_vdev *assoc_vdev =
961 			mlo_get_assoc_link_vdev(mlo_dev_ctx);
962 
963 	if (!assoc_vdev)
964 		return QDF_STATUS_E_FAILURE;
965 
966 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
967 		if (!mlo_dev_ctx->wlan_vdev_list[i])
968 			continue;
969 
970 		if (mlo_dev_ctx->wlan_vdev_list[i] !=
971 				mlo_get_assoc_link_vdev(mlo_dev_ctx))
972 			wlan_cm_disconnect_sync(mlo_dev_ctx->wlan_vdev_list[i],
973 						source, reason_code);
974 	}
975 
976 	wlan_cm_disconnect_sync(assoc_vdev,
977 				source, reason_code);
978 	return QDF_STATUS_SUCCESS;
979 }
980 
981 QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
982 			  enum wlan_cm_source source,
983 			  enum wlan_reason_code reason_code,
984 			  struct qdf_mac_addr *bssid)
985 {
986 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
987 	struct wlan_mlo_sta *sta_ctx = NULL;
988 	QDF_STATUS status = QDF_STATUS_SUCCESS;
989 
990 	if (!vdev)
991 		return QDF_STATUS_E_FAILURE;
992 
993 	mlo_dev_ctx = vdev->mlo_dev_ctx;
994 	if (mlo_dev_ctx)
995 		sta_ctx = mlo_dev_ctx->sta_ctx;
996 	if (sta_ctx) {
997 		copied_conn_req_lock_acquire(sta_ctx);
998 		if (sta_ctx->copied_conn_req) {
999 			mlo_free_connect_ies(sta_ctx->copied_conn_req);
1000 			qdf_mem_free(sta_ctx->copied_conn_req);
1001 			sta_ctx->copied_conn_req = NULL;
1002 		}
1003 		copied_conn_req_lock_release(sta_ctx);
1004 	}
1005 
1006 	if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1007 		mlo_dev_lock_acquire(mlo_dev_ctx);
1008 		if (sta_ctx && sta_ctx->connect_req) {
1009 			mlo_free_connect_ies(sta_ctx->connect_req);
1010 			qdf_mem_free(sta_ctx->connect_req);
1011 			sta_ctx->connect_req = NULL;
1012 		}
1013 
1014 		status = mlo_validate_disconn_req(vdev, source,
1015 						  reason_code, bssid);
1016 		if (QDF_IS_STATUS_ERROR(status)) {
1017 			mlo_debug("Connect in progress, deferring disconnect");
1018 			mlo_dev_lock_release(mlo_dev_ctx);
1019 			return status;
1020 		}
1021 
1022 		status = mlo_send_link_disconnect(mlo_dev_ctx, source,
1023 						  reason_code, bssid);
1024 		mlo_dev_lock_release(mlo_dev_ctx);
1025 		return status;
1026 	}
1027 	return wlan_cm_disconnect(vdev, source,
1028 				  reason_code, NULL);
1029 }
1030 
1031 QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev,
1032 			       enum wlan_cm_source source,
1033 			       enum wlan_reason_code reason_code,
1034 			       struct qdf_mac_addr *bssid)
1035 {
1036 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1037 	struct wlan_mlo_sta *sta_ctx = NULL;
1038 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1039 
1040 	if (!vdev)
1041 		return QDF_STATUS_E_FAILURE;
1042 
1043 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1044 	if (mlo_dev_ctx)
1045 		sta_ctx = mlo_dev_ctx->sta_ctx;
1046 	if (sta_ctx) {
1047 		copied_conn_req_lock_acquire(sta_ctx);
1048 		if (sta_ctx->copied_conn_req) {
1049 			mlo_free_connect_ies(sta_ctx->copied_conn_req);
1050 			qdf_mem_free(sta_ctx->copied_conn_req);
1051 			sta_ctx->copied_conn_req = NULL;
1052 		}
1053 		copied_conn_req_lock_release(sta_ctx);
1054 	}
1055 
1056 	if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1057 		if (sta_ctx && sta_ctx->connect_req) {
1058 			mlo_free_connect_ies(sta_ctx->connect_req);
1059 			qdf_mem_free(sta_ctx->connect_req);
1060 			sta_ctx->connect_req = NULL;
1061 		}
1062 
1063 		status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source,
1064 						       reason_code, bssid);
1065 
1066 		return status;
1067 	}
1068 	return wlan_cm_disconnect_sync(vdev, source,
1069 				       reason_code);
1070 }
1071 
1072 /**
1073  * mlo_handle_disconnect_resp- Issue desired actions on partner link vdev
1074  *
1075  * @mlo_dev_ctx: pointer to mlo dev context
1076  * @resp: disconnect resp
1077  *
1078  * Return: none
1079  */
1080 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1081 static
1082 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx,
1083 				struct wlan_cm_discon_rsp *resp)
1084 {
1085 /* If it is secondary link then delete vdev object from mlo device. */
1086 	enum wlan_cm_source source;
1087 	enum wlan_reason_code reason_code;
1088 	uint8_t i = 0;
1089 
1090 	mlo_dev_lock_acquire(mlo_dev_ctx);
1091 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1092 		if (!mlo_dev_ctx->wlan_vdev_list[i])
1093 			continue;
1094 
1095 		if (wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) {
1096 			if (wlan_vdev_mlme_is_mlo_link_vdev(
1097 					mlo_dev_ctx->wlan_vdev_list[i])) {
1098 				source = resp->req.req.source;
1099 				reason_code = resp->req.req.reason_code;
1100 				wlan_cm_disconnect(
1101 						mlo_dev_ctx->wlan_vdev_list[i],
1102 						source, reason_code, NULL);
1103 				mlo_dev_lock_release(mlo_dev_ctx);
1104 				return;
1105 			}
1106 		}
1107 	}
1108 	mlo_dev_lock_release(mlo_dev_ctx);
1109 }
1110 #else
1111 static
1112 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx,
1113 				struct wlan_cm_discon_rsp *resp)
1114 { }
1115 
1116 static QDF_STATUS ml_activate_connect_req_sched_cb(struct scheduler_msg *msg)
1117 {
1118 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1119 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1120 	struct wlan_mlo_sta *sta_ctx = NULL;
1121 
1122 	if (!vdev) {
1123 		mlme_err("Null input vdev");
1124 		return QDF_STATUS_E_INVAL;
1125 	}
1126 
1127 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1128 	if (!mlo_dev_ctx) {
1129 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1130 		return QDF_STATUS_E_INVAL;
1131 	}
1132 
1133 	sta_ctx = mlo_dev_ctx->sta_ctx;
1134 	if (!sta_ctx) {
1135 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1136 		return QDF_STATUS_E_INVAL;
1137 	}
1138 
1139 	mlo_connect(vdev, sta_ctx->connect_req);
1140 	mlo_free_connect_ies(sta_ctx->connect_req);
1141 	qdf_mem_free(sta_ctx->connect_req);
1142 	sta_ctx->connect_req = NULL;
1143 
1144 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1145 	return QDF_STATUS_SUCCESS;
1146 }
1147 
1148 static QDF_STATUS ml_activate_connect_req_flush_cb(struct scheduler_msg *msg)
1149 {
1150 	struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1151 
1152 	if (!vdev) {
1153 		mlme_err("Null input vdev");
1154 		return QDF_STATUS_E_INVAL;
1155 	}
1156 
1157 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1158 	return QDF_STATUS_SUCCESS;
1159 }
1160 #endif
1161 
1162 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1163 static inline
1164 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
1165 { }
1166 #else
1167 static inline
1168 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
1169 {
1170 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1171 	struct wlan_objmgr_vdev *tmp_vdev;
1172 	struct scheduler_msg msg = {0};
1173 	QDF_STATUS ret;
1174 	struct wlan_mlo_sta *sta_ctx = NULL;
1175 	uint8_t i = 0;
1176 	struct mlo_partner_info partner_info;
1177 	struct mlo_link_info partner_link_info;
1178 
1179 	if (!mlo_dev_ctx) {
1180 		mlo_err("ML dev ctx is null");
1181 		return;
1182 	}
1183 	sta_ctx = mlo_dev_ctx->sta_ctx;
1184 	ret = wlan_objmgr_vdev_try_get_ref(
1185 			vdev,
1186 			WLAN_MLO_MGR_ID);
1187 	if (QDF_IS_STATUS_ERROR(ret)) {
1188 		mlo_free_connect_ies(sta_ctx->connect_req);
1189 		qdf_mem_free(sta_ctx->connect_req);
1190 		sta_ctx->connect_req = NULL;
1191 		return;
1192 	}
1193 	msg.bodyptr = vdev;
1194 	msg.callback = ml_activate_connect_req_sched_cb;
1195 	msg.flush_callback = ml_activate_connect_req_flush_cb;
1196 
1197 	ret = scheduler_post_message(QDF_MODULE_ID_MLME,
1198 				     QDF_MODULE_ID_MLME,
1199 				     QDF_MODULE_ID_MLME, &msg);
1200 	if (QDF_IS_STATUS_ERROR(ret)) {
1201 		mlo_free_connect_ies(sta_ctx->connect_req);
1202 		qdf_mem_free(sta_ctx->connect_req);
1203 		sta_ctx->connect_req = NULL;
1204 		wlan_objmgr_vdev_release_ref(vdev,
1205 					     WLAN_MLO_MGR_ID);
1206 		return;
1207 	}
1208 
1209 	if (sta_ctx->connect_req->ml_parnter_info.num_partner_links) {
1210 		partner_info = sta_ctx->connect_req->ml_parnter_info;
1211 		wlan_vdev_mlme_set_mlo_vdev(vdev);
1212 		wlan_vdev_mlme_feat_ext2_cap_clear(
1213 				vdev, WLAN_VDEV_FEXT2_MLO_STA_LINK);
1214 		mlo_clear_connect_req_links_bmap(vdev);
1215 		mlo_update_connect_req_links(vdev, 1);
1216 		for (i = 0; i < partner_info.num_partner_links; i++) {
1217 			partner_link_info = partner_info.partner_link_info[i];
1218 			tmp_vdev = mlo_get_ml_vdev_by_mac(
1219 					vdev,
1220 					&partner_link_info.link_addr);
1221 			if (tmp_vdev) {
1222 				mlo_update_connect_req_links(tmp_vdev, 1);
1223 				wlan_vdev_mlme_set_mlo_vdev(tmp_vdev);
1224 				wlan_vdev_mlme_feat_ext2_cap_set(
1225 						tmp_vdev,
1226 						WLAN_VDEV_FEXT2_MLO_STA_LINK);
1227 				wlan_vdev_set_link_id(
1228 					tmp_vdev,
1229 					partner_link_info.link_id);
1230 			}
1231 		}
1232 	}
1233 }
1234 #endif
1235 
1236 void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev,
1237 				 struct wlan_cm_discon_rsp *resp)
1238 {
1239 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1240 	struct wlan_mlo_sta *sta_ctx = NULL;
1241 	struct wlan_objmgr_vdev *assoc_vdev = NULL;
1242 
1243 	if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev)))
1244 		return;
1245 
1246 	sta_ctx = mlo_dev_ctx->sta_ctx;
1247 	if (!sta_ctx)
1248 		return;
1249 
1250 	if (!wlan_cm_is_vdev_disconnected(vdev))
1251 		return;
1252 
1253 	mlo_update_connected_links(vdev, 0);
1254 	if (mlo_is_mld_disconnected(vdev)) {
1255 		if (sta_ctx->connect_req) {
1256 			assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
1257 			if (!assoc_vdev)
1258 				return;
1259 			mlo_sta_link_handle_pending_connect(assoc_vdev);
1260 		}
1261 	}
1262 
1263 	mlo_handle_disconnect_resp(mlo_dev_ctx, resp);
1264 }
1265 
1266 bool mlo_is_mld_sta(struct wlan_objmgr_vdev *vdev)
1267 {
1268 	if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) &&
1269 	    wlan_vdev_mlme_is_mlo_vdev(vdev))
1270 		return true;
1271 
1272 	return false;
1273 }
1274 
1275 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1276 struct wlan_objmgr_vdev *
1277 mlo_get_ml_vdev_by_mac(struct wlan_objmgr_vdev *vdev,
1278 		       struct qdf_mac_addr *macaddr)
1279 {
1280 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1281 	uint8_t i = 0;
1282 
1283 	if (!mlo_dev_ctx)
1284 		return NULL;
1285 
1286 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1287 		if (!mlo_dev_ctx->wlan_vdev_list[i])
1288 			continue;
1289 
1290 		if(qdf_mem_cmp(macaddr,
1291 			       wlan_vdev_mlme_get_macaddr(mlo_dev_ctx->wlan_vdev_list[i]),
1292 			       QDF_MAC_ADDR_SIZE) == 0) {
1293 			return mlo_dev_ctx->wlan_vdev_list[i];
1294 		}
1295 	}
1296 	return NULL;
1297 }
1298 #endif
1299 
1300 qdf_freq_t
1301 mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev *pdev,
1302 			   struct qdf_mac_addr *bssid)
1303 {
1304 	struct scan_filter *scan_filter;
1305 	int8_t ch_freq = 0;
1306 	qdf_list_t *list = NULL;
1307 	struct scan_cache_node *first_node = NULL;
1308 	qdf_list_node_t *cur_node = NULL;
1309 
1310 	scan_filter = qdf_mem_malloc(sizeof(*scan_filter));
1311 	if (!scan_filter)
1312 		return ch_freq;
1313 
1314 	scan_filter->num_of_bssid = 1;
1315 	qdf_mem_copy(scan_filter->bssid_list[0].bytes,
1316 		     bssid, sizeof(struct qdf_mac_addr));
1317 	list = wlan_scan_get_result(pdev, scan_filter);
1318 	qdf_mem_free(scan_filter);
1319 
1320 	if (!list || (list && !qdf_list_size(list))) {
1321 		mlo_debug("scan list empty");
1322 		goto error;
1323 	}
1324 
1325 	qdf_list_peek_front(list, &cur_node);
1326 	first_node = qdf_container_of(cur_node,
1327 				      struct scan_cache_node,
1328 				      node);
1329 	if (first_node && first_node->entry)
1330 		ch_freq = first_node->entry->channel.chan_freq;
1331 error:
1332 	if (list)
1333 		wlan_scan_purge_results(list);
1334 
1335 	return ch_freq;
1336 }
1337 
1338 void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev,
1339 		       struct element_info *assoc_rsp_frame)
1340 {
1341 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1342 	struct wlan_mlo_sta *sta_ctx = NULL;
1343 
1344 	if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx)
1345 		return;
1346 
1347 	sta_ctx = mlo_dev_ctx->sta_ctx;
1348 
1349 	if (!sta_ctx->assoc_rsp.len || !sta_ctx->assoc_rsp.ptr) {
1350 		mlo_err("Assoc Resp info is empty");
1351 		return;
1352 	}
1353 
1354 	*assoc_rsp_frame = sta_ctx->assoc_rsp;
1355 }
1356 
1357 QDF_STATUS mlo_sta_save_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
1358 				     uint8_t link_id,
1359 				     bool quiet_status)
1360 {
1361 	struct wlan_mlo_sta *sta_ctx;
1362 	int i;
1363 	bool find_free_buffer = false;
1364 	int free_idx;
1365 
1366 	if (!mlo_dev_ctx) {
1367 		mlo_err("invalid mlo_dev_ctx");
1368 		return QDF_STATUS_E_INVAL;
1369 	}
1370 
1371 	mlo_dev_lock_acquire(mlo_dev_ctx);
1372 	sta_ctx = mlo_dev_ctx->sta_ctx;
1373 	if (!sta_ctx) {
1374 		mlo_err("invalid sta_ctx");
1375 		mlo_dev_lock_release(mlo_dev_ctx);
1376 		return QDF_STATUS_E_INVAL;
1377 	}
1378 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) {
1379 		if (!sta_ctx->mlo_quiet_status[i].valid_status) {
1380 			if (!find_free_buffer) {
1381 				free_idx = i;
1382 				find_free_buffer = true;
1383 			}
1384 		} else if (link_id == sta_ctx->mlo_quiet_status[i].link_id) {
1385 			sta_ctx->mlo_quiet_status[i].quiet_status =
1386 							quiet_status;
1387 			mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d quiet status update %d",
1388 				  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
1389 				  link_id, quiet_status);
1390 			mlo_dev_lock_release(mlo_dev_ctx);
1391 			return QDF_STATUS_SUCCESS;
1392 		}
1393 	}
1394 	if (!find_free_buffer) {
1395 		mlo_err("no free buffer for link id %d to save quiet_status",
1396 			link_id);
1397 		mlo_dev_lock_release(mlo_dev_ctx);
1398 		return QDF_STATUS_E_INVAL;
1399 	}
1400 	sta_ctx->mlo_quiet_status[free_idx].quiet_status = quiet_status;
1401 	sta_ctx->mlo_quiet_status[free_idx].link_id = link_id;
1402 	sta_ctx->mlo_quiet_status[free_idx].valid_status = true;
1403 
1404 	mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d in quiet status %d",
1405 		  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
1406 		  link_id, quiet_status);
1407 	mlo_dev_lock_release(mlo_dev_ctx);
1408 
1409 	return QDF_STATUS_SUCCESS;
1410 }
1411 
1412 bool mlo_is_sta_in_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
1413 				uint8_t link_id)
1414 {
1415 	struct wlan_mlo_sta *sta_ctx;
1416 	int i;
1417 	bool quiet_status = false;
1418 
1419 	if (!mlo_dev_ctx) {
1420 		mlo_err("invalid mlo_dev_ctx");
1421 		return quiet_status;
1422 	}
1423 
1424 	mlo_dev_lock_acquire(mlo_dev_ctx);
1425 	sta_ctx = mlo_dev_ctx->sta_ctx;
1426 	if (!sta_ctx) {
1427 		mlo_err("invalid sta_ctx");
1428 		mlo_dev_lock_release(mlo_dev_ctx);
1429 		return quiet_status;
1430 	}
1431 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) {
1432 		if (sta_ctx->mlo_quiet_status[i].valid_status &&
1433 		    link_id == sta_ctx->mlo_quiet_status[i].link_id) {
1434 			quiet_status =
1435 				sta_ctx->mlo_quiet_status[i].quiet_status;
1436 			break;
1437 		}
1438 	}
1439 	mlo_dev_lock_release(mlo_dev_ctx);
1440 
1441 	return quiet_status;
1442 }
1443 
1444 bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc,
1445 					      uint8_t *vdev_id_list,
1446 					      uint8_t num_mlo, uint8_t *mlo_idx,
1447 					      uint8_t affected_links,
1448 					      uint8_t *affected_list)
1449 {
1450 	uint8_t i, j;
1451 	struct wlan_objmgr_vdev *vdev;
1452 	bool allowed = false;
1453 
1454 	for (i = 0; i < num_mlo; i++) {
1455 		for (j = 0; j < affected_links; j++) {
1456 			if (vdev_id_list[mlo_idx[i]] == affected_list[j])
1457 				break;
1458 		}
1459 		if (j != affected_links)
1460 			continue;
1461 		/* find vdev not in affected_list */
1462 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
1463 				psoc, vdev_id_list[mlo_idx[i]],
1464 				WLAN_IF_MGR_ID);
1465 		if (!vdev) {
1466 			mlo_err("invalid vdev for id %d",
1467 				vdev_id_list[mlo_idx[i]]);
1468 			continue;
1469 		}
1470 
1471 		/* for not affected vdev, check the vdev is in quiet or not*/
1472 		allowed = !mlo_is_sta_in_quiet_status(
1473 				vdev->mlo_dev_ctx, wlan_vdev_get_link_id(vdev));
1474 		wlan_objmgr_vdev_release_ref(vdev, WLAN_IF_MGR_ID);
1475 		if (allowed) {
1476 			mlo_debug("vdev id %d link id %d is not in quiet, allow partner link to trigger inactivity",
1477 				  wlan_vdev_get_id(vdev),
1478 				  wlan_vdev_get_link_id(vdev));
1479 			break;
1480 		}
1481 	}
1482 
1483 	return allowed;
1484 }
1485 
1486 bool mlo_is_sta_csa_synced(struct wlan_mlo_dev_context *mlo_dev_ctx,
1487 			   uint8_t link_id)
1488 {
1489 	struct wlan_mlo_sta *sta_ctx;
1490 	int i;
1491 	bool sta_csa_synced = false;
1492 
1493 	if (!mlo_dev_ctx) {
1494 		mlo_err("invalid mlo_dev_ctx");
1495 		return sta_csa_synced;
1496 	}
1497 
1498 	mlo_dev_lock_acquire(mlo_dev_ctx);
1499 	sta_ctx = mlo_dev_ctx->sta_ctx;
1500 	if (!sta_ctx) {
1501 		mlo_err("invalid sta_ctx");
1502 		mlo_dev_lock_release(mlo_dev_ctx);
1503 		return sta_csa_synced;
1504 	}
1505 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
1506 		if (link_id == sta_ctx->mlo_csa_param[i].link_id &&
1507 		    (sta_ctx->mlo_csa_param[i].valid_csa_param ||
1508 		     sta_ctx->mlo_csa_param[i].mlo_csa_synced)) {
1509 			mlo_dev_lock_release(mlo_dev_ctx);
1510 			sta_csa_synced =
1511 				sta_ctx->mlo_csa_param[i].mlo_csa_synced;
1512 			break;
1513 		}
1514 	}
1515 	mlo_dev_lock_release(mlo_dev_ctx);
1516 
1517 	return sta_csa_synced;
1518 }
1519 
1520 QDF_STATUS mlo_sta_csa_save_params(struct wlan_mlo_dev_context *mlo_dev_ctx,
1521 				   uint8_t link_id,
1522 				   struct csa_offload_params *csa_param)
1523 {
1524 	struct wlan_mlo_sta *sta_ctx;
1525 	int i;
1526 	bool find_free_buffer = false;
1527 	int free_idx;
1528 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1529 
1530 	if (!mlo_dev_ctx) {
1531 		mlo_err("invalid mlo_dev_ctx");
1532 		status = QDF_STATUS_E_INVAL;
1533 		goto done;
1534 	}
1535 
1536 	mlo_dev_lock_acquire(mlo_dev_ctx);
1537 	sta_ctx = mlo_dev_ctx->sta_ctx;
1538 	if (!sta_ctx) {
1539 		mlo_err("invalid sta_ctx");
1540 		status = QDF_STATUS_E_INVAL;
1541 		goto rel_lock;
1542 	}
1543 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
1544 		if (!sta_ctx->mlo_csa_param[i].valid_csa_param &&
1545 		    !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
1546 			if (!find_free_buffer) {
1547 				free_idx = i;
1548 				find_free_buffer = true;
1549 			}
1550 		} else if (link_id == sta_ctx->mlo_csa_param[i].link_id) {
1551 			qdf_mem_copy(&sta_ctx->mlo_csa_param[i].csa_param,
1552 				     csa_param, sizeof(*csa_param));
1553 			mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d update csa",
1554 				  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
1555 				  link_id);
1556 			goto rel_lock;
1557 		}
1558 	}
1559 	if (!find_free_buffer) {
1560 		mlo_err("no free buffer of csa param for link %d in sta_ctx",
1561 			link_id);
1562 		status = QDF_STATUS_E_INVAL;
1563 		goto rel_lock;
1564 	}
1565 	qdf_mem_copy(&sta_ctx->mlo_csa_param[free_idx].csa_param,
1566 		     csa_param, sizeof(*csa_param));
1567 	sta_ctx->mlo_csa_param[free_idx].link_id = link_id;
1568 	sta_ctx->mlo_csa_param[free_idx].valid_csa_param = true;
1569 	mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d RX csa",
1570 		  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
1571 		  link_id);
1572 
1573 rel_lock:
1574 	mlo_dev_lock_release(mlo_dev_ctx);
1575 
1576 done:
1577 
1578 	return status;
1579 }
1580 
1581 QDF_STATUS mlo_sta_up_active_notify(struct wlan_objmgr_vdev *vdev)
1582 {
1583 	struct wlan_mlo_sta *sta_ctx;
1584 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1585 	uint8_t link_id;
1586 	int i;
1587 	bool find_free_buffer = false;
1588 	int free_idx;
1589 	struct csa_offload_params csa_param;
1590 	struct wlan_channel *chan;
1591 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1592 
1593 	if (!vdev) {
1594 		mlo_err("invalid vdev");
1595 		status = QDF_STATUS_E_INVAL;
1596 		goto done;
1597 	}
1598 	link_id = wlan_vdev_get_link_id(vdev);
1599 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1600 	if (!mlo_dev_ctx) {
1601 		mlo_err("invalid mlo_dev_ctx");
1602 		status = QDF_STATUS_E_INVAL;
1603 		goto done;
1604 	}
1605 	mlo_dev_lock_acquire(mlo_dev_ctx);
1606 	sta_ctx = mlo_dev_ctx->sta_ctx;
1607 	if (!sta_ctx) {
1608 		mlo_err("invalid sta_ctx");
1609 		status = QDF_STATUS_E_INVAL;
1610 		goto rel_lock;
1611 	}
1612 
1613 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
1614 		if (!sta_ctx->mlo_csa_param[i].valid_csa_param &&
1615 		    !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
1616 			if (!find_free_buffer) {
1617 				free_idx = i;
1618 				find_free_buffer = true;
1619 			}
1620 		} else if (link_id == sta_ctx->mlo_csa_param[i].link_id) {
1621 			if (sta_ctx->mlo_csa_param[i].valid_csa_param &&
1622 			    !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
1623 				mlo_debug("mld mac " QDF_MAC_ADDR_FMT " vdev id %d link id %d handle csa",
1624 					  QDF_MAC_ADDR_REF(
1625 						mlo_dev_ctx->mld_addr.bytes),
1626 					  wlan_vdev_get_id(vdev), link_id);
1627 				csa_param = sta_ctx->mlo_csa_param[i].csa_param;
1628 				sta_ctx->mlo_csa_param[i].mlo_csa_synced = true;
1629 				mlo_dev_lock_release(mlo_dev_ctx);
1630 				chan = wlan_vdev_mlme_get_bss_chan(vdev);
1631 				if (csa_param.csa_chan_freq && chan &&
1632 				    csa_param.csa_chan_freq != chan->ch_freq)
1633 					mlo_mlme_handle_sta_csa_param(
1634 						vdev, &csa_param);
1635 				goto done;
1636 			}
1637 			sta_ctx->mlo_csa_param[i].mlo_csa_synced = true;
1638 			goto rel_lock;
1639 		}
1640 	}
1641 	if (!find_free_buffer) {
1642 		mlo_err("no free buffer of csa param for link %d in sta_ctx",
1643 			link_id);
1644 		goto rel_lock;
1645 	}
1646 	sta_ctx->mlo_csa_param[free_idx].mlo_csa_synced = true;
1647 	sta_ctx->mlo_csa_param[free_idx].link_id = link_id;
1648 	mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d UP Active",
1649 		  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
1650 		  link_id);
1651 
1652 rel_lock:
1653 	mlo_dev_lock_release(mlo_dev_ctx);
1654 
1655 done:
1656 
1657 	return status;
1658 }
1659 
1660 bool mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev *vdev,
1661 				  struct csa_offload_params *csa_param)
1662 {
1663 	struct wlan_mlo_sta *sta_ctx;
1664 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1665 	uint8_t link_id;
1666 	int i;
1667 	bool handled = false;
1668 
1669 	if (!vdev) {
1670 		mlo_err("invalid vdev");
1671 		goto done;
1672 	}
1673 	link_id = wlan_vdev_get_link_id(vdev);
1674 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1675 	if (!mlo_dev_ctx) {
1676 		mlo_err("invalid mlo_dev_ctx");
1677 		goto done;
1678 	}
1679 	mlo_dev_lock_acquire(mlo_dev_ctx);
1680 	sta_ctx = mlo_dev_ctx->sta_ctx;
1681 	if (!sta_ctx) {
1682 		mlo_err("invalid sta_ctx");
1683 		goto rel_lock;
1684 	}
1685 
1686 	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
1687 		if (link_id == sta_ctx->mlo_csa_param[i].link_id &&
1688 		    (sta_ctx->mlo_csa_param[i].valid_csa_param ||
1689 		     sta_ctx->mlo_csa_param[i].mlo_csa_synced))
1690 			break;
1691 	}
1692 
1693 	if (i >= QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param)) {
1694 		mlo_debug("mlo csa synced does not happen before csa FW event");
1695 		goto rel_lock;
1696 	}
1697 	if (!sta_ctx->mlo_csa_param[i].csa_offload_event_recvd) {
1698 		sta_ctx->mlo_csa_param[i].csa_offload_event_recvd = true;
1699 		if (sta_ctx->mlo_csa_param[i].valid_csa_param &&
1700 		    !qdf_mem_cmp(&sta_ctx->mlo_csa_param[i].csa_param,
1701 				 csa_param, sizeof(*csa_param)))
1702 			handled = true;
1703 	}
1704 
1705 rel_lock:
1706 	mlo_dev_lock_release(mlo_dev_ctx);
1707 
1708 done:
1709 
1710 	return handled;
1711 }
1712 
1713 void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev)
1714 {
1715 	struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1716 	struct wlan_mlo_sta *sta_ctx = NULL;
1717 	uint8_t i;
1718 
1719 	if (!vdev)
1720 		return;
1721 
1722 	if (!wlan_vdev_mlme_is_assoc_sta_vdev(vdev)) {
1723 		mlo_debug("Not an assoc vdev, so ignore disconnect req");
1724 		return;
1725 	}
1726 
1727 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1728 	if (mlo_dev_ctx) {
1729 		sta_ctx = mlo_dev_ctx->sta_ctx;
1730 	} else {
1731 		mlo_err("Invalid mlo_dev_ctx");
1732 		return;
1733 	}
1734 
1735 	if (sta_ctx) {
1736 		copied_conn_req_lock_acquire(sta_ctx);
1737 		if (sta_ctx->copied_conn_req) {
1738 			mlo_free_connect_ies(sta_ctx->copied_conn_req);
1739 			qdf_mem_free(sta_ctx->copied_conn_req);
1740 			sta_ctx->copied_conn_req = NULL;
1741 		}
1742 		copied_conn_req_lock_release(sta_ctx);
1743 	} else {
1744 		mlo_err("Invalid sta_ctx");
1745 		return;
1746 	}
1747 
1748 	mlo_dev_lock_acquire(mlo_dev_ctx);
1749 	if (sta_ctx->connect_req) {
1750 		mlo_free_connect_ies(sta_ctx->connect_req);
1751 		qdf_mem_free(sta_ctx->connect_req);
1752 		sta_ctx->connect_req = NULL;
1753 	}
1754 
1755 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1756 		if (!mlo_dev_ctx->wlan_vdev_list[i])
1757 			continue;
1758 
1759 		if (qdf_test_bit(i,
1760 				 mlo_dev_ctx->sta_ctx->wlan_connected_links) &&
1761 		    mlo_dev_ctx->wlan_vdev_list[i] !=
1762 		    mlo_get_assoc_link_vdev(mlo_dev_ctx))
1763 			wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
1764 					   CM_INTERNAL_DISCONNECT,
1765 					   REASON_UNSPEC_FAILURE,
1766 					   NULL);
1767 	}
1768 
1769 	mlo_dev_lock_release(mlo_dev_ctx);
1770 }
1771 
1772 void mlo_sta_get_vdev_list(struct wlan_objmgr_vdev *vdev, uint16_t *vdev_count,
1773 			   struct wlan_objmgr_vdev **wlan_vdev_list)
1774 {
1775 	struct wlan_mlo_dev_context *dev_ctx;
1776 	int i;
1777 	QDF_STATUS status;
1778 
1779 	*vdev_count = 0;
1780 
1781 	if (!vdev || !vdev->mlo_dev_ctx) {
1782 		mlo_err("Invalid input");
1783 		return;
1784 	}
1785 
1786 	dev_ctx = vdev->mlo_dev_ctx;
1787 
1788 	mlo_dev_lock_acquire(dev_ctx);
1789 	*vdev_count = 0;
1790 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
1791 		if (dev_ctx->wlan_vdev_list[i]) {
1792 			status =
1793 			wlan_objmgr_vdev_try_get_ref(dev_ctx->wlan_vdev_list[i],
1794 						     WLAN_MLO_MGR_ID);
1795 			if (QDF_IS_STATUS_ERROR(status))
1796 				break;
1797 			wlan_vdev_list[*vdev_count] =
1798 				dev_ctx->wlan_vdev_list[i];
1799 			(*vdev_count) += 1;
1800 		}
1801 	}
1802 	mlo_dev_lock_release(dev_ctx);
1803 }
1804 
1805 #endif
1806