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