1 /*
2  * Copyright (c) 2021-2024 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
mlo_check_connect_req_bmap(struct wlan_objmgr_vdev * vdev)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
mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t ml_link_vdev_id)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
mlo_cleanup_link(struct wlan_objmgr_vdev * vdev,uint8_t num_setup_links)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
mlo_update_vdev_after_roam(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t num_setup_links)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
mlo_clear_link_bmap(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)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
mlo_roam_abort_req(struct wlan_objmgr_psoc * psoc,uint8_t * event,uint8_t vdev_id)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
mlo_clear_link_bmap(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)182 mlo_clear_link_bmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
183 {}
184 
185 static inline void
mlo_update_vdev_after_roam(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t num_setup_links)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
mlo_cleanup_link(struct wlan_objmgr_vdev * vdev,uint8_t num_setup_links)191 mlo_cleanup_link(struct wlan_objmgr_vdev *vdev, uint8_t num_setup_links)
192 {}
193 
194 static inline void
mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t ml_link_vdev_id)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
mlo_check_connect_req_bmap(struct wlan_objmgr_vdev * vdev)201 mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev)
202 {
203 	return false;
204 }
205 
206 static inline QDF_STATUS
mlo_roam_abort_req(struct wlan_objmgr_psoc * psoc,uint8_t * event,uint8_t vdev_id)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 
mlo_roam_update_vdev_macaddr(struct wlan_objmgr_psoc * psoc,struct roam_offload_synch_ind * sync_ind,uint8_t vdev_id,bool is_non_ml_connection)214 static void mlo_roam_update_vdev_macaddr(struct wlan_objmgr_psoc *psoc,
215 					 struct roam_offload_synch_ind *sync_ind,
216 					 uint8_t vdev_id,
217 					 bool is_non_ml_connection)
218 {
219 	struct wlan_objmgr_vdev *vdev;
220 	struct qdf_mac_addr *mld_mac;
221 
222 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
223 						    vdev_id,
224 						    WLAN_MLO_MGR_ID);
225 	if (!vdev) {
226 		mlo_err("VDEV is null");
227 		return;
228 	}
229 
230 	if (is_non_ml_connection) {
231 		mld_mac = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
232 		if (!qdf_is_macaddr_zero(mld_mac))
233 			wlan_vdev_mlme_set_macaddr(vdev, mld_mac->bytes);
234 	} else {
235 		struct qdf_mac_addr *vdev_link_addr;
236 		uint8_t i;
237 
238 		wlan_vdev_mlme_set_macaddr(vdev,
239 					   wlan_vdev_mlme_get_linkaddr(vdev));
240 		/* Update the link address received from fw to assoc vdev */
241 		for (i = 0; i < sync_ind->num_setup_links; i++) {
242 			if (vdev_id != sync_ind->ml_link[i].vdev_id)
243 				continue;
244 
245 			vdev_link_addr = &sync_ind->ml_link[i].self_link_addr;
246 			if (qdf_is_macaddr_zero(vdev_link_addr) ||
247 			    qdf_is_macaddr_broadcast(vdev_link_addr))
248 				continue;
249 
250 			wlan_vdev_mlme_set_macaddr(vdev, vdev_link_addr->bytes);
251 			wlan_vdev_mlme_set_linkaddr(vdev,
252 						    vdev_link_addr->bytes);
253 		}
254 	}
255 
256 	mlme_debug("vdev_id %d self mac " QDF_MAC_ADDR_FMT,
257 		   vdev_id,
258 		   QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)));
259 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
260 }
261 
mlo_fw_roam_sync_req(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,void * event,uint32_t event_data_len)262 QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
263 				void *event, uint32_t event_data_len)
264 {
265 	struct roam_offload_synch_ind *sync_ind;
266 	QDF_STATUS status;
267 	uint8_t i;
268 	bool is_non_mlo_ap = false;
269 
270 	sync_ind = (struct roam_offload_synch_ind *)event;
271 	if (!sync_ind)
272 		return QDF_STATUS_E_FAILURE;
273 
274 	for (i = 0; i < sync_ind->num_setup_links; i++)
275 		mlo_update_for_multi_link_roam(psoc, vdev_id,
276 					       sync_ind->ml_link[i].vdev_id);
277 
278 	if (!sync_ind->num_setup_links) {
279 		mlo_debug("MLO_ROAM: Roamed to Legacy");
280 		is_non_mlo_ap = true;
281 		mlo_set_single_link_ml_roaming(psoc, vdev_id, false);
282 	} else if (sync_ind->num_setup_links == 1 ||
283 		sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) {
284 		mlo_debug("MLO_ROAM: Roamed to single link MLO");
285 		mlo_set_single_link_ml_roaming(psoc, vdev_id, true);
286 	} else {
287 		mlo_debug("MLO_ROAM: Roamed to MLO with %d links",
288 			  sync_ind->num_setup_links);
289 		mlo_set_single_link_ml_roaming(psoc, vdev_id, false);
290 	}
291 
292 	mlo_roam_update_vdev_macaddr(psoc, sync_ind, vdev_id, is_non_mlo_ap);
293 	ml_nlink_conn_change_notify(
294 		psoc, vdev_id, ml_nlink_roam_sync_start_evt, NULL);
295 
296 	status = cm_fw_roam_sync_req(psoc, vdev_id, event, event_data_len);
297 
298 	if (QDF_IS_STATUS_ERROR(status))
299 		mlo_clear_link_bmap(psoc, vdev_id);
300 
301 	return status;
302 }
303 
304 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
305 static struct mlo_link_info *
mlo_mgr_get_link_info_by_self_addr(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * self_addr)306 mlo_mgr_get_link_info_by_self_addr(struct wlan_objmgr_vdev *vdev,
307 				   struct qdf_mac_addr *self_addr)
308 {
309 	uint8_t iter;
310 	struct mlo_link_info *mlo_link;
311 
312 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx ||
313 	    !self_addr || qdf_is_macaddr_zero(self_addr))
314 		return NULL;
315 
316 	for (iter = 0; iter < WLAN_MAX_ML_BSS_LINKS; iter++) {
317 		mlo_link = &vdev->mlo_dev_ctx->link_ctx->links_info[iter];
318 
319 		if (qdf_is_macaddr_equal(&mlo_link->link_addr, self_addr))
320 			return mlo_link;
321 	}
322 
323 	return NULL;
324 }
325 
326 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
mlo_mgr_num_roam_links(struct wlan_objmgr_vdev * vdev)327 uint8_t mlo_mgr_num_roam_links(struct wlan_objmgr_vdev *vdev)
328 {
329 	struct wlan_cm_connect_resp *reassoc_rsp;
330 
331 	if (!vdev->mlo_dev_ctx)
332 		return 1;
333 
334 	if (!vdev->mlo_dev_ctx->sta_ctx)
335 		return 0;
336 
337 	reassoc_rsp = vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp;
338 	if (!reassoc_rsp || !reassoc_rsp->roaming_info)
339 		return 0;
340 
341 	return reassoc_rsp->roaming_info->num_setup_links;
342 }
343 #endif
344 
mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev * vdev,struct ml_setup_link_param * src_link_info,struct wlan_channel * channel)345 void mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev *vdev,
346 				      struct ml_setup_link_param *src_link_info,
347 				      struct wlan_channel *channel)
348 {
349 	struct mlo_link_info *link_info;
350 
351 	if (!src_link_info)
352 		return;
353 
354 	link_info = mlo_mgr_get_link_info_by_self_addr(vdev,
355 						       &src_link_info->self_link_addr);
356 	if (!link_info) {
357 		mlo_err("No link info found for vdev %d with " QDF_MAC_ADDR_FMT,
358 			src_link_info->vdev_id,
359 			QDF_MAC_ADDR_REF(src_link_info->self_link_addr.bytes));
360 		QDF_BUG(0);
361 		return;
362 	}
363 
364 	if (link_info->vdev_id != src_link_info->vdev_id) {
365 		mlo_err("Host(%d)-FW(%d) VDEV-MAC addr mismatch",
366 			link_info->vdev_id, src_link_info->vdev_id);
367 		QDF_BUG(0);
368 		return;
369 	}
370 
371 	link_info->link_id = src_link_info->link_id;
372 	qdf_copy_macaddr(&link_info->ap_link_addr, &src_link_info->link_addr);
373 	qdf_mem_copy(link_info->link_chan_info, channel, sizeof(*channel));
374 
375 	mlo_debug("link_id: %d, vdev_id:%d freq:%d ap_link_addr: "QDF_MAC_ADDR_FMT", self_link_addr: "QDF_MAC_ADDR_FMT,
376 		  link_info->link_id, link_info->vdev_id,
377 		  link_info->link_chan_info->ch_freq,
378 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes),
379 		  QDF_MAC_ADDR_REF(link_info->link_addr.bytes));
380 }
381 
mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev * vdev,void * event,uint32_t event_data_len)382 QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev,
383 			       void *event, uint32_t event_data_len)
384 {
385 	QDF_STATUS status;
386 	struct roam_offload_synch_ind *sync_ind;
387 	struct wlan_objmgr_psoc *psoc;
388 	struct wlan_objmgr_vdev *link_vdev = NULL;
389 	uint8_t i;
390 	uint8_t vdev_id;
391 
392 	sync_ind = (struct roam_offload_synch_ind *)event;
393 	vdev_id = wlan_vdev_get_id(vdev);
394 	psoc = wlan_vdev_get_psoc(vdev);
395 
396 	/* Clean up link vdev in following cases
397 	 * 1. When roamed to legacy, num_setup_links = 0
398 	 * 2. When roamed to single link, num_setup_links = 1
399 	 * 3. Roamed to AP with auth_status = ROAMED_AUTH_STATUS_CONNECTED
400 	 */
401 	if (sync_ind->num_setup_links < 2 ||
402 	    sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) {
403 		mlme_debug("Roam auth status %d", sync_ind->auth_status);
404 		mlo_update_vdev_after_roam(psoc, vdev_id,
405 					   sync_ind->num_setup_links);
406 	}
407 
408 	/* If EAPOL is offloaded to supplicant, link vdev/s are not up
409 	 * at FW, in that case complete roam sync on assoc vdev
410 	 * link vdev will be initialized after set key is complete.
411 	 */
412 	if (sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED)
413 		return QDF_STATUS_SUCCESS;
414 
415 	for (i = 0; i < sync_ind->num_setup_links; i++) {
416 		if (vdev_id == sync_ind->ml_link[i].vdev_id)
417 			continue;
418 
419 		/* Standby Link */
420 		if (sync_ind->ml_link[i].vdev_id == WLAN_INVALID_VDEV_ID)
421 			continue;
422 
423 		link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
424 								 sync_ind->ml_link[i].vdev_id,
425 								 WLAN_MLME_SB_ID);
426 		if (!link_vdev) {
427 			mlo_err("Link vdev:%d is null",
428 				sync_ind->ml_link[i].vdev_id);
429 			return QDF_STATUS_E_FAILURE;
430 		}
431 
432 		if (mlo_check_connect_req_bmap(link_vdev)) {
433 			struct qdf_mac_addr *vdev_link_addr;
434 
435 			mlo_update_connect_req_links(link_vdev, false);
436 
437 			vdev_link_addr = &sync_ind->ml_link[i].self_link_addr;
438 			if (!qdf_is_macaddr_zero(vdev_link_addr) &&
439 			    !qdf_is_macaddr_broadcast(vdev_link_addr)) {
440 				wlan_vdev_mlme_set_macaddr(link_vdev,
441 							   vdev_link_addr->bytes);
442 				wlan_vdev_mlme_set_linkaddr(link_vdev,
443 							    vdev_link_addr->bytes);
444 			}
445 
446 			status = cm_fw_roam_sync_req(psoc,
447 						     sync_ind->ml_link[i].vdev_id,
448 						     event, event_data_len);
449 			if (QDF_IS_STATUS_ERROR(status)) {
450 				mlo_clear_connect_req_links_bmap(link_vdev);
451 				mlo_roam_abort_req(psoc, event,
452 						   sync_ind->ml_link[i].vdev_id);
453 				wlan_objmgr_vdev_release_ref(link_vdev,
454 							     WLAN_MLME_SB_ID);
455 				return QDF_STATUS_E_FAILURE;
456 			}
457 		}
458 		wlan_objmgr_vdev_release_ref(link_vdev,
459 					     WLAN_MLME_SB_ID);
460 	}
461 
462 	return QDF_STATUS_SUCCESS;
463 }
464 #endif
465 
466 void
mlo_fw_ho_fail_req(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,struct qdf_mac_addr bssid)467 mlo_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc,
468 		   uint8_t vdev_id, struct qdf_mac_addr bssid)
469 {
470 	struct wlan_objmgr_vdev *vdev;
471 	struct wlan_mlo_dev_context *mlo_dev_ctx;
472 	uint8_t i;
473 
474 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
475 						    vdev_id,
476 						    WLAN_MLME_SB_ID);
477 
478 	if (!vdev) {
479 		mlo_err("vdev is null");
480 		return;
481 	}
482 
483 	if (!vdev->mlo_dev_ctx)
484 		goto end;
485 
486 	mlo_dev_ctx = vdev->mlo_dev_ctx;
487 
488 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
489 		if (!mlo_dev_ctx->wlan_vdev_list[i] ||
490 		    mlo_dev_ctx->wlan_vdev_list[i] == vdev)
491 			continue;
492 		cm_fw_ho_fail_req(psoc,
493 				  wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]),
494 				  bssid);
495 	}
496 
497 end:
498 	cm_fw_ho_fail_req(psoc, vdev_id, bssid);
499 	wlan_objmgr_vdev_release_ref(vdev,
500 				     WLAN_MLME_SB_ID);
501 }
502 
503 QDF_STATUS
mlo_get_sta_link_mac_addr(uint8_t vdev_id,struct roam_offload_synch_ind * sync_ind,struct qdf_mac_addr * link_mac_addr)504 mlo_get_sta_link_mac_addr(uint8_t vdev_id,
505 			  struct roam_offload_synch_ind *sync_ind,
506 			  struct qdf_mac_addr *link_mac_addr)
507 {
508 	QDF_STATUS status = QDF_STATUS_SUCCESS;
509 	uint8_t i;
510 
511 	if (!sync_ind || !sync_ind->num_setup_links)
512 		return QDF_STATUS_E_FAILURE;
513 
514 	for (i = 0; i < sync_ind->num_setup_links; i++) {
515 		if (sync_ind->ml_link[i].vdev_id == vdev_id) {
516 			qdf_copy_macaddr(link_mac_addr,
517 					 &sync_ind->ml_link[i].link_addr);
518 			return status;
519 		}
520 	}
521 
522 	if (i == sync_ind->num_setup_links) {
523 		mlo_err("Link mac addr not found");
524 		status = QDF_STATUS_E_FAILURE;
525 	}
526 
527 	return status;
528 }
529 
530 uint32_t
mlo_roam_get_chan_freq(uint8_t vdev_id,struct roam_offload_synch_ind * sync_ind)531 mlo_roam_get_chan_freq(uint8_t vdev_id,
532 		       struct roam_offload_synch_ind *sync_ind)
533 {
534 	uint8_t i;
535 
536 	if (!sync_ind || !sync_ind->num_setup_links)
537 		return 0;
538 
539 	for (i = 0; i < sync_ind->num_setup_links; i++) {
540 		if (sync_ind->ml_link[i].vdev_id == vdev_id)
541 			return sync_ind->ml_link[i].channel.mhz;
542 	}
543 
544 	return 0;
545 }
546 
547 uint32_t
mlo_roam_get_link_id(uint8_t vdev_id,struct roam_offload_synch_ind * sync_ind)548 mlo_roam_get_link_id(uint8_t vdev_id,
549 		     struct roam_offload_synch_ind *sync_ind)
550 {
551 	uint8_t i;
552 
553 	if (!sync_ind || !sync_ind->num_setup_links)
554 		return 0;
555 
556 	for (i = 0; i < sync_ind->num_setup_links; i++) {
557 		if (sync_ind->ml_link[i].vdev_id == vdev_id)
558 			return sync_ind->ml_link[i].link_id;
559 	}
560 
561 	return 0;
562 }
563 
is_multi_link_roam(struct roam_offload_synch_ind * sync_ind)564 bool is_multi_link_roam(struct roam_offload_synch_ind *sync_ind)
565 {
566 	if (!sync_ind)
567 		return false;
568 
569 	if (sync_ind->num_setup_links)
570 		return true;
571 
572 	return false;
573 }
574 
575 uint8_t
mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind * sync_ind)576 mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind *sync_ind)
577 {
578 	if (!sync_ind) {
579 		mlo_err("Roam Sync ind is null");
580 		return WLAN_INVALID_VDEV_ID;
581 	}
582 
583 	return sync_ind->num_setup_links;
584 }
585 
586 uint32_t
mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind * sync_ind,uint8_t * link_mac_addr)587 mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind *sync_ind,
588 				     uint8_t *link_mac_addr)
589 {
590 	uint8_t i;
591 
592 	if (!sync_ind)
593 		return 0;
594 
595 	/* Non-MLO roaming */
596 	if (!sync_ind->num_setup_links)
597 		return sync_ind->chan_freq;
598 
599 	if (!link_mac_addr) {
600 		mlo_debug("link_mac_addr is NULL");
601 		return 0;
602 	}
603 
604 	for (i = 0; i < sync_ind->num_setup_links; i++)
605 		if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes,
606 				 link_mac_addr,
607 				 QDF_MAC_ADDR_SIZE))
608 			return sync_ind->ml_link[i].channel.mhz;
609 
610 	mlo_debug("Mac address not found in ml_link info" QDF_MAC_ADDR_FMT,
611 		  QDF_MAC_ADDR_REF(link_mac_addr));
612 
613 	return 0;
614 }
615 
616 QDF_STATUS
mlo_roam_get_link_id_from_mac_addr(struct roam_offload_synch_ind * sync_ind,uint8_t * link_mac_addr,uint32_t * link_id)617 mlo_roam_get_link_id_from_mac_addr(struct roam_offload_synch_ind *sync_ind,
618 				   uint8_t *link_mac_addr, uint32_t *link_id)
619 {
620 	uint8_t i;
621 
622 	if (!sync_ind || !sync_ind->num_setup_links || !link_mac_addr)
623 		return QDF_STATUS_E_INVAL;
624 
625 	for (i = 0; i < sync_ind->num_setup_links; i++)
626 		if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes,
627 				 link_mac_addr,
628 				 QDF_MAC_ADDR_SIZE)) {
629 			*link_id = sync_ind->ml_link[i].link_id;
630 			return QDF_STATUS_SUCCESS;
631 		}
632 
633 	return QDF_STATUS_E_INVAL;
634 }
635 
mlo_enable_rso(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * rsp)636 QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev,
637 			  struct wlan_objmgr_vdev *vdev,
638 			  struct wlan_cm_connect_resp *rsp)
639 {
640 	struct wlan_objmgr_vdev *assoc_vdev;
641 	uint8_t num_partner_links;
642 
643 	if (!rsp) {
644 		mlo_err("Connect resp is null");
645 		return QDF_STATUS_E_NULL_VALUE;
646 	}
647 
648 	num_partner_links = rsp->ml_parnter_info.num_partner_links;
649 
650 	if (num_partner_links &&
651 	    (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) ||
652 	     !mlo_check_if_all_links_up(vdev)))
653 		return QDF_STATUS_SUCCESS;
654 
655 	assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
656 	if (!assoc_vdev) {
657 		mlo_err("Assoc vdev is null");
658 		return QDF_STATUS_E_NULL_VALUE;
659 	}
660 	cm_roam_start_init_on_connect(pdev, wlan_vdev_get_id(assoc_vdev));
661 
662 	return QDF_STATUS_SUCCESS;
663 }
664 
665 void
mlo_roam_copy_partner_info(struct mlo_partner_info * partner_info,struct roam_offload_synch_ind * sync_ind,uint8_t skip_vdev_id,bool fill_all_links)666 mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info,
667 			   struct roam_offload_synch_ind *sync_ind,
668 			   uint8_t skip_vdev_id, bool fill_all_links)
669 {
670 	uint8_t i, j;
671 	struct mlo_link_info *link;
672 
673 	if (!sync_ind)
674 		return;
675 
676 	for (i = 0, j = 0; i < sync_ind->num_setup_links; i++) {
677 		if (!fill_all_links &&
678 		    sync_ind->ml_link[i].vdev_id == skip_vdev_id)
679 			continue;
680 
681 		link = &partner_info->partner_link_info[j];
682 		link->link_id = sync_ind->ml_link[i].link_id;
683 		link->vdev_id = sync_ind->ml_link[i].vdev_id;
684 
685 		qdf_copy_macaddr(&link->link_addr,
686 				 &sync_ind->ml_link[i].link_addr);
687 		link->chan_freq = sync_ind->ml_link[i].channel.mhz;
688 		mlo_debug("vdev_id %d link_id %d freq %d bssid" QDF_MAC_ADDR_FMT,
689 			  link->vdev_id, link->link_id, link->chan_freq,
690 			  QDF_MAC_ADDR_REF(link->link_addr.bytes));
691 		j++;
692 	}
693 	partner_info->num_partner_links = j;
694 	mlo_debug("vdev_to_skip:%d num_setup_links %d fill_all_links:%d",
695 		  skip_vdev_id, partner_info->num_partner_links,
696 		  fill_all_links);
697 }
698 
mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev * vdev,struct roam_offload_synch_ind * sync_ind)699 void mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev *vdev,
700 			   struct roam_offload_synch_ind *sync_ind)
701 {
702 	uint8_t i;
703 	struct wlan_mlo_dev_context *mlo_dev_ctx;
704 
705 	if (!vdev) {
706 		mlo_err("vdev is NULL");
707 		return;
708 	}
709 
710 	mlo_dev_ctx = vdev->mlo_dev_ctx;
711 	if (!mlo_dev_ctx) {
712 		mlo_err("ML dev ctx is NULL");
713 		return;
714 	}
715 
716 	mlo_clear_cu_bpcc(vdev);
717 	for (i = 0; i < sync_ind->num_setup_links; i++)
718 		mlo_init_cu_bpcc(mlo_dev_ctx, sync_ind->ml_link[i].vdev_id);
719 
720 	mlo_debug("update cu info from roam sync");
721 }
722 
723 void
mlo_roam_update_connected_links(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * connect_rsp)724 mlo_roam_update_connected_links(struct wlan_objmgr_vdev *vdev,
725 				struct wlan_cm_connect_resp *connect_rsp)
726 {
727 	mlo_clear_connected_links_bmap(vdev);
728 	if (mlo_get_single_link_ml_roaming(wlan_vdev_get_psoc(vdev),
729 					   wlan_vdev_get_id(vdev)))
730 		mlo_update_connected_links(vdev, 1);
731 	else
732 		mlo_update_connected_links_bmap(vdev->mlo_dev_ctx,
733 						connect_rsp->ml_parnter_info);
734 }
735 
736 QDF_STATUS
wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc * psoc,uint8_t * event,uint8_t vdev_id)737 wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc *psoc,
738 			    uint8_t *event, uint8_t vdev_id)
739 {
740 	uint8_t i;
741 	QDF_STATUS status;
742 	struct roam_offload_synch_ind *sync_ind = NULL;
743 
744 	sync_ind = (struct roam_offload_synch_ind *)event;
745 
746 	if (!sync_ind) {
747 		mlo_err("Roam Sync ind ptr is NULL");
748 		return QDF_STATUS_E_NULL_VALUE;
749 	}
750 
751 	for (i = 0; i < sync_ind->num_setup_links; i++) {
752 		if (sync_ind->ml_link[i].vdev_id != vdev_id) {
753 			status = cm_fw_roam_abort_req(psoc,
754 						      sync_ind->ml_link[i].vdev_id);
755 			if (QDF_IS_STATUS_ERROR(status)) {
756 				mlo_err("LFR3: Fail to abort roam on vdev: %u",
757 					sync_ind->ml_link[i].vdev_id);
758 			}
759 		}
760 	}
761 
762 	return QDF_STATUS_SUCCESS;
763 }
764 
765 void
mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,bool is_single_link_ml_roaming)766 mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc,
767 			       uint8_t vdev_id,
768 			       bool is_single_link_ml_roaming)
769 {
770 	struct wlan_objmgr_vdev *vdev;
771 
772 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
773 						    vdev_id,
774 						    WLAN_MLME_SB_ID);
775 	if (!vdev) {
776 		mlo_err("VDEV is null");
777 		return;
778 	}
779 
780 	if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
781 		mlme_set_single_link_mlo_roaming(vdev,
782 						 is_single_link_ml_roaming);
783 
784 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
785 }
786 
787 bool
mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)788 mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc,
789 			       uint8_t vdev_id)
790 {
791 	bool is_single_link_ml_roaming = false;
792 	struct wlan_objmgr_vdev *vdev;
793 
794 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
795 						    vdev_id,
796 						    WLAN_MLME_SB_ID);
797 	if (!vdev) {
798 		mlo_err("VDEV is null");
799 		return is_single_link_ml_roaming;
800 	}
801 
802 	is_single_link_ml_roaming = mlme_get_single_link_mlo_roaming(vdev);
803 	mlo_debug("MLO:is_single_link_ml_roaming %d",
804 		  is_single_link_ml_roaming);
805 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
806 
807 	return is_single_link_ml_roaming;
808 }
809 
810 QDF_STATUS
mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id,struct roam_offload_synch_ind * sync_ind,struct qdf_mac_addr * bssid,wmi_channel * chan)811 mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id,
812 				 struct roam_offload_synch_ind *sync_ind,
813 				 struct qdf_mac_addr *bssid,
814 				 wmi_channel *chan)
815 {
816 	QDF_STATUS status = QDF_STATUS_SUCCESS;
817 	uint8_t i;
818 
819 	if (!sync_ind || !sync_ind->num_setup_links)
820 		return QDF_STATUS_E_FAILURE;
821 
822 	for (i = 0; i < sync_ind->num_setup_links; i++) {
823 		if (vdev_id == sync_ind->ml_link[i].vdev_id) {
824 			qdf_mem_copy(chan, &sync_ind->ml_link[i].channel,
825 				     sizeof(wmi_channel));
826 			qdf_copy_macaddr(bssid,
827 					 &sync_ind->ml_link[i].link_addr);
828 			return status;
829 		}
830 	}
831 
832 	if (i == sync_ind->num_setup_links) {
833 		mlo_err("roam sync info not found for vdev id %d", vdev_id);
834 		status = QDF_STATUS_E_FAILURE;
835 	}
836 
837 	return status;
838 }
839 
840 bool
mlo_check_if_all_links_up(struct wlan_objmgr_vdev * vdev)841 mlo_check_if_all_links_up(struct wlan_objmgr_vdev *vdev)
842 {
843 	struct wlan_mlo_dev_context *mlo_dev_ctx;
844 	struct wlan_mlo_sta *sta_ctx;
845 	uint8_t i;
846 
847 	if (!vdev || !vdev->mlo_dev_ctx) {
848 		mlo_err("Vdev is null");
849 		return false;
850 	}
851 
852 	mlo_dev_ctx = vdev->mlo_dev_ctx;
853 	if (!mlo_dev_ctx->sta_ctx) {
854 		mlo_err("mlo sta ctx is null");
855 		return false;
856 	}
857 
858 	sta_ctx = mlo_dev_ctx->sta_ctx;
859 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
860 		if (!mlo_dev_ctx->wlan_vdev_list[i])
861 			continue;
862 
863 		if (qdf_test_bit(i, sta_ctx->wlan_connected_links) &&
864 		    !wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) {
865 			mlo_debug("Vdev id %d is not in connected state",
866 				  wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]));
867 			return false;
868 		}
869 	}
870 
871 	if (i == WLAN_UMAC_MLO_MAX_VDEVS) {
872 		mlo_debug("all links are up");
873 		return true;
874 	}
875 
876 	return false;
877 }
878 
879 bool
mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev * vdev)880 mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev *vdev)
881 {
882 	struct wlan_mlo_dev_context *mlo_dev_ctx;
883 	struct wlan_mlo_sta *sta_ctx;
884 	uint8_t i;
885 
886 	if (!vdev || !vdev->mlo_dev_ctx) {
887 		mlo_err("Vdev is null");
888 		return false;
889 	}
890 
891 	if (QDF_IS_STATUS_ERROR(wlan_vdev_is_up(vdev))) {
892 		mlo_debug("Vdev id %d is not in up state",
893 			  wlan_vdev_get_id(vdev));
894 			return false;
895 	}
896 
897 	mlo_dev_ctx = vdev->mlo_dev_ctx;
898 	if (!mlo_dev_ctx->sta_ctx) {
899 		mlo_err("mlo sta ctx is null");
900 		return false;
901 	}
902 	sta_ctx = mlo_dev_ctx->sta_ctx;
903 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
904 		if (!mlo_dev_ctx->wlan_vdev_list[i])
905 			continue;
906 
907 		if ((qdf_test_bit(i, sta_ctx->wlan_connected_links) ||
908 		     qdf_test_bit(i, sta_ctx->wlan_connect_req_links)) &&
909 		    !QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(mlo_dev_ctx->wlan_vdev_list[i]))) {
910 			mlo_debug("Vdev id %d is not in up state",
911 				  wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]));
912 			return false;
913 		}
914 	}
915 
916 	if (i == WLAN_UMAC_MLO_MAX_VDEVS) {
917 		mlo_debug("all links are up");
918 		return true;
919 	}
920 
921 	return false;
922 }
923 
924 void
mlo_roam_set_link_id(struct wlan_objmgr_vdev * vdev,struct roam_offload_synch_ind * sync_ind)925 mlo_roam_set_link_id(struct wlan_objmgr_vdev *vdev,
926 		     struct roam_offload_synch_ind *sync_ind)
927 {
928 	uint8_t i;
929 	uint8_t j;
930 	struct wlan_mlo_dev_context *mlo_dev_ctx;
931 
932 	if (!vdev || !sync_ind || !vdev->mlo_dev_ctx) {
933 		mlo_debug("Invalid input");
934 		return;
935 	}
936 
937 	mlo_dev_ctx = vdev->mlo_dev_ctx;
938 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
939 		vdev = mlo_dev_ctx->wlan_vdev_list[i];
940 		if (!vdev)
941 			continue;
942 
943 		wlan_vdev_set_link_id(vdev, WLAN_LINK_ID_INVALID);
944 		for (j = 0; j < sync_ind->num_setup_links; j++) {
945 			if (sync_ind->ml_link[j].vdev_id ==
946 			    wlan_vdev_get_id(vdev)) {
947 				wlan_vdev_set_link_id(
948 					vdev, sync_ind->ml_link[j].link_id);
949 				mlme_debug("Set link for vdev id %d link id %d",
950 					   wlan_vdev_get_id(vdev),
951 					   sync_ind->ml_link[j].link_id);
952 			}
953 		}
954 	}
955 }
956 
957 QDF_STATUS
mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * link_mac_addr)958 mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
959 				       struct qdf_mac_addr *link_mac_addr)
960 {
961 	uint8_t i;
962 	struct wlan_mlo_sta *sta_ctx;
963 	struct wlan_cm_connect_resp *rsp;
964 	struct mlo_partner_info parnter_info;
965 	uint8_t vdev_id;
966 
967 	if (!vdev)
968 		return QDF_STATUS_E_NULL_VALUE;
969 
970 	vdev_id = wlan_vdev_get_id(vdev);
971 
972 	if (!vdev->mlo_dev_ctx) {
973 		mlo_err("mlo dev ctx is null, vdev id %d", vdev_id);
974 		return QDF_STATUS_E_NULL_VALUE;
975 	}
976 
977 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
978 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
979 	    !sta_ctx->copied_reassoc_rsp->roaming_info) {
980 		mlo_debug("sta ctx or copied reassoc rsp is null for vdev id %d", vdev_id);
981 		return QDF_STATUS_E_NULL_VALUE;
982 	}
983 
984 	rsp = sta_ctx->copied_reassoc_rsp;
985 	if (rsp->roaming_info->auth_status != ROAM_AUTH_STATUS_CONNECTED) {
986 		mlo_debug("Roam auth status is not connected");
987 		return QDF_STATUS_E_FAILURE;
988 	}
989 
990 	parnter_info = rsp->ml_parnter_info;
991 	for (i = 0; i < parnter_info.num_partner_links; i++) {
992 		if (parnter_info.partner_link_info[i].vdev_id == vdev_id) {
993 			qdf_copy_macaddr(link_mac_addr,
994 					 &parnter_info.partner_link_info[i].link_addr);
995 			return QDF_STATUS_SUCCESS;
996 		}
997 	}
998 
999 	if (i == parnter_info.num_partner_links) {
1000 		mlo_debug("Link mac addr not found");
1001 		return QDF_STATUS_E_FAILURE;
1002 	}
1003 
1004 	return QDF_STATUS_SUCCESS;
1005 }
1006 
1007 QDF_STATUS
mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * reassoc_rsp)1008 mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
1009 			  struct wlan_cm_connect_resp *reassoc_rsp)
1010 {
1011 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1012 	struct wlan_mlo_sta *sta_ctx;
1013 	struct wlan_connect_rsp_ies *connect_ies;
1014 
1015 	if (!vdev)
1016 		return QDF_STATUS_E_NULL_VALUE;
1017 
1018 	if (!reassoc_rsp)
1019 		return QDF_STATUS_E_NULL_VALUE;
1020 
1021 	/* Store reassoc rsp only if roamed to 2 link AP */
1022 	if (reassoc_rsp->ml_parnter_info.num_partner_links < 2)
1023 		return QDF_STATUS_E_INVAL;
1024 
1025 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1026 	if (!mlo_dev_ctx)
1027 		return QDF_STATUS_E_NULL_VALUE;
1028 
1029 	sta_ctx = mlo_dev_ctx->sta_ctx;
1030 	if (!sta_ctx)
1031 		return QDF_STATUS_E_NULL_VALUE;
1032 
1033 	wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1034 	/* Free assoc rsp, so that reassoc rsp can be used during
1035 	 * reassociation.
1036 	 */
1037 	if (sta_ctx->assoc_rsp.ptr) {
1038 		qdf_mem_free(sta_ctx->assoc_rsp.ptr);
1039 		sta_ctx->assoc_rsp.ptr = NULL;
1040 		sta_ctx->assoc_rsp.len = 0;
1041 	}
1042 
1043 	sta_ctx->ml_partner_info = reassoc_rsp->ml_parnter_info;
1044 
1045 	sta_ctx->copied_reassoc_rsp = qdf_mem_malloc(
1046 			sizeof(struct wlan_cm_connect_resp));
1047 	if (!sta_ctx->copied_reassoc_rsp)
1048 		return QDF_STATUS_E_NOMEM;
1049 
1050 	qdf_mem_copy(sta_ctx->copied_reassoc_rsp, reassoc_rsp,
1051 		     sizeof(struct wlan_cm_connect_resp));
1052 
1053 	sta_ctx->copied_reassoc_rsp->roaming_info = qdf_mem_malloc(
1054 			sizeof(struct wlan_roam_sync_info));
1055 
1056 	if (!sta_ctx->copied_reassoc_rsp->roaming_info) {
1057 		qdf_mem_free(sta_ctx->copied_reassoc_rsp);
1058 		sta_ctx->copied_reassoc_rsp = NULL;
1059 		return QDF_STATUS_E_NOMEM;
1060 	}
1061 
1062 	qdf_mem_copy(sta_ctx->copied_reassoc_rsp->roaming_info,
1063 		     reassoc_rsp->roaming_info,
1064 		     sizeof(struct wlan_roam_sync_info));
1065 
1066 	connect_ies = &sta_ctx->copied_reassoc_rsp->connect_ies;
1067 
1068 	connect_ies->assoc_rsp.len =
1069 		reassoc_rsp->connect_ies.assoc_rsp.len;
1070 
1071 	connect_ies->assoc_rsp.ptr = qdf_mem_malloc(
1072 			connect_ies->assoc_rsp.len);
1073 
1074 	if (!connect_ies->assoc_rsp.ptr) {
1075 		qdf_mem_free(sta_ctx->copied_reassoc_rsp->roaming_info);
1076 		sta_ctx->copied_reassoc_rsp->roaming_info = NULL;
1077 		qdf_mem_free(sta_ctx->copied_reassoc_rsp);
1078 		sta_ctx->copied_reassoc_rsp = NULL;
1079 		return QDF_STATUS_E_NOMEM;
1080 	}
1081 
1082 	qdf_mem_copy(connect_ies->assoc_rsp.ptr,
1083 		     reassoc_rsp->connect_ies.assoc_rsp.ptr,
1084 		     reassoc_rsp->connect_ies.assoc_rsp.len);
1085 
1086 	connect_ies->assoc_req.len = 0;
1087 	connect_ies->assoc_req.ptr = NULL;
1088 	connect_ies->bcn_probe_rsp.len = 0;
1089 	connect_ies->bcn_probe_rsp.ptr = NULL;
1090 	connect_ies->link_bcn_probe_rsp.len = 0;
1091 	connect_ies->link_bcn_probe_rsp.ptr = NULL;
1092 	connect_ies->fils_ie = NULL;
1093 
1094 	mlo_debug("Copied reassoc response for vdev: %d len: %d",
1095 		  wlan_vdev_get_id(vdev), connect_ies->assoc_rsp.len);
1096 
1097 	return QDF_STATUS_SUCCESS;
1098 }
1099 
1100 static bool
mlo_roam_is_internal_disconnect(struct wlan_objmgr_vdev * link_vdev)1101 mlo_roam_is_internal_disconnect(struct wlan_objmgr_vdev *link_vdev)
1102 {
1103 	struct wlan_cm_vdev_discon_req *disconn_req;
1104 
1105 	if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) &&
1106 	    wlan_cm_is_vdev_disconnecting(link_vdev)) {
1107 		mlo_debug("Disconnect is ongoing on vdev %d",
1108 			  wlan_vdev_get_id(link_vdev));
1109 
1110 		disconn_req = qdf_mem_malloc(sizeof(*disconn_req));
1111 		if (!disconn_req) {
1112 			mlme_err("Malloc failed for disconnect req");
1113 			return false;
1114 		}
1115 
1116 		if (!wlan_cm_get_active_disconnect_req(link_vdev,
1117 						       disconn_req)) {
1118 			mlme_err("vdev: %d: Active disconnect not found",
1119 				 wlan_vdev_get_id(link_vdev));
1120 			qdf_mem_free(disconn_req);
1121 			return false;
1122 		}
1123 
1124 		mlo_debug("Disconnect source %d", disconn_req->req.source);
1125 
1126 		if (disconn_req->req.source == CM_MLO_ROAM_INTERNAL_DISCONNECT) {
1127 			qdf_mem_free(disconn_req);
1128 			return true;
1129 		}
1130 
1131 		qdf_mem_free(disconn_req);
1132 	}
1133 	/* Disconnect is not ongoing */
1134 	return true;
1135 }
1136 
1137 static QDF_STATUS
mlo_roam_validate_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_vdev * link_vdev,struct wlan_cm_connect_resp * rsp)1138 mlo_roam_validate_req(struct wlan_objmgr_vdev *vdev,
1139 		      struct wlan_objmgr_vdev *link_vdev,
1140 		      struct wlan_cm_connect_resp *rsp)
1141 {
1142 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1143 	struct wlan_mlo_sta *sta_ctx;
1144 
1145 	if (!vdev) {
1146 		mlo_debug_rl("vdev is NULL");
1147 		return QDF_STATUS_E_NULL_VALUE;
1148 	}
1149 
1150 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1151 	if (!mlo_dev_ctx) {
1152 		mlo_debug_rl("mlo_dev_ctx is NULL");
1153 		return QDF_STATUS_E_NULL_VALUE;
1154 	}
1155 
1156 	sta_ctx = mlo_dev_ctx->sta_ctx;
1157 	if (sta_ctx && sta_ctx->disconn_req) {
1158 		mlo_debug("Handle pending disconnect for vdev %d",
1159 			  wlan_vdev_get_id(vdev));
1160 		mlo_handle_pending_disconnect(vdev);
1161 		return QDF_STATUS_E_FAILURE;
1162 	}
1163 
1164 	if (wlan_cm_is_vdev_disconnected(vdev) ||
1165 	    (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) &&
1166 	     (wlan_cm_is_vdev_connecting(link_vdev) ||
1167 	      !mlo_roam_is_internal_disconnect(link_vdev)))) {
1168 		if (sta_ctx) {
1169 			if (sta_ctx->copied_reassoc_rsp) {
1170 				wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1171 				sta_ctx->copied_reassoc_rsp = NULL;
1172 			}
1173 			copied_conn_req_lock_acquire(sta_ctx);
1174 			if (sta_ctx->copied_conn_req) {
1175 				wlan_cm_free_connect_req(sta_ctx->copied_conn_req);
1176 				sta_ctx->copied_conn_req = NULL;
1177 			}
1178 			copied_conn_req_lock_release(sta_ctx);
1179 		}
1180 	}
1181 
1182 	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1183 		mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev));
1184 		if (wlan_cm_is_vdev_disconnected(vdev)) {
1185 			mlo_handle_sta_link_connect_failure(vdev, rsp);
1186 			return QDF_STATUS_E_FAILURE;
1187 		} else if (!wlan_cm_is_vdev_connected(vdev)) {
1188 			/* If vdev is not in disconnected or connected state,
1189 			 * then the event is received due to connect req being
1190 			 * flushed. Hence, ignore this event
1191 			 */
1192 			if (sta_ctx && sta_ctx->copied_reassoc_rsp) {
1193 				wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1194 				sta_ctx->copied_reassoc_rsp = NULL;
1195 			}
1196 			return QDF_STATUS_E_FAILURE;
1197 		}
1198 	}
1199 
1200 	if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) &&
1201 	    (wlan_cm_is_vdev_connecting(link_vdev) ||
1202 	     !mlo_roam_is_internal_disconnect(link_vdev))) {
1203 		return QDF_STATUS_E_FAILURE;
1204 	}
1205 
1206 	if (sta_ctx && !wlan_vdev_mlme_is_mlo_link_vdev(vdev)) {
1207 		if (sta_ctx->assoc_rsp.ptr) {
1208 			qdf_mem_free(sta_ctx->assoc_rsp.ptr);
1209 			sta_ctx->assoc_rsp.ptr = NULL;
1210 		}
1211 		sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len;
1212 		sta_ctx->assoc_rsp.ptr =
1213 			qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len);
1214 		if (!sta_ctx->assoc_rsp.ptr)
1215 			return QDF_STATUS_E_FAILURE;
1216 		if (rsp->connect_ies.assoc_rsp.ptr)
1217 			qdf_mem_copy(sta_ctx->assoc_rsp.ptr,
1218 				     rsp->connect_ies.assoc_rsp.ptr,
1219 				     rsp->connect_ies.assoc_rsp.len);
1220 		/* Update connected_links_bmap for all vdev taking
1221 		 * part in association
1222 		 */
1223 		mlo_update_connected_links(vdev, 1);
1224 		mlo_update_connected_links_bmap(mlo_dev_ctx,
1225 						rsp->ml_parnter_info);
1226 	}
1227 
1228 	return QDF_STATUS_SUCCESS;
1229 }
1230 
1231 static QDF_STATUS
mlo_roam_prepare_and_send_link_connect_req(struct wlan_objmgr_vdev * assoc_vdev,struct wlan_objmgr_vdev * link_vdev,struct wlan_cm_connect_resp * rsp,struct qdf_mac_addr * link_addr,uint16_t chan_freq)1232 mlo_roam_prepare_and_send_link_connect_req(struct wlan_objmgr_vdev *assoc_vdev,
1233 					   struct wlan_objmgr_vdev *link_vdev,
1234 					   struct wlan_cm_connect_resp *rsp,
1235 					   struct qdf_mac_addr *link_addr,
1236 					   uint16_t chan_freq)
1237 {
1238 	struct wlan_mlo_sta *sta_ctx;
1239 	struct wlan_cm_connect_req req = {0};
1240 	struct wlan_ssid ssid = {0};
1241 	struct rso_config *rso_cfg;
1242 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1243 
1244 	if (!assoc_vdev->mlo_dev_ctx || !assoc_vdev->mlo_dev_ctx->sta_ctx)
1245 		return QDF_STATUS_E_FAILURE;
1246 
1247 	sta_ctx = assoc_vdev->mlo_dev_ctx->sta_ctx;
1248 
1249 	wlan_vdev_mlme_get_ssid(assoc_vdev, ssid.ssid,
1250 				&ssid.length);
1251 
1252 	req.vdev_id = wlan_vdev_get_id(link_vdev);
1253 	req.source = CM_MLO_LINK_VDEV_CONNECT;
1254 	req.chan_freq = chan_freq;
1255 	qdf_mem_copy(&req.bssid.bytes, link_addr->bytes, QDF_MAC_ADDR_SIZE);
1256 
1257 	req.ssid.length = ssid.length;
1258 	qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length);
1259 	qdf_copy_macaddr(&req.mld_addr, &rsp->mld_addr);
1260 
1261 	req.ml_parnter_info = rsp->ml_parnter_info;
1262 
1263 	rso_cfg = wlan_cm_get_rso_config(assoc_vdev);
1264 	if (rso_cfg) {
1265 		req.crypto.rsn_caps = rso_cfg->orig_sec_info.rsn_caps;
1266 		req.crypto.auth_type = rso_cfg->orig_sec_info.authmodeset;
1267 		req.crypto.ciphers_pairwise =
1268 				rso_cfg->orig_sec_info.ucastcipherset;
1269 		req.crypto.group_cipher = rso_cfg->orig_sec_info.mcastcipherset;
1270 		req.crypto.mgmt_ciphers = rso_cfg->orig_sec_info.mgmtcipherset;
1271 		req.crypto.akm_suites = rso_cfg->orig_sec_info.key_mgmt;
1272 		req.assoc_ie.len = rso_cfg->assoc_ie.len;
1273 
1274 		req.assoc_ie.ptr = qdf_mem_malloc(req.assoc_ie.len);
1275 		if (!req.assoc_ie.ptr)
1276 			return QDF_STATUS_E_NOMEM;
1277 
1278 		if (rso_cfg->assoc_ie.len)
1279 			qdf_mem_copy(req.assoc_ie.ptr, rso_cfg->assoc_ie.ptr,
1280 				     rso_cfg->assoc_ie.len);
1281 	}
1282 
1283 	mlme_cm_osif_roam_get_scan_params(assoc_vdev, &req.scan_ie,
1284 					  &req.dot11mode_filter);
1285 
1286 	mlme_info("vdev:%d Connecting to " QDF_SSID_FMT " link_addr: " QDF_MAC_ADDR_FMT " freq %d rsn_caps:0x%x auth_type:0x%x pairwise:0x%x grp:0x%x mcast:0x%x akms:0x%x assoc_ie_len:%d f_rsne:%d is_wps:%d dot11_filter:%d",
1287 		  req.vdev_id, QDF_SSID_REF(req.ssid.length, req.ssid.ssid),
1288 		  QDF_MAC_ADDR_REF(link_addr->bytes),
1289 		  req.chan_freq, req.crypto.rsn_caps, req.crypto.auth_type,
1290 		  req.crypto.ciphers_pairwise, req.crypto.group_cipher,
1291 		  req.crypto.mgmt_ciphers, req.crypto.akm_suites,
1292 		  req.assoc_ie.len, req.force_rsne_override,
1293 		  req.is_wps_connection, req.dot11mode_filter);
1294 
1295 	copied_conn_req_lock_acquire(sta_ctx);
1296 	if (!sta_ctx->copied_conn_req)
1297 		sta_ctx->copied_conn_req =
1298 			qdf_mem_malloc(sizeof(struct wlan_cm_connect_req));
1299 	else
1300 		wlan_cm_free_connect_req_param(sta_ctx->copied_conn_req);
1301 
1302 	if (!sta_ctx->copied_conn_req) {
1303 		mlo_err("MLO_ROAM: vdev:%d Failed to allocate connect req",
1304 			req.vdev_id);
1305 		copied_conn_req_lock_release(sta_ctx);
1306 		status = QDF_STATUS_E_NOMEM;
1307 		goto err;
1308 	}
1309 
1310 	qdf_mem_copy(sta_ctx->copied_conn_req, &req,
1311 		     sizeof(struct wlan_cm_connect_req));
1312 	mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req, &req);
1313 	copied_conn_req_lock_release(sta_ctx);
1314 
1315 	status = mlo_roam_validate_req(assoc_vdev, link_vdev, rsp);
1316 	if (QDF_IS_STATUS_ERROR(status))
1317 		goto err;
1318 
1319 	status = wlan_cm_start_connect(link_vdev, &req);
1320 	if (QDF_IS_STATUS_ERROR(status))
1321 		goto err;
1322 
1323 	mlo_update_connected_links(link_vdev, 1);
1324 err:
1325 	qdf_mem_free(req.assoc_ie.ptr);
1326 
1327 	return status;
1328 }
1329 
mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev * vdev)1330 void mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev *vdev)
1331 {
1332 	struct wlan_mlo_sta *sta_ctx;
1333 
1334 	if (!vdev)
1335 		return;
1336 
1337 	if (!vdev->mlo_dev_ctx)
1338 		return;
1339 
1340 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1341 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
1342 	    !sta_ctx->copied_reassoc_rsp->roaming_info)
1343 		return;
1344 
1345 	wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1346 	sta_ctx->copied_reassoc_rsp = NULL;
1347 }
1348 
mlo_roam_connect_complete(struct wlan_objmgr_vdev * vdev)1349 void mlo_roam_connect_complete(struct wlan_objmgr_vdev *vdev)
1350 {
1351 	struct wlan_mlo_sta *sta_ctx;
1352 	uint8_t auth_status;
1353 
1354 	if (!vdev)
1355 		return;
1356 
1357 	if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
1358 		return;
1359 
1360 	if (!vdev->mlo_dev_ctx)
1361 		return;
1362 
1363 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1364 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
1365 	    !sta_ctx->copied_reassoc_rsp->roaming_info)
1366 		return;
1367 
1368 	auth_status = sta_ctx->copied_reassoc_rsp->roaming_info->auth_status;
1369 	if (!mlo_check_connect_req_bmap(vdev) &&
1370 	    auth_status == ROAM_AUTH_STATUS_CONNECTED) {
1371 		wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1372 		sta_ctx->copied_reassoc_rsp = NULL;
1373 	}
1374 }
1375 
1376 bool
mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)1377 mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1378 {
1379 	bool status = false;
1380 	struct wlan_mlo_sta *sta_ctx;
1381 	struct wlan_cm_connect_resp *rsp;
1382 	struct wlan_objmgr_vdev *vdev;
1383 
1384 	if (!psoc)
1385 		return status;
1386 
1387 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1388 						    WLAN_MLME_SB_ID);
1389 	if (!vdev)
1390 		return status;
1391 
1392 	if (!vdev->mlo_dev_ctx)
1393 		goto end;
1394 
1395 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1396 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
1397 	    !sta_ctx->copied_reassoc_rsp->roaming_info)
1398 		goto end;
1399 
1400 	rsp = sta_ctx->copied_reassoc_rsp;
1401 	if (rsp->roaming_info->auth_status == ROAM_AUTH_STATUS_CONNECTED)
1402 		status = true;
1403 
1404 end:
1405 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
1406 	return status;
1407 }
1408 
1409 QDF_STATUS
mlo_roam_link_connect_notify(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)1410 mlo_roam_link_connect_notify(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1411 {
1412 	struct wlan_mlo_sta *sta_ctx = NULL;
1413 	struct wlan_cm_connect_resp *rsp;
1414 	struct wlan_objmgr_vdev *assoc_vdev;
1415 	struct wlan_objmgr_vdev *link_vdev = NULL;
1416 	struct wlan_objmgr_vdev *vdev;
1417 	struct mlo_partner_info partner_info;
1418 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1419 	uint8_t i;
1420 	uint8_t assoc_vdev_id;
1421 	uint8_t link_vdev_id;
1422 
1423 	if (!psoc)
1424 		return QDF_STATUS_E_NULL_VALUE;
1425 
1426 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1427 						    WLAN_MLME_SB_ID);
1428 	if (!vdev)
1429 		return QDF_STATUS_E_NULL_VALUE;
1430 
1431 	if (!vdev->mlo_dev_ctx) {
1432 		mlo_err("mlo dev ctx is null");
1433 		status = QDF_STATUS_E_FAILURE;
1434 		goto err;
1435 	}
1436 
1437 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1438 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1439 		mlo_debug("MLO_ROAM: Ignore if not mlo vdev");
1440 		status = QDF_STATUS_E_FAILURE;
1441 		goto err;
1442 	}
1443 
1444 	assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
1445 	if (!assoc_vdev) {
1446 		status =  QDF_STATUS_E_NULL_VALUE;
1447 		goto err;
1448 	}
1449 
1450 	assoc_vdev_id = wlan_vdev_get_id(assoc_vdev);
1451 	if (!sta_ctx || !sta_ctx->copied_reassoc_rsp) {
1452 		status = QDF_STATUS_E_NULL_VALUE;
1453 		goto err;
1454 	}
1455 
1456 	rsp = sta_ctx->copied_reassoc_rsp;
1457 	partner_info = rsp->ml_parnter_info;
1458 	mlo_debug("partner links %d", partner_info.num_partner_links);
1459 
1460 	for (i = 0; i < partner_info.num_partner_links; i++) {
1461 		link_vdev_id = partner_info.partner_link_info[i].vdev_id;
1462 		if (assoc_vdev_id == link_vdev_id)
1463 			continue;
1464 		link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
1465 								 link_vdev_id,
1466 								 WLAN_MLME_SB_ID);
1467 		if (!link_vdev) {
1468 			mlo_err("Link vdev is null");
1469 			status = QDF_STATUS_E_NULL_VALUE;
1470 			goto err;
1471 		}
1472 
1473 		if (mlo_check_connect_req_bmap(link_vdev)) {
1474 			status = mlo_roam_prepare_and_send_link_connect_req(assoc_vdev,
1475 							link_vdev,
1476 							rsp,
1477 							&partner_info.partner_link_info[i].link_addr,
1478 							partner_info.partner_link_info[i].chan_freq);
1479 			if (QDF_IS_STATUS_ERROR(status))
1480 				goto err;
1481 			else {
1482 				mlo_update_connect_req_links(link_vdev, false);
1483 				goto end;
1484 			}
1485 		}
1486 	}
1487 err:
1488 	if (link_vdev)
1489 		mlo_clear_connect_req_links_bmap(link_vdev);
1490 	if (sta_ctx && sta_ctx->copied_reassoc_rsp) {
1491 		wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1492 		sta_ctx->copied_reassoc_rsp = NULL;
1493 	}
1494 end:
1495 	if (link_vdev)
1496 		wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLME_SB_ID);
1497 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
1498 	return status;
1499 }
1500 
1501 bool
mlo_is_roaming_in_progress(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)1502 mlo_is_roaming_in_progress(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1503 {
1504 	struct wlan_objmgr_vdev *vdev;
1505 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1506 	bool is_roaming_in_progress = false;
1507 	uint8_t link_vdev_id;
1508 	uint8_t i;
1509 
1510 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1511 						    WLAN_MLME_OBJMGR_ID);
1512 	if (!vdev) {
1513 		mlme_err("vdev object is NULL for vdev %d", vdev_id);
1514 		return false;
1515 	}
1516 
1517 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1518 	if (!mlo_dev_ctx) {
1519 		mlme_err("mlo_dev_ctx object is NULL for vdev %d", vdev_id);
1520 		goto end;
1521 	}
1522 
1523 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1524 		if (!mlo_dev_ctx->wlan_vdev_list[i])
1525 			continue;
1526 
1527 		link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
1528 		if (link_vdev_id == WLAN_INVALID_VDEV_ID) {
1529 			mlme_err("invalid vdev id");
1530 			goto end;
1531 		}
1532 
1533 		if (wlan_cm_is_roam_sync_in_progress(psoc, link_vdev_id)) {
1534 			is_roaming_in_progress = true;
1535 			goto end;
1536 		}
1537 	}
1538 
1539 end:
1540 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
1541 	return is_roaming_in_progress;
1542 }
1543 
1544 QDF_STATUS
mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc * psoc,struct roam_scan_candidate_frame * rcvd_frame)1545 mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc,
1546 			struct roam_scan_candidate_frame *rcvd_frame)
1547 {
1548 	uint8_t *ml_ie, link_id, idx, ies_offset;
1549 	qdf_size_t ml_ie_total_len, gen_frame_len;
1550 	QDF_STATUS status;
1551 	struct mlo_partner_info ml_partner_info = {0};
1552 	struct element_info rcvd_probe_rsp, gen_probe_rsp = {0, NULL};
1553 	struct roam_scan_candidate_frame entry = {0};
1554 	struct qdf_mac_addr self_link_addr;
1555 	struct wlan_objmgr_vdev *vdev;
1556 
1557 	/* Add the received scan entry as it is */
1558 	wlan_cm_add_frame_to_scan_db(psoc, rcvd_frame);
1559 
1560 	ies_offset = WLAN_MAC_HDR_LEN_3A + WLAN_PROBE_RESP_IES_OFFSET;
1561 	if (rcvd_frame->frame_length < ies_offset) {
1562 		mlme_err("No IEs in probe rsp");
1563 		return QDF_STATUS_E_FAILURE;
1564 	}
1565 
1566 	status = util_find_mlie(rcvd_frame->frame + ies_offset,
1567 				rcvd_frame->frame_length - ies_offset,
1568 				&ml_ie, &ml_ie_total_len);
1569 	if (QDF_IS_STATUS_ERROR(status))
1570 		return QDF_STATUS_SUCCESS;
1571 
1572 	status = util_get_bvmlie_persta_partner_info(ml_ie,
1573 						     ml_ie_total_len,
1574 						     &ml_partner_info);
1575 	if (QDF_IS_STATUS_ERROR(status)) {
1576 		mlme_err("Per STA profile parsing failed");
1577 		return status;
1578 	}
1579 
1580 	gen_frame_len = MAX_MGMT_MPDU_LEN;
1581 
1582 	gen_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len);
1583 	if (!gen_probe_rsp.ptr)
1584 		return QDF_STATUS_E_NOMEM;
1585 
1586 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rcvd_frame->vdev_id,
1587 						    WLAN_MLME_CM_ID);
1588 	if (!vdev) {
1589 		mlme_err("vdev object is NULL");
1590 		status = QDF_STATUS_E_NULL_VALUE;
1591 		goto done;
1592 	}
1593 	qdf_mem_copy(self_link_addr.bytes,
1594 		     wlan_vdev_mlme_get_macaddr(vdev),
1595 		     QDF_MAC_ADDR_SIZE);
1596 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
1597 
1598 	rcvd_probe_rsp.ptr = rcvd_frame->frame + WLAN_MAC_HDR_LEN_3A;
1599 	rcvd_probe_rsp.len = rcvd_frame->frame_length - WLAN_MAC_HDR_LEN_3A;
1600 
1601 	for (idx = 0; idx < ml_partner_info.num_partner_links; idx++) {
1602 		link_id = ml_partner_info.partner_link_info[idx].link_id;
1603 		status = util_gen_link_probe_rsp(rcvd_probe_rsp.ptr,
1604 				rcvd_probe_rsp.len,
1605 				link_id,
1606 				self_link_addr,
1607 				gen_probe_rsp.ptr,
1608 				gen_frame_len,
1609 				(qdf_size_t *)&gen_probe_rsp.len);
1610 		if (QDF_IS_STATUS_ERROR(status)) {
1611 			mlme_err("MLO: Link %d probe resp gen failed %d",
1612 				 link_id, status);
1613 			status = QDF_STATUS_E_FAILURE;
1614 			goto done;
1615 		}
1616 
1617 		mlme_debug("MLO: link probe rsp size:%u orig probe rsp :%u",
1618 			   gen_probe_rsp.len, rcvd_probe_rsp.len);
1619 
1620 		entry.vdev_id = rcvd_frame->vdev_id;
1621 		entry.frame = gen_probe_rsp.ptr;
1622 		entry.frame_length = gen_probe_rsp.len;
1623 		entry.rssi = rcvd_frame->rssi;
1624 
1625 		wlan_cm_add_frame_to_scan_db(psoc, &entry);
1626 	}
1627 done:
1628 	qdf_mem_free(gen_probe_rsp.ptr);
1629 
1630 	return status;
1631 }
1632 
1633 bool
mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev * vdev)1634 mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev *vdev)
1635 {
1636 	struct mlo_partner_info *partner_info;
1637 
1638 	if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
1639 		return true;
1640 
1641 	if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx ||
1642 	    !vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp)
1643 		return true;
1644 
1645 	partner_info =
1646 	       &vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp->ml_parnter_info;
1647 	if (partner_info->num_partner_links <= 1)
1648 		return true;
1649 
1650 	/* Roamed to MLO AP, do nothing if link vdev is disconnected */
1651 	return false;
1652 }
1653 
1654 bool
mlo_check_is_given_vdevs_on_same_mld(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id_1,uint8_t vdev_id_2)1655 mlo_check_is_given_vdevs_on_same_mld(struct wlan_objmgr_psoc *psoc,
1656 				     uint8_t vdev_id_1, uint8_t vdev_id_2)
1657 {
1658 	struct wlan_objmgr_vdev *vdev1;
1659 	struct wlan_mlo_dev_context *ml_dev_ctx1;
1660 	struct wlan_objmgr_vdev **vdev_list;
1661 	bool is_same_mld = false;
1662 	uint8_t i;
1663 
1664 	vdev1 = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id_1,
1665 						     WLAN_MLME_CM_ID);
1666 	if (!vdev1)
1667 		return false;
1668 
1669 	ml_dev_ctx1 = vdev1->mlo_dev_ctx;
1670 	if (!ml_dev_ctx1)
1671 		goto end;
1672 
1673 	vdev_list = ml_dev_ctx1->wlan_vdev_list;
1674 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1675 		if (!vdev_list[i])
1676 			continue;
1677 
1678 		if (wlan_vdev_get_id(vdev_list[i]) == vdev_id_2) {
1679 			is_same_mld = true;
1680 			goto end;
1681 		}
1682 	}
1683 
1684 end:
1685 	if (vdev1)
1686 		wlan_objmgr_vdev_release_ref(vdev1, WLAN_MLME_CM_ID);
1687 
1688 	return is_same_mld;
1689 }
1690