xref: /wlan-dirver/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c (revision fa7ef9dc94d54d7249583ffc7a8a13fa1d3381e4)
1 /*
2  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * DOC: contains MLO manager roaming related functionality
19  */
20 #include <wlan_cmn.h>
21 #include <wlan_cm_public_struct.h>
22 #include <wlan_cm_roam_public_struct.h>
23 #include "wlan_mlo_mgr_cmn.h"
24 #include "wlan_mlo_mgr_main.h"
25 #include "wlan_mlo_mgr_roam.h"
26 #include "wlan_mlo_mgr_public_structs.h"
27 #include "wlan_mlo_mgr_sta.h"
28 #include <../../core/src/wlan_cm_roam_i.h>
29 #include "wlan_cm_roam_api.h"
30 #include "wlan_mlme_vdev_mgr_interface.h"
31 #include <include/wlan_mlme_cmn.h>
32 #include <wlan_cm_api.h>
33 #include <utils_mlo.h>
34 #include <wlan_mlo_mgr_peer.h>
35 #include "wlan_mlo_link_force.h"
36 
37 #ifdef WLAN_FEATURE_11BE_MLO
38 static bool
39 mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev)
40 {
41 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
42 	struct wlan_mlo_sta *sta_ctx;
43 	uint8_t i = 0;
44 
45 	if (!mlo_dev_ctx)
46 		return false;
47 
48 	sta_ctx = mlo_dev_ctx->sta_ctx;
49 
50 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
51 		if (!mlo_dev_ctx->wlan_vdev_list[i])
52 			continue;
53 
54 		if (vdev == mlo_dev_ctx->wlan_vdev_list[i])
55 			return qdf_test_bit(i, sta_ctx->wlan_connect_req_links);
56 	}
57 
58 	mlo_err("vdev:%d not found in ml dev ctx list", wlan_vdev_get_id(vdev));
59 
60 	return false;
61 }
62 
63 static void
64 mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc *psoc,
65 			       uint8_t vdev_id,
66 			       uint8_t ml_link_vdev_id)
67 {
68 	struct wlan_objmgr_vdev *vdev;
69 
70 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
71 						    ml_link_vdev_id,
72 						    WLAN_MLME_SB_ID);
73 	if (!vdev) {
74 		mlo_err("VDEV is null");
75 		return;
76 	}
77 
78 	if (vdev_id == ml_link_vdev_id) {
79 		wlan_vdev_mlme_set_mlo_vdev(vdev);
80 		goto end;
81 	}
82 
83 	wlan_vdev_mlme_set_mlo_vdev(vdev);
84 	wlan_vdev_mlme_set_mlo_link_vdev(vdev);
85 
86 	mlo_update_connect_req_links(vdev, true);
87 
88 end:
89 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
90 }
91 
92 static void
93 mlo_cleanup_link(struct wlan_objmgr_vdev *vdev, uint8_t num_setup_links)
94 {
95 	/*
96 	 * Cleanup the non-assoc link link in below cases,
97 	 * 1. Roamed to single link-MLO AP
98 	 * 2. Roamed to an MLO AP but 4-way handshake is offloaded to
99 	 *    userspace, i.e.auth_status = ROAM_AUTH_STATUS_CONNECTED
100 	 * 3. Roamed to non-MLO AP(num_setup_links = 0)
101 	 * This covers all supported combinations. So cleanup the link always.
102 	 */
103 	if (wlan_vdev_mlme_is_mlo_link_vdev(vdev))
104 		cm_cleanup_mlo_link(vdev);
105 	/*
106 	 * Clear the MLO vdev flag when roam to a non-MLO AP to prepare the
107 	 * roam done indication to userspace in non-MLO format
108 	 * i.e. without MLD/link info
109 	 */
110 	else if (wlan_vdev_mlme_is_mlo_vdev(vdev) && !num_setup_links)
111 		wlan_vdev_mlme_clear_mlo_vdev(vdev);
112 }
113 
114 static void
115 mlo_update_vdev_after_roam(struct wlan_objmgr_psoc *psoc,
116 			   uint8_t vdev_id, uint8_t num_setup_links)
117 {
118 	struct wlan_mlo_dev_context *mlo_dev_ctx;
119 	uint8_t i;
120 	struct wlan_objmgr_vdev *vdev, *tmp_vdev;
121 
122 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
123 						    vdev_id,
124 						    WLAN_MLME_SB_ID);
125 	if (!vdev) {
126 		mlo_err("VDEV:%d is null", vdev_id);
127 		return;
128 	}
129 
130 	if (!vdev->mlo_dev_ctx)
131 		goto end;
132 
133 	mlo_dev_ctx = vdev->mlo_dev_ctx;
134 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
135 		if (!mlo_dev_ctx->wlan_vdev_list[i])
136 			continue;
137 
138 		tmp_vdev = mlo_dev_ctx->wlan_vdev_list[i];
139 		mlo_cleanup_link(tmp_vdev, num_setup_links);
140 	}
141 
142 end:
143 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
144 }
145 
146 static void
147 mlo_clear_link_bmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
148 {
149 	struct wlan_objmgr_vdev *vdev;
150 
151 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
152 						    vdev_id,
153 						    WLAN_MLME_SB_ID);
154 	if (!vdev) {
155 		mlo_err("VDEV is null");
156 		return;
157 	}
158 
159 	mlo_clear_connect_req_links_bmap(vdev);
160 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
161 }
162 
163 static QDF_STATUS
164 mlo_roam_abort_req(struct wlan_objmgr_psoc *psoc,
165 		   uint8_t *event, uint8_t vdev_id)
166 {
167 	struct roam_offload_synch_ind *sync_ind = NULL;
168 
169 	sync_ind = (struct roam_offload_synch_ind *)event;
170 
171 	if (!sync_ind) {
172 		mlme_err("Roam Sync ind ptr is NULL");
173 		return QDF_STATUS_E_NULL_VALUE;
174 	}
175 
176 	wlan_mlo_roam_abort_on_link(psoc, event, sync_ind->roamed_vdev_id);
177 
178 	return QDF_STATUS_SUCCESS;
179 }
180 #else
181 static inline void
182 mlo_clear_link_bmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
183 {}
184 
185 static inline void
186 mlo_update_vdev_after_roam(struct wlan_objmgr_psoc *psoc,
187 			   uint8_t vdev_id, uint8_t num_setup_links)
188 {}
189 
190 static inline void
191 mlo_cleanup_link(struct wlan_objmgr_vdev *vdev, uint8_t num_setup_links)
192 {}
193 
194 static inline void
195 mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc *psoc,
196 			       uint8_t vdev_id,
197 			       uint8_t ml_link_vdev_id)
198 {}
199 
200 static inline bool
201 mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev)
202 {
203 	return false;
204 }
205 
206 static inline QDF_STATUS
207 mlo_roam_abort_req(struct wlan_objmgr_psoc *psoc,
208 		   uint8_t *event, uint8_t vdev_id)
209 {
210 	return QDF_STATUS_E_NOSUPPORT;
211 }
212 #endif
213 
214 static void mlo_roam_update_vdev_macaddr(struct wlan_objmgr_psoc *psoc,
215 					 uint8_t vdev_id,
216 					 bool is_non_ml_connection)
217 {
218 	struct wlan_objmgr_vdev *vdev;
219 	struct qdf_mac_addr *mld_mac;
220 
221 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
222 						    vdev_id,
223 						    WLAN_MLO_MGR_ID);
224 	if (!vdev) {
225 		mlo_err("VDEV is null");
226 		return;
227 	}
228 
229 	if (is_non_ml_connection) {
230 		mld_mac = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
231 		if (!qdf_is_macaddr_zero(mld_mac))
232 			wlan_vdev_mlme_set_macaddr(vdev, mld_mac->bytes);
233 	} else {
234 		wlan_vdev_mlme_set_macaddr(vdev,
235 					   wlan_vdev_mlme_get_linkaddr(vdev));
236 	}
237 
238 	mlme_debug("vdev_id %d self mac " QDF_MAC_ADDR_FMT,
239 		   vdev_id,
240 		   QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)));
241 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
242 }
243 
244 QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
245 				void *event, uint32_t event_data_len)
246 {
247 	struct roam_offload_synch_ind *sync_ind;
248 	QDF_STATUS status;
249 	uint8_t i;
250 	bool is_non_mlo_ap = false;
251 
252 	sync_ind = (struct roam_offload_synch_ind *)event;
253 	if (!sync_ind)
254 		return QDF_STATUS_E_FAILURE;
255 
256 	for (i = 0; i < sync_ind->num_setup_links; i++)
257 		mlo_update_for_multi_link_roam(psoc, vdev_id,
258 					       sync_ind->ml_link[i].vdev_id);
259 
260 	if (!sync_ind->num_setup_links) {
261 		mlo_debug("MLO_ROAM: Roamed to Legacy");
262 		is_non_mlo_ap = true;
263 		mlo_set_single_link_ml_roaming(psoc, vdev_id, false);
264 	} else if (sync_ind->num_setup_links == 1 ||
265 		sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) {
266 		mlo_debug("MLO_ROAM: Roamed to single link MLO");
267 		mlo_set_single_link_ml_roaming(psoc, vdev_id, true);
268 	} else {
269 		mlo_debug("MLO_ROAM: Roamed to MLO with %d links",
270 			  sync_ind->num_setup_links);
271 		mlo_set_single_link_ml_roaming(psoc, vdev_id, false);
272 	}
273 
274 	mlo_roam_update_vdev_macaddr(psoc, vdev_id, is_non_mlo_ap);
275 	ml_nlink_conn_change_notify(
276 		psoc, vdev_id, ml_nlink_roam_sync_start_evt, NULL);
277 
278 	status = cm_fw_roam_sync_req(psoc, vdev_id, event, event_data_len);
279 
280 	if (QDF_IS_STATUS_ERROR(status))
281 		mlo_clear_link_bmap(psoc, vdev_id);
282 
283 	return status;
284 }
285 
286 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
287 QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev,
288 			       void *event, uint32_t event_data_len)
289 {
290 	QDF_STATUS status;
291 	struct roam_offload_synch_ind *sync_ind;
292 	struct wlan_objmgr_psoc *psoc;
293 	struct wlan_objmgr_vdev *link_vdev = NULL;
294 	uint8_t i;
295 	uint8_t vdev_id;
296 
297 	sync_ind = (struct roam_offload_synch_ind *)event;
298 	vdev_id = wlan_vdev_get_id(vdev);
299 	psoc = wlan_vdev_get_psoc(vdev);
300 
301 	/* Clean up link vdev in following cases
302 	 * 1. When roamed to legacy, num_setup_links = 0
303 	 * 2. When roamed to single link, num_setup_links = 1
304 	 * 3. Roamed to AP with auth_status = ROAMED_AUTH_STATUS_CONNECTED
305 	 */
306 	if (sync_ind->num_setup_links < 2 ||
307 	    sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) {
308 		mlme_debug("Roam auth status %d", sync_ind->auth_status);
309 		mlo_update_vdev_after_roam(psoc, vdev_id,
310 					   sync_ind->num_setup_links);
311 	}
312 
313 	/* If EAPOL is offloaded to supplicant, link vdev/s are not up
314 	 * at FW, in that case complete roam sync on assoc vdev
315 	 * link vdev will be initialized after set key is complete.
316 	 */
317 	if (sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED)
318 		return QDF_STATUS_SUCCESS;
319 
320 	for (i = 0; i < sync_ind->num_setup_links; i++) {
321 		if (vdev_id == sync_ind->ml_link[i].vdev_id)
322 			continue;
323 
324 		/* Standby Link */
325 		if (sync_ind->ml_link[i].vdev_id == WLAN_INVALID_VDEV_ID)
326 			continue;
327 
328 		link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
329 								 sync_ind->ml_link[i].vdev_id,
330 								 WLAN_MLME_SB_ID);
331 		if (!link_vdev) {
332 			mlo_err("Link vdev:%d is null",
333 				sync_ind->ml_link[i].vdev_id);
334 			return QDF_STATUS_E_FAILURE;
335 		}
336 
337 		if (mlo_check_connect_req_bmap(link_vdev)) {
338 			mlo_update_connect_req_links(link_vdev, false);
339 
340 			status = cm_fw_roam_sync_req(psoc,
341 						     sync_ind->ml_link[i].vdev_id,
342 						     event, event_data_len);
343 			if (QDF_IS_STATUS_ERROR(status)) {
344 				mlo_clear_connect_req_links_bmap(link_vdev);
345 				mlo_roam_abort_req(psoc, event,
346 						   sync_ind->ml_link[i].vdev_id);
347 				wlan_objmgr_vdev_release_ref(link_vdev,
348 							     WLAN_MLME_SB_ID);
349 				return QDF_STATUS_E_FAILURE;
350 			}
351 		}
352 		wlan_objmgr_vdev_release_ref(link_vdev,
353 					     WLAN_MLME_SB_ID);
354 	}
355 
356 	return QDF_STATUS_SUCCESS;
357 }
358 #endif
359 
360 void
361 mlo_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc,
362 		   uint8_t vdev_id, struct qdf_mac_addr bssid)
363 {
364 	struct wlan_objmgr_vdev *vdev;
365 	struct wlan_mlo_dev_context *mlo_dev_ctx;
366 	uint8_t i;
367 
368 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
369 						    vdev_id,
370 						    WLAN_MLME_SB_ID);
371 
372 	if (!vdev) {
373 		mlo_err("vdev is null");
374 		return;
375 	}
376 
377 	if (!vdev->mlo_dev_ctx)
378 		goto end;
379 
380 	mlo_dev_ctx = vdev->mlo_dev_ctx;
381 
382 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
383 		if (!mlo_dev_ctx->wlan_vdev_list[i] ||
384 		    mlo_dev_ctx->wlan_vdev_list[i] == vdev)
385 			continue;
386 		cm_fw_ho_fail_req(psoc,
387 				  wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]),
388 				  bssid);
389 	}
390 
391 end:
392 	cm_fw_ho_fail_req(psoc, vdev_id, bssid);
393 	wlan_objmgr_vdev_release_ref(vdev,
394 				     WLAN_MLME_SB_ID);
395 }
396 
397 QDF_STATUS
398 mlo_get_sta_link_mac_addr(uint8_t vdev_id,
399 			  struct roam_offload_synch_ind *sync_ind,
400 			  struct qdf_mac_addr *link_mac_addr)
401 {
402 	QDF_STATUS status = QDF_STATUS_SUCCESS;
403 	uint8_t i;
404 
405 	if (!sync_ind || !sync_ind->num_setup_links)
406 		return QDF_STATUS_E_FAILURE;
407 
408 	for (i = 0; i < sync_ind->num_setup_links; i++) {
409 		if (sync_ind->ml_link[i].vdev_id == vdev_id) {
410 			qdf_copy_macaddr(link_mac_addr,
411 					 &sync_ind->ml_link[i].link_addr);
412 			return status;
413 		}
414 	}
415 
416 	if (i == sync_ind->num_setup_links) {
417 		mlo_err("Link mac addr not found");
418 		status = QDF_STATUS_E_FAILURE;
419 	}
420 
421 	return status;
422 }
423 
424 uint32_t
425 mlo_roam_get_chan_freq(uint8_t vdev_id,
426 		       struct roam_offload_synch_ind *sync_ind)
427 {
428 	uint8_t i;
429 
430 	if (!sync_ind || !sync_ind->num_setup_links)
431 		return 0;
432 
433 	for (i = 0; i < sync_ind->num_setup_links; i++) {
434 		if (sync_ind->ml_link[i].vdev_id == vdev_id)
435 			return sync_ind->ml_link[i].channel.mhz;
436 	}
437 
438 	return 0;
439 }
440 
441 uint32_t
442 mlo_roam_get_link_id(uint8_t vdev_id,
443 		     struct roam_offload_synch_ind *sync_ind)
444 {
445 	uint8_t i;
446 
447 	if (!sync_ind || !sync_ind->num_setup_links)
448 		return 0;
449 
450 	for (i = 0; i < sync_ind->num_setup_links; i++) {
451 		if (sync_ind->ml_link[i].vdev_id == vdev_id)
452 			return sync_ind->ml_link[i].link_id;
453 	}
454 
455 	return 0;
456 }
457 
458 bool is_multi_link_roam(struct roam_offload_synch_ind *sync_ind)
459 {
460 	if (!sync_ind)
461 		return false;
462 
463 	if (sync_ind->num_setup_links)
464 		return true;
465 
466 	return false;
467 }
468 
469 uint8_t
470 mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind *sync_ind)
471 {
472 	if (!sync_ind) {
473 		mlo_err("Roam Sync ind is null");
474 		return WLAN_INVALID_VDEV_ID;
475 	}
476 
477 	return sync_ind->num_setup_links;
478 }
479 
480 uint32_t
481 mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind *sync_ind,
482 				     uint8_t *link_mac_addr)
483 {
484 	uint8_t i;
485 
486 	if (!sync_ind)
487 		return 0;
488 
489 	/* Non-MLO roaming */
490 	if (!sync_ind->num_setup_links)
491 		return sync_ind->chan_freq;
492 
493 	if (!link_mac_addr) {
494 		mlo_debug("link_mac_addr is NULL");
495 		return 0;
496 	}
497 
498 	for (i = 0; i < sync_ind->num_setup_links; i++)
499 		if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes,
500 				 link_mac_addr,
501 				 QDF_MAC_ADDR_SIZE))
502 			return sync_ind->ml_link[i].channel.mhz;
503 
504 	mlo_debug("Mac address not found in ml_link info" QDF_MAC_ADDR_FMT,
505 		  QDF_MAC_ADDR_REF(link_mac_addr));
506 
507 	return 0;
508 }
509 
510 QDF_STATUS
511 mlo_roam_get_link_id_from_mac_addr(struct roam_offload_synch_ind *sync_ind,
512 				   uint8_t *link_mac_addr, uint32_t *link_id)
513 {
514 	uint8_t i;
515 
516 	if (!sync_ind || !sync_ind->num_setup_links || !link_mac_addr)
517 		return QDF_STATUS_E_INVAL;
518 
519 	for (i = 0; i < sync_ind->num_setup_links; i++)
520 		if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes,
521 				 link_mac_addr,
522 				 QDF_MAC_ADDR_SIZE)) {
523 			*link_id = sync_ind->ml_link[i].link_id;
524 			return QDF_STATUS_SUCCESS;
525 		}
526 
527 	return QDF_STATUS_E_INVAL;
528 }
529 
530 QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev,
531 			  struct wlan_objmgr_vdev *vdev,
532 			  struct wlan_cm_connect_resp *rsp)
533 {
534 	struct wlan_objmgr_vdev *assoc_vdev;
535 	uint8_t num_partner_links;
536 
537 	if (!rsp) {
538 		mlo_err("Connect resp is null");
539 		return QDF_STATUS_E_NULL_VALUE;
540 	}
541 
542 	num_partner_links = rsp->ml_parnter_info.num_partner_links;
543 
544 	if (num_partner_links &&
545 	    (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) ||
546 	     !mlo_check_if_all_links_up(vdev)))
547 		return QDF_STATUS_SUCCESS;
548 
549 	assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
550 	if (!assoc_vdev) {
551 		mlo_err("Assoc vdev is null");
552 		return QDF_STATUS_E_NULL_VALUE;
553 	}
554 	cm_roam_start_init_on_connect(pdev, wlan_vdev_get_id(assoc_vdev));
555 
556 	return QDF_STATUS_SUCCESS;
557 }
558 
559 void
560 mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info,
561 			   struct roam_offload_synch_ind *sync_ind,
562 			   uint8_t skip_vdev_id, bool fill_all_links)
563 {
564 	uint8_t i, j;
565 	struct mlo_link_info *link;
566 
567 	if (!sync_ind)
568 		return;
569 
570 	for (i = 0, j = 0; i < sync_ind->num_setup_links; i++) {
571 		if (!fill_all_links &&
572 		    sync_ind->ml_link[i].vdev_id == skip_vdev_id)
573 			continue;
574 
575 		link = &partner_info->partner_link_info[j];
576 		link->link_id = sync_ind->ml_link[i].link_id;
577 		link->vdev_id = sync_ind->ml_link[i].vdev_id;
578 
579 		qdf_copy_macaddr(&link->link_addr,
580 				 &sync_ind->ml_link[i].link_addr);
581 		link->chan_freq = sync_ind->ml_link[i].channel.mhz;
582 		mlo_debug("vdev_id %d link_id %d freq %d bssid" QDF_MAC_ADDR_FMT,
583 			  link->vdev_id, link->link_id, link->chan_freq,
584 			  QDF_MAC_ADDR_REF(link->link_addr.bytes));
585 		j++;
586 	}
587 	partner_info->num_partner_links = j;
588 	mlo_debug("vdev_to_skip:%d num_setup_links %d fill_all_links:%d",
589 		  skip_vdev_id, partner_info->num_partner_links,
590 		  fill_all_links);
591 }
592 
593 void mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev *vdev,
594 			   struct roam_offload_synch_ind *sync_ind)
595 {
596 	uint8_t i;
597 	struct wlan_mlo_dev_context *mlo_dev_ctx;
598 
599 	if (!vdev) {
600 		mlo_err("vdev is NULL");
601 		return;
602 	}
603 
604 	mlo_dev_ctx = vdev->mlo_dev_ctx;
605 	if (!mlo_dev_ctx) {
606 		mlo_err("ML dev ctx is NULL");
607 		return;
608 	}
609 
610 	mlo_clear_cu_bpcc(vdev);
611 	for (i = 0; i < sync_ind->num_setup_links; i++)
612 		mlo_init_cu_bpcc(mlo_dev_ctx, sync_ind->ml_link[i].vdev_id);
613 
614 	mlo_debug("update cu info from roam sync");
615 }
616 
617 void
618 mlo_roam_update_connected_links(struct wlan_objmgr_vdev *vdev,
619 				struct wlan_cm_connect_resp *connect_rsp)
620 {
621 	mlo_clear_connected_links_bmap(vdev);
622 	if (mlo_get_single_link_ml_roaming(wlan_vdev_get_psoc(vdev),
623 					   wlan_vdev_get_id(vdev)))
624 		mlo_update_connected_links(vdev, 1);
625 	else
626 		mlo_update_connected_links_bmap(vdev->mlo_dev_ctx,
627 						connect_rsp->ml_parnter_info);
628 }
629 
630 QDF_STATUS
631 wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc *psoc,
632 			    uint8_t *event, uint8_t vdev_id)
633 {
634 	uint8_t i;
635 	QDF_STATUS status;
636 	struct roam_offload_synch_ind *sync_ind = NULL;
637 
638 	sync_ind = (struct roam_offload_synch_ind *)event;
639 
640 	if (!sync_ind) {
641 		mlo_err("Roam Sync ind ptr is NULL");
642 		return QDF_STATUS_E_NULL_VALUE;
643 	}
644 
645 	for (i = 0; i < sync_ind->num_setup_links; i++) {
646 		if (sync_ind->ml_link[i].vdev_id != vdev_id) {
647 			status = cm_fw_roam_abort_req(psoc,
648 						      sync_ind->ml_link[i].vdev_id);
649 			if (QDF_IS_STATUS_ERROR(status)) {
650 				mlo_err("LFR3: Fail to abort roam on vdev: %u",
651 					sync_ind->ml_link[i].vdev_id);
652 			}
653 		}
654 	}
655 
656 	return QDF_STATUS_SUCCESS;
657 }
658 
659 void
660 mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc,
661 			       uint8_t vdev_id,
662 			       bool is_single_link_ml_roaming)
663 {
664 	struct wlan_objmgr_vdev *vdev;
665 
666 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
667 						    vdev_id,
668 						    WLAN_MLME_SB_ID);
669 	if (!vdev) {
670 		mlo_err("VDEV is null");
671 		return;
672 	}
673 
674 	if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
675 		mlme_set_single_link_mlo_roaming(vdev,
676 						 is_single_link_ml_roaming);
677 
678 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
679 }
680 
681 bool
682 mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc,
683 			       uint8_t vdev_id)
684 {
685 	bool is_single_link_ml_roaming = false;
686 	struct wlan_objmgr_vdev *vdev;
687 
688 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
689 						    vdev_id,
690 						    WLAN_MLME_SB_ID);
691 	if (!vdev) {
692 		mlo_err("VDEV is null");
693 		return is_single_link_ml_roaming;
694 	}
695 
696 	is_single_link_ml_roaming = mlme_get_single_link_mlo_roaming(vdev);
697 	mlo_debug("MLO:is_single_link_ml_roaming %d",
698 		  is_single_link_ml_roaming);
699 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
700 
701 	return is_single_link_ml_roaming;
702 }
703 
704 QDF_STATUS
705 mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id,
706 				 struct roam_offload_synch_ind *sync_ind,
707 				 struct qdf_mac_addr *bssid,
708 				 wmi_channel *chan)
709 {
710 	QDF_STATUS status = QDF_STATUS_SUCCESS;
711 	uint8_t i;
712 
713 	if (!sync_ind || !sync_ind->num_setup_links)
714 		return QDF_STATUS_E_FAILURE;
715 
716 	for (i = 0; i < sync_ind->num_setup_links; i++) {
717 		if (vdev_id == sync_ind->ml_link[i].vdev_id) {
718 			qdf_mem_copy(chan, &sync_ind->ml_link[i].channel,
719 				     sizeof(wmi_channel));
720 			qdf_copy_macaddr(bssid,
721 					 &sync_ind->ml_link[i].link_addr);
722 			return status;
723 		}
724 	}
725 
726 	if (i == sync_ind->num_setup_links) {
727 		mlo_err("roam sync info not found for vdev id %d", vdev_id);
728 		status = QDF_STATUS_E_FAILURE;
729 	}
730 
731 	return status;
732 }
733 
734 bool
735 mlo_check_if_all_links_up(struct wlan_objmgr_vdev *vdev)
736 {
737 	struct wlan_mlo_dev_context *mlo_dev_ctx;
738 	struct wlan_mlo_sta *sta_ctx;
739 	uint8_t i;
740 
741 	if (!vdev || !vdev->mlo_dev_ctx) {
742 		mlo_err("Vdev is null");
743 		return false;
744 	}
745 
746 	mlo_dev_ctx = vdev->mlo_dev_ctx;
747 	sta_ctx = mlo_dev_ctx->sta_ctx;
748 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
749 		if (!mlo_dev_ctx->wlan_vdev_list[i])
750 			continue;
751 
752 		if (qdf_test_bit(i, sta_ctx->wlan_connected_links) &&
753 		    !wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) {
754 			mlo_debug("Vdev id %d is not in connected state",
755 				  wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]));
756 			return false;
757 		}
758 	}
759 
760 	if (i == WLAN_UMAC_MLO_MAX_VDEVS) {
761 		mlo_debug("all links are up");
762 		return true;
763 	}
764 
765 	return false;
766 }
767 
768 bool
769 mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev *vdev)
770 {
771 	struct wlan_mlo_dev_context *mlo_dev_ctx;
772 	struct wlan_mlo_sta *sta_ctx;
773 	uint8_t i;
774 
775 	if (!vdev || !vdev->mlo_dev_ctx) {
776 		mlo_err("Vdev is null");
777 		return false;
778 	}
779 
780 	if (QDF_IS_STATUS_ERROR(wlan_vdev_is_up(vdev))) {
781 		mlo_debug("Vdev id %d is not in up state",
782 			  wlan_vdev_get_id(vdev));
783 			return false;
784 	}
785 
786 	mlo_dev_ctx = vdev->mlo_dev_ctx;
787 	sta_ctx = mlo_dev_ctx->sta_ctx;
788 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
789 		if (!mlo_dev_ctx->wlan_vdev_list[i])
790 			continue;
791 
792 		if (qdf_test_bit(i, sta_ctx->wlan_connected_links) &&
793 		    !QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(mlo_dev_ctx->wlan_vdev_list[i]))) {
794 			mlo_debug("Vdev id %d is not in up state",
795 				  wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]));
796 			return false;
797 		}
798 	}
799 
800 	if (i == WLAN_UMAC_MLO_MAX_VDEVS) {
801 		mlo_debug("all links are up");
802 		return true;
803 	}
804 
805 	return false;
806 }
807 
808 void
809 mlo_roam_set_link_id(struct wlan_objmgr_vdev *vdev,
810 		     struct roam_offload_synch_ind *sync_ind)
811 {
812 	uint8_t i;
813 	uint8_t j;
814 	struct wlan_mlo_dev_context *mlo_dev_ctx;
815 
816 	if (!vdev || !sync_ind || !vdev->mlo_dev_ctx) {
817 		mlo_debug("Invalid input");
818 		return;
819 	}
820 
821 	mlo_dev_ctx = vdev->mlo_dev_ctx;
822 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
823 		vdev = mlo_dev_ctx->wlan_vdev_list[i];
824 		if (!vdev)
825 			continue;
826 
827 		wlan_vdev_set_link_id(vdev, WLAN_LINK_ID_INVALID);
828 		for (j = 0; j < sync_ind->num_setup_links; j++) {
829 			if (sync_ind->ml_link[j].vdev_id ==
830 			    wlan_vdev_get_id(vdev)) {
831 				wlan_vdev_set_link_id(
832 					vdev, sync_ind->ml_link[j].link_id);
833 				mlme_debug("Set link for vdev id %d link id %d",
834 					   wlan_vdev_get_id(vdev),
835 					   sync_ind->ml_link[j].link_id);
836 			}
837 		}
838 	}
839 }
840 
841 QDF_STATUS
842 mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
843 				       struct qdf_mac_addr *link_mac_addr)
844 {
845 	uint8_t i;
846 	struct wlan_mlo_sta *sta_ctx;
847 	struct wlan_cm_connect_resp *rsp;
848 	struct mlo_partner_info parnter_info;
849 	uint8_t vdev_id;
850 
851 	if (!vdev)
852 		return QDF_STATUS_E_NULL_VALUE;
853 
854 	vdev_id = wlan_vdev_get_id(vdev);
855 
856 	if (!vdev->mlo_dev_ctx) {
857 		mlo_err("mlo dev ctx is null, vdev id %d", vdev_id);
858 		return QDF_STATUS_E_NULL_VALUE;
859 	}
860 
861 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
862 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
863 	    !sta_ctx->copied_reassoc_rsp->roaming_info) {
864 		mlo_debug("sta ctx or copied reassoc rsp is null for vdev id %d", vdev_id);
865 		return QDF_STATUS_E_NULL_VALUE;
866 	}
867 
868 	rsp = sta_ctx->copied_reassoc_rsp;
869 	if (rsp->roaming_info->auth_status != ROAM_AUTH_STATUS_CONNECTED) {
870 		mlo_debug("Roam auth status is not connected");
871 		return QDF_STATUS_E_FAILURE;
872 	}
873 
874 	parnter_info = rsp->ml_parnter_info;
875 	for (i = 0; i < parnter_info.num_partner_links; i++) {
876 		if (parnter_info.partner_link_info[i].vdev_id == vdev_id) {
877 			qdf_copy_macaddr(link_mac_addr,
878 					 &parnter_info.partner_link_info[i].link_addr);
879 			return QDF_STATUS_SUCCESS;
880 		}
881 	}
882 
883 	if (i == parnter_info.num_partner_links) {
884 		mlo_debug("Link mac addr not found");
885 		return QDF_STATUS_E_FAILURE;
886 	}
887 
888 	return QDF_STATUS_SUCCESS;
889 }
890 
891 QDF_STATUS
892 mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
893 			  struct wlan_cm_connect_resp *reassoc_rsp)
894 {
895 	struct wlan_mlo_dev_context *mlo_dev_ctx;
896 	struct wlan_mlo_sta *sta_ctx;
897 	struct wlan_connect_rsp_ies *connect_ies;
898 
899 	if (!vdev)
900 		return QDF_STATUS_E_NULL_VALUE;
901 
902 	if (!reassoc_rsp)
903 		return QDF_STATUS_E_NULL_VALUE;
904 
905 	/* Store reassoc rsp only if roamed to 2 link AP */
906 	if (reassoc_rsp->ml_parnter_info.num_partner_links < 2)
907 		return QDF_STATUS_E_INVAL;
908 
909 	mlo_dev_ctx = vdev->mlo_dev_ctx;
910 	if (!mlo_dev_ctx)
911 		return QDF_STATUS_E_NULL_VALUE;
912 
913 	sta_ctx = mlo_dev_ctx->sta_ctx;
914 	if (!sta_ctx)
915 		return QDF_STATUS_E_NULL_VALUE;
916 
917 	if (sta_ctx) {
918 		wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
919 
920 		sta_ctx->copied_reassoc_rsp = qdf_mem_malloc(
921 				sizeof(struct wlan_cm_connect_resp));
922 		if (!sta_ctx->copied_reassoc_rsp)
923 			return QDF_STATUS_E_NOMEM;
924 
925 		qdf_mem_copy(sta_ctx->copied_reassoc_rsp, reassoc_rsp,
926 			     sizeof(struct wlan_cm_connect_resp));
927 
928 		sta_ctx->copied_reassoc_rsp->roaming_info = qdf_mem_malloc(
929 				sizeof(struct wlan_roam_sync_info));
930 
931 		if (!sta_ctx->copied_reassoc_rsp->roaming_info) {
932 			qdf_mem_free(sta_ctx->copied_reassoc_rsp);
933 			return QDF_STATUS_E_NOMEM;
934 		}
935 
936 		qdf_mem_copy(sta_ctx->copied_reassoc_rsp->roaming_info,
937 			     reassoc_rsp->roaming_info,
938 			     sizeof(struct wlan_roam_sync_info));
939 
940 		connect_ies = &sta_ctx->copied_reassoc_rsp->connect_ies;
941 
942 		connect_ies->assoc_rsp.len =
943 			reassoc_rsp->connect_ies.assoc_rsp.len;
944 
945 		connect_ies->assoc_rsp.ptr = qdf_mem_malloc(
946 				connect_ies->assoc_rsp.len);
947 
948 		if (!connect_ies->assoc_rsp.ptr) {
949 			qdf_mem_free(sta_ctx->copied_reassoc_rsp->roaming_info);
950 			qdf_mem_free(sta_ctx->copied_reassoc_rsp);
951 			return QDF_STATUS_E_NOMEM;
952 		}
953 
954 		qdf_mem_copy(connect_ies->assoc_rsp.ptr,
955 			     reassoc_rsp->connect_ies.assoc_rsp.ptr,
956 			     reassoc_rsp->connect_ies.assoc_rsp.len);
957 
958 		connect_ies->assoc_req.len = 0;
959 		connect_ies->assoc_req.ptr = NULL;
960 		connect_ies->bcn_probe_rsp.len = 0;
961 		connect_ies->bcn_probe_rsp.ptr = NULL;
962 		connect_ies->link_bcn_probe_rsp.len = 0;
963 		connect_ies->link_bcn_probe_rsp.ptr = NULL;
964 		connect_ies->fils_ie = NULL;
965 
966 		mlo_debug("Copied reassoc response");
967 	}
968 
969 	return QDF_STATUS_SUCCESS;
970 }
971 
972 static bool
973 mlo_roam_is_internal_disconnect(struct wlan_objmgr_vdev *link_vdev)
974 {
975 	struct wlan_cm_vdev_discon_req *disconn_req;
976 
977 	if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) &&
978 	    wlan_cm_is_vdev_disconnecting(link_vdev)) {
979 		mlo_debug("Disconnect is ongoing on vdev %d",
980 			  wlan_vdev_get_id(link_vdev));
981 
982 		disconn_req = qdf_mem_malloc(sizeof(*disconn_req));
983 		if (!disconn_req) {
984 			mlme_err("Malloc failed for disconnect req");
985 			return false;
986 		}
987 
988 		if (!wlan_cm_get_active_disconnect_req(link_vdev,
989 						       disconn_req)) {
990 			mlme_err("vdev: %d: Active disconnect not found",
991 				 wlan_vdev_get_id(link_vdev));
992 			qdf_mem_free(disconn_req);
993 			return false;
994 		}
995 
996 		mlo_debug("Disconnect source %d", disconn_req->req.source);
997 
998 		if (disconn_req->req.source == CM_MLO_ROAM_INTERNAL_DISCONNECT) {
999 			qdf_mem_free(disconn_req);
1000 			return true;
1001 		}
1002 
1003 		qdf_mem_free(disconn_req);
1004 	}
1005 	/* Disconnect is not ongoing */
1006 	return true;
1007 }
1008 
1009 static QDF_STATUS
1010 mlo_roam_validate_req(struct wlan_objmgr_vdev *vdev,
1011 		      struct wlan_objmgr_vdev *link_vdev,
1012 		      struct wlan_cm_connect_resp *rsp)
1013 {
1014 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1015 	struct wlan_mlo_sta *sta_ctx;
1016 
1017 	if (!vdev) {
1018 		mlo_debug_rl("vdev is NULL");
1019 		return QDF_STATUS_E_NULL_VALUE;
1020 	}
1021 
1022 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1023 	if (!mlo_dev_ctx) {
1024 		mlo_debug_rl("mlo_dev_ctx is NULL");
1025 		return QDF_STATUS_E_NULL_VALUE;
1026 	}
1027 
1028 	sta_ctx = mlo_dev_ctx->sta_ctx;
1029 	if (sta_ctx && sta_ctx->disconn_req) {
1030 		mlo_debug("Handle pending disconnect for vdev %d",
1031 			  wlan_vdev_get_id(vdev));
1032 		mlo_handle_pending_disconnect(vdev);
1033 		return QDF_STATUS_E_FAILURE;
1034 	}
1035 
1036 	if (wlan_cm_is_vdev_disconnected(vdev) ||
1037 	    (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) &&
1038 	     (wlan_cm_is_vdev_connecting(link_vdev) ||
1039 	      !mlo_roam_is_internal_disconnect(link_vdev)))) {
1040 		if (sta_ctx) {
1041 			if (sta_ctx->copied_reassoc_rsp) {
1042 				wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1043 				sta_ctx->copied_reassoc_rsp = NULL;
1044 			}
1045 			copied_conn_req_lock_acquire(sta_ctx);
1046 			if (sta_ctx->copied_conn_req) {
1047 				wlan_cm_free_connect_req(sta_ctx->copied_conn_req);
1048 				sta_ctx->copied_conn_req = NULL;
1049 			}
1050 			copied_conn_req_lock_release(sta_ctx);
1051 		}
1052 	}
1053 
1054 	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1055 		mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev));
1056 		if (wlan_cm_is_vdev_disconnected(vdev)) {
1057 			mlo_handle_sta_link_connect_failure(vdev, rsp);
1058 			return QDF_STATUS_E_FAILURE;
1059 		} else if (!wlan_cm_is_vdev_connected(vdev)) {
1060 			/* If vdev is not in disconnected or connected state,
1061 			 * then the event is received due to connect req being
1062 			 * flushed. Hence, ignore this event
1063 			 */
1064 			if (sta_ctx && sta_ctx->copied_reassoc_rsp) {
1065 				wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1066 				sta_ctx->copied_reassoc_rsp = NULL;
1067 			}
1068 			return QDF_STATUS_E_FAILURE;
1069 		}
1070 	}
1071 
1072 	if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) &&
1073 	    (wlan_cm_is_vdev_connecting(link_vdev) ||
1074 	     !mlo_roam_is_internal_disconnect(link_vdev))) {
1075 		return QDF_STATUS_E_FAILURE;
1076 	}
1077 
1078 	if (sta_ctx && !wlan_vdev_mlme_is_mlo_link_vdev(vdev)) {
1079 		if (sta_ctx->assoc_rsp.ptr) {
1080 			qdf_mem_free(sta_ctx->assoc_rsp.ptr);
1081 			sta_ctx->assoc_rsp.ptr = NULL;
1082 		}
1083 		sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len;
1084 		sta_ctx->assoc_rsp.ptr =
1085 			qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len);
1086 		if (!sta_ctx->assoc_rsp.ptr)
1087 			return QDF_STATUS_E_FAILURE;
1088 		if (rsp->connect_ies.assoc_rsp.ptr)
1089 			qdf_mem_copy(sta_ctx->assoc_rsp.ptr,
1090 				     rsp->connect_ies.assoc_rsp.ptr,
1091 				     rsp->connect_ies.assoc_rsp.len);
1092 		/* Update connected_links_bmap for all vdev taking
1093 		 * part in association
1094 		 */
1095 		mlo_update_connected_links(vdev, 1);
1096 		mlo_update_connected_links_bmap(mlo_dev_ctx,
1097 						rsp->ml_parnter_info);
1098 	}
1099 
1100 	return QDF_STATUS_SUCCESS;
1101 }
1102 
1103 static QDF_STATUS
1104 mlo_roam_prepare_and_send_link_connect_req(struct wlan_objmgr_vdev *assoc_vdev,
1105 					   struct wlan_objmgr_vdev *link_vdev,
1106 					   struct wlan_cm_connect_resp *rsp,
1107 					   struct qdf_mac_addr *link_addr,
1108 					   uint16_t chan_freq)
1109 {
1110 	struct wlan_mlo_sta *sta_ctx;
1111 	struct wlan_cm_connect_req req = {0};
1112 	struct wlan_ssid ssid = {0};
1113 	struct rso_config *rso_cfg;
1114 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1115 
1116 	if (!assoc_vdev || !link_vdev || !rsp)
1117 		return QDF_STATUS_E_FAILURE;
1118 
1119 	if (!assoc_vdev->mlo_dev_ctx || !assoc_vdev->mlo_dev_ctx->sta_ctx)
1120 		return QDF_STATUS_E_FAILURE;
1121 
1122 	sta_ctx = assoc_vdev->mlo_dev_ctx->sta_ctx;
1123 
1124 	wlan_vdev_mlme_get_ssid(assoc_vdev, ssid.ssid,
1125 				&ssid.length);
1126 
1127 	rso_cfg = wlan_cm_get_rso_config(assoc_vdev);
1128 	req.vdev_id = wlan_vdev_get_id(link_vdev);
1129 	req.source = CM_MLO_LINK_VDEV_CONNECT;
1130 	qdf_mem_copy(&req.bssid.bytes,
1131 		     link_addr->bytes,
1132 		     QDF_MAC_ADDR_SIZE);
1133 	req.ssid.length = ssid.length;
1134 	qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length);
1135 	req.chan_freq = chan_freq;
1136 
1137 	req.ml_parnter_info = rsp->ml_parnter_info;
1138 	if (rso_cfg) {
1139 		req.crypto.rsn_caps = rso_cfg->orig_sec_info.rsn_caps;
1140 		req.crypto.auth_type = rso_cfg->orig_sec_info.authmodeset;
1141 		req.crypto.ciphers_pairwise = rso_cfg->orig_sec_info.ucastcipherset;
1142 		req.crypto.group_cipher = rso_cfg->orig_sec_info.mcastcipherset;
1143 		req.crypto.akm_suites = rso_cfg->orig_sec_info.key_mgmt;
1144 		req.assoc_ie.len = rso_cfg->assoc_ie.len;
1145 		if (rso_cfg->assoc_ie.len)
1146 			qdf_mem_copy(&req.assoc_ie.ptr, &rso_cfg->assoc_ie.ptr,
1147 				     rso_cfg->assoc_ie.len);
1148 	}
1149 
1150 	mlo_debug("vdev_id %d, chan_freq %d, mac_addr " QDF_MAC_ADDR_FMT,
1151 		  req.vdev_id, req.chan_freq,
1152 		  QDF_MAC_ADDR_REF(link_addr->bytes));
1153 
1154 	mlme_cm_osif_roam_get_scan_params(assoc_vdev, &req.scan_ie,
1155 					  &req.dot11mode_filter);
1156 
1157 	copied_conn_req_lock_acquire(sta_ctx);
1158 	if (!sta_ctx->copied_conn_req)
1159 		sta_ctx->copied_conn_req = qdf_mem_malloc(
1160 				sizeof(struct wlan_cm_connect_req));
1161 	else
1162 		wlan_cm_free_connect_req_param(sta_ctx->copied_conn_req);
1163 
1164 	mlo_debug("MLO_ROAM: storing from roam connect rsp to connect req");
1165 	if (sta_ctx->copied_conn_req) {
1166 		qdf_mem_copy(sta_ctx->copied_conn_req, &req,
1167 			     sizeof(struct wlan_cm_connect_req));
1168 		mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req,
1169 					  &req);
1170 		copied_conn_req_lock_release(sta_ctx);
1171 	} else {
1172 		mlo_err("MLO_ROAM: Failed to allocate connect req");
1173 		copied_conn_req_lock_release(sta_ctx);
1174 		return QDF_STATUS_E_NOMEM;
1175 	}
1176 
1177 	status = mlo_roam_validate_req(assoc_vdev, link_vdev, rsp);
1178 	if (QDF_IS_STATUS_ERROR(status))
1179 		return status;
1180 
1181 	mlo_debug("MLO_ROAM: Partner link connect mac:" QDF_MAC_ADDR_FMT " vdev_id:%d",
1182 		  QDF_MAC_ADDR_REF(req.bssid.bytes),
1183 		  req.vdev_id);
1184 	status = wlan_cm_start_connect(link_vdev, &req);
1185 	if (QDF_IS_STATUS_ERROR(status))
1186 		return status;
1187 
1188 	mlo_update_connected_links(link_vdev, 1);
1189 	return status;
1190 }
1191 
1192 void mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev *vdev)
1193 {
1194 	struct wlan_mlo_sta *sta_ctx;
1195 
1196 	if (!vdev)
1197 		return;
1198 
1199 	if (!vdev->mlo_dev_ctx)
1200 		return;
1201 
1202 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1203 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
1204 	    !sta_ctx->copied_reassoc_rsp->roaming_info)
1205 		return;
1206 
1207 	wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1208 	sta_ctx->copied_reassoc_rsp = NULL;
1209 }
1210 
1211 void mlo_roam_connect_complete(struct wlan_objmgr_vdev *vdev)
1212 {
1213 	struct wlan_mlo_sta *sta_ctx;
1214 	uint8_t auth_status;
1215 
1216 	if (!vdev)
1217 		return;
1218 
1219 	if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
1220 		return;
1221 
1222 	if (!vdev->mlo_dev_ctx)
1223 		return;
1224 
1225 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1226 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
1227 	    !sta_ctx->copied_reassoc_rsp->roaming_info)
1228 		return;
1229 
1230 	auth_status = sta_ctx->copied_reassoc_rsp->roaming_info->auth_status;
1231 	if (!mlo_check_connect_req_bmap(vdev) &&
1232 	    auth_status == ROAM_AUTH_STATUS_CONNECTED) {
1233 		wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1234 		sta_ctx->copied_reassoc_rsp = NULL;
1235 	}
1236 }
1237 
1238 bool
1239 mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1240 {
1241 	bool status = false;
1242 	struct wlan_mlo_sta *sta_ctx;
1243 	struct wlan_cm_connect_resp *rsp;
1244 	struct wlan_objmgr_vdev *vdev;
1245 
1246 	if (!psoc)
1247 		return status;
1248 
1249 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1250 						    WLAN_MLME_SB_ID);
1251 	if (!vdev)
1252 		return status;
1253 
1254 	if (!vdev->mlo_dev_ctx)
1255 		goto end;
1256 
1257 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1258 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
1259 	    !sta_ctx->copied_reassoc_rsp->roaming_info)
1260 		goto end;
1261 
1262 	rsp = sta_ctx->copied_reassoc_rsp;
1263 	if (rsp->roaming_info->auth_status == ROAM_AUTH_STATUS_CONNECTED)
1264 		status = true;
1265 
1266 end:
1267 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
1268 	return status;
1269 }
1270 
1271 QDF_STATUS
1272 mlo_roam_link_connect_notify(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1273 {
1274 	struct wlan_mlo_sta *sta_ctx = NULL;
1275 	struct wlan_cm_connect_resp *rsp;
1276 	struct wlan_objmgr_vdev *assoc_vdev;
1277 	struct wlan_objmgr_vdev *link_vdev = NULL;
1278 	struct wlan_objmgr_vdev *vdev;
1279 	struct mlo_partner_info partner_info;
1280 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1281 	uint8_t i;
1282 	uint8_t assoc_vdev_id;
1283 	uint8_t link_vdev_id;
1284 
1285 	if (!psoc)
1286 		return QDF_STATUS_E_NULL_VALUE;
1287 
1288 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1289 						    WLAN_MLME_SB_ID);
1290 	if (!vdev)
1291 		return QDF_STATUS_E_NULL_VALUE;
1292 
1293 	if (!vdev->mlo_dev_ctx) {
1294 		mlo_err("mlo dev ctx is null");
1295 		status = QDF_STATUS_E_FAILURE;
1296 		goto err;
1297 	}
1298 
1299 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1300 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1301 		mlo_debug("MLO_ROAM: Ignore if not mlo vdev");
1302 		status = QDF_STATUS_E_FAILURE;
1303 		goto err;
1304 	}
1305 
1306 	assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
1307 	if (!assoc_vdev) {
1308 		status =  QDF_STATUS_E_NULL_VALUE;
1309 		goto err;
1310 	}
1311 
1312 	assoc_vdev_id = wlan_vdev_get_id(assoc_vdev);
1313 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp) {
1314 		status = QDF_STATUS_E_NULL_VALUE;
1315 		goto err;
1316 	}
1317 
1318 	rsp = sta_ctx->copied_reassoc_rsp;
1319 	partner_info = rsp->ml_parnter_info;
1320 	mlo_debug("partner links %d", partner_info.num_partner_links);
1321 
1322 	for (i = 0; i < partner_info.num_partner_links; i++) {
1323 		link_vdev_id = partner_info.partner_link_info[i].vdev_id;
1324 		if (assoc_vdev_id == link_vdev_id)
1325 			continue;
1326 		link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
1327 								 link_vdev_id,
1328 								 WLAN_MLME_SB_ID);
1329 		if (!link_vdev) {
1330 			mlo_err("Link vdev is null");
1331 			status = QDF_STATUS_E_NULL_VALUE;
1332 			goto err;
1333 		}
1334 
1335 		if (mlo_check_connect_req_bmap(link_vdev)) {
1336 			mlo_update_connect_req_links(link_vdev, false);
1337 			status = mlo_roam_prepare_and_send_link_connect_req(assoc_vdev,
1338 							link_vdev,
1339 							rsp,
1340 							&partner_info.partner_link_info[i].link_addr,
1341 							partner_info.partner_link_info[i].chan_freq);
1342 			if (QDF_IS_STATUS_ERROR(status))
1343 				goto err;
1344 			else
1345 				goto end;
1346 		}
1347 	}
1348 err:
1349 	if (link_vdev)
1350 		mlo_clear_connect_req_links_bmap(link_vdev);
1351 	if (sta_ctx && sta_ctx->copied_reassoc_rsp) {
1352 		wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1353 		sta_ctx->copied_reassoc_rsp = NULL;
1354 	}
1355 end:
1356 	if (link_vdev)
1357 		wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLME_SB_ID);
1358 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
1359 	return status;
1360 }
1361 
1362 bool
1363 mlo_is_roaming_in_progress(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1364 {
1365 	struct wlan_objmgr_vdev *vdev;
1366 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1367 	bool is_roaming_in_progress = false;
1368 	uint8_t link_vdev_id;
1369 	uint8_t i;
1370 
1371 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1372 						    WLAN_MLME_OBJMGR_ID);
1373 	if (!vdev) {
1374 		mlme_err("vdev object is NULL for vdev %d", vdev_id);
1375 		return false;
1376 	}
1377 
1378 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1379 	if (!mlo_dev_ctx) {
1380 		mlme_err("mlo_dev_ctx object is NULL for vdev %d", vdev_id);
1381 		goto end;
1382 	}
1383 
1384 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1385 		if (!mlo_dev_ctx->wlan_vdev_list[i])
1386 			continue;
1387 
1388 		link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
1389 		if (link_vdev_id == WLAN_INVALID_VDEV_ID) {
1390 			mlme_err("invalid vdev id");
1391 			goto end;
1392 		}
1393 
1394 		if (wlan_cm_is_roam_sync_in_progress(psoc, link_vdev_id)) {
1395 			is_roaming_in_progress = true;
1396 			goto end;
1397 		}
1398 	}
1399 
1400 end:
1401 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
1402 	return is_roaming_in_progress;
1403 }
1404 
1405 QDF_STATUS
1406 mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc,
1407 			struct roam_scan_candidate_frame *rcvd_frame)
1408 {
1409 	uint8_t *ml_ie, link_id, idx, ies_offset;
1410 	qdf_size_t ml_ie_total_len, gen_frame_len;
1411 	QDF_STATUS status;
1412 	struct mlo_partner_info ml_partner_info = {0};
1413 	struct element_info rcvd_probe_rsp, gen_probe_rsp = {0, NULL};
1414 	struct roam_scan_candidate_frame entry = {0};
1415 	struct qdf_mac_addr self_link_addr;
1416 	struct wlan_objmgr_vdev *vdev;
1417 
1418 	/* Add the received scan entry as it is */
1419 	wlan_cm_add_frame_to_scan_db(psoc, rcvd_frame);
1420 
1421 	ies_offset = WLAN_MAC_HDR_LEN_3A + WLAN_PROBE_RESP_IES_OFFSET;
1422 	if (rcvd_frame->frame_length < ies_offset) {
1423 		mlme_err("No IEs in probe rsp");
1424 		return QDF_STATUS_E_FAILURE;
1425 	}
1426 
1427 	status = util_find_mlie(rcvd_frame->frame + ies_offset,
1428 				rcvd_frame->frame_length - ies_offset,
1429 				&ml_ie, &ml_ie_total_len);
1430 	if (QDF_IS_STATUS_ERROR(status))
1431 		return QDF_STATUS_SUCCESS;
1432 
1433 	status = util_get_bvmlie_persta_partner_info(ml_ie,
1434 						     ml_ie_total_len,
1435 						     &ml_partner_info);
1436 	if (QDF_IS_STATUS_ERROR(status)) {
1437 		mlme_err("Per STA profile parsing failed");
1438 		return status;
1439 	}
1440 
1441 	gen_frame_len = MAX_MGMT_MPDU_LEN;
1442 
1443 	gen_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len);
1444 	if (!gen_probe_rsp.ptr)
1445 		return QDF_STATUS_E_NOMEM;
1446 
1447 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rcvd_frame->vdev_id,
1448 						    WLAN_MLME_CM_ID);
1449 	if (!vdev) {
1450 		mlme_err("vdev object is NULL");
1451 		status = QDF_STATUS_E_NULL_VALUE;
1452 		goto done;
1453 	}
1454 	qdf_mem_copy(self_link_addr.bytes,
1455 		     wlan_vdev_mlme_get_macaddr(vdev),
1456 		     QDF_MAC_ADDR_SIZE);
1457 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
1458 
1459 	rcvd_probe_rsp.ptr = rcvd_frame->frame + WLAN_MAC_HDR_LEN_3A;
1460 	rcvd_probe_rsp.len = rcvd_frame->frame_length - WLAN_MAC_HDR_LEN_3A;
1461 
1462 	for (idx = 0; idx < ml_partner_info.num_partner_links; idx++) {
1463 		link_id = ml_partner_info.partner_link_info[idx].link_id;
1464 		status = util_gen_link_probe_rsp(rcvd_probe_rsp.ptr,
1465 				rcvd_probe_rsp.len,
1466 				link_id,
1467 				self_link_addr,
1468 				gen_probe_rsp.ptr,
1469 				gen_frame_len,
1470 				(qdf_size_t *)&gen_probe_rsp.len);
1471 		if (QDF_IS_STATUS_ERROR(status)) {
1472 			mlme_err("MLO: Link %d probe resp gen failed %d",
1473 				 link_id, status);
1474 			status = QDF_STATUS_E_FAILURE;
1475 			goto done;
1476 		}
1477 
1478 		mlme_debug("MLO: link probe rsp size:%u orig probe rsp :%u",
1479 			   gen_probe_rsp.len, rcvd_probe_rsp.len);
1480 
1481 		entry.vdev_id = rcvd_frame->vdev_id;
1482 		entry.frame = gen_probe_rsp.ptr;
1483 		entry.frame_length = gen_probe_rsp.len;
1484 		entry.rssi = rcvd_frame->rssi;
1485 
1486 		wlan_cm_add_frame_to_scan_db(psoc, &entry);
1487 	}
1488 done:
1489 	qdf_mem_free(gen_probe_rsp.ptr);
1490 
1491 	return status;
1492 }
1493 
1494 bool
1495 mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev *vdev)
1496 {
1497 	struct mlo_partner_info *partner_info;
1498 
1499 	if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
1500 		return true;
1501 
1502 	if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx ||
1503 	    !vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp)
1504 		return true;
1505 
1506 	partner_info =
1507 	       &vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp->ml_parnter_info;
1508 	if (partner_info->num_partner_links <= 1)
1509 		return true;
1510 
1511 	/* Roamed to MLO AP, do nothing if link vdev is disconnected */
1512 	return false;
1513 }
1514