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