xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_sta.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * DOC: contains MLO manager STA related api's
19  */
20 
21 #include <wlan_cmn.h>
22 #include <wlan_mlo_mgr_sta.h>
23 #include <wlan_cm_public_struct.h>
24 #include <wlan_mlo_mgr_main.h>
25 #include <wlan_cm_api.h>
26 #include <wlan_mlo_mgr_cmn.h>
27 #include <wlan_scan_api.h>
28 
29 #ifdef WLAN_FEATURE_11BE_MLO
30 /**
31  * mlo_disconnect_no_lock - Start the disconnection process without acquiring
32  * ML dev lock
33  *
34  * @vdev: pointer to vdev
35  * @source: source of the request (can be connect or disconnect request)
36  * @reason_code: reason for disconnect
37  * @bssid: BSSID
38  *
39  * Return: QDF_STATUS
40  */
41 static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
42 					 enum wlan_cm_source source,
43 					 enum wlan_reason_code reason_code,
44 					 struct qdf_mac_addr *bssid);
45 /*
46  * mlo_get_assoc_link_vdev - API to get assoc link vdev
47  *
48  * @mlo_dev_ctx: pointer to mlo dev context
49  *
50  * Return: MLD assoc link vdev
51  */
52 static inline struct wlan_objmgr_vdev *
53 mlo_get_assoc_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx)
54 {
55 	uint8_t i = 0;
56 
57 	if (!mlo_dev_ctx)
58 		return NULL;
59 
60 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
61 		if (!mlo_dev_ctx->wlan_vdev_list[i])
62 			continue;
63 
64 		if (wlan_vdev_mlme_is_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]) &&
65 		    !wlan_vdev_mlme_is_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i]))
66 			return mlo_dev_ctx->wlan_vdev_list[i];
67 	}
68 	return NULL;
69 }
70 
71 struct wlan_objmgr_vdev *
72 ucfg_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev)
73 {
74 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
75 
76 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
77 		return NULL;
78 
79 	return mlo_get_assoc_link_vdev(mlo_dev_ctx);
80 }
81 
82 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
83 static QDF_STATUS
84 mlo_validate_connect_req(struct wlan_mlo_dev_context *mlo_dev_ctx,
85 			 struct wlan_cm_connect_req *req)
86 {
87 /* check back to back connect handling */
88 	return QDF_STATUS_SUCCESS;
89 }
90 #else
91 /**
92  * mlo_is_mld_connected - Check whether MLD is connected
93  *
94  * @vdev: pointer to vdev
95  *
96  * Return: true if mld is connected, false otherwise
97  */
98 static inline
99 bool mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev)
100 {
101 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
102 	uint8_t i = 0;
103 
104 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
105 		return true;
106 
107 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
108 		if (!mlo_dev_ctx->wlan_vdev_list[i])
109 			continue;
110 
111 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
112 			if (!wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i]))
113 				return false;
114 		}
115 	}
116 	return true;
117 }
118 
119 bool ucfg_mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev)
120 {
121 	return mlo_is_mld_connected(vdev);
122 }
123 
124 /**
125  * mlo_is_mld_disconnected - Check whether MLD is disconnected
126  *
127  * @vdev: pointer to vdev
128  *
129  * Return: true if mld is disconnected, false otherwise
130  */
131 static inline
132 bool mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev)
133 {
134 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
135 	uint8_t i = 0;
136 
137 	if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
138 		return true;
139 
140 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
141 		if (!mlo_dev_ctx->wlan_vdev_list[i])
142 			continue;
143 
144 		if (!wlan_cm_is_vdev_disconnected(mlo_dev_ctx->wlan_vdev_list[i]))
145 			return false;
146 	}
147 	return true;
148 }
149 
150 bool ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev)
151 {
152 	return mlo_is_mld_disconnected(vdev);
153 }
154 
155 static void
156 mlo_cm_handle_connect_in_disconnection_state(struct wlan_objmgr_vdev *vdev,
157 					     struct wlan_cm_connect_req *req)
158 {
159 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
160 	struct wlan_mlo_sta *sta_ctx = mlo_dev_ctx->sta_ctx;
161 
162 	if (!sta_ctx->connect_req)
163 		sta_ctx->connect_req = qdf_mem_malloc(
164 					sizeof(struct wlan_cm_connect_req));
165 
166 	if (sta_ctx->connect_req)
167 		qdf_mem_copy(sta_ctx->connect_req, req,
168 			     sizeof(struct wlan_cm_connect_req));
169 	else
170 		mlo_err("Failed to allocate connect req");
171 }
172 
173 static void
174 mlo_cm_handle_connect_in_connection_state(struct wlan_objmgr_vdev *vdev,
175 					  struct wlan_cm_connect_req *req)
176 {
177 	mlo_disconnect_no_lock(vdev, CM_SB_DISCONNECT,
178 			       REASON_UNSPEC_FAILURE, NULL);
179 	mlo_cm_handle_connect_in_disconnection_state(vdev, req);
180 }
181 
182 static QDF_STATUS
183 mlo_validate_connect_req(struct wlan_mlo_dev_context *mlo_dev_ctx,
184 			 struct wlan_cm_connect_req *req)
185 {
186 	uint8_t i = 0;
187 	QDF_STATUS status = QDF_STATUS_SUCCESS;
188 
189 	// Handle connect in various states
190 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
191 		if (!mlo_dev_ctx->wlan_vdev_list[i])
192 			continue;
193 
194 		if ((wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) ||
195 		    (wlan_cm_is_vdev_connecting(mlo_dev_ctx->wlan_vdev_list[i])) ||
196 		    (wlan_cm_is_vdev_roaming(mlo_dev_ctx->wlan_vdev_list[i]))) {
197 			mlo_cm_handle_connect_in_connection_state(mlo_dev_ctx->wlan_vdev_list[i], req);
198 			return QDF_STATUS_E_BUSY;
199 		} else if (wlan_cm_is_vdev_disconnecting(mlo_dev_ctx->wlan_vdev_list[i])) {
200 			mlo_cm_handle_connect_in_disconnection_state(mlo_dev_ctx->wlan_vdev_list[i], req);
201 			return QDF_STATUS_E_BUSY;
202 		}
203 
204 		/*
205 		 * mlo_connect: update wlan_connect_req_links in
206 		 * wlan_cfg80211_conect on osif_cm_connect,
207 		 * Validate pre checks for connection
208 		 */
209 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connect_req_links)) {
210 			status = mlo_mlme_validate_conn_req(
211 					mlo_dev_ctx->wlan_vdev_list[i], NULL);
212 			if (status != QDF_STATUS_SUCCESS)
213 				return status;
214 		}
215 	}
216 	return status;
217 }
218 #endif
219 
220 QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev,
221 		       struct wlan_cm_connect_req *req)
222 {
223 	struct wlan_mlo_dev_context *mlo_dev_ctx;
224 	struct wlan_mlo_sta *sta_ctx;
225 	QDF_STATUS status = QDF_STATUS_SUCCESS;
226 
227 	if (qdf_mem_cmp(vdev->vdev_mlme.macaddr,
228 			vdev->vdev_mlme.linkaddr,
229 			QDF_MAC_ADDR_SIZE))
230 		return wlan_cm_start_connect(vdev, req);
231 
232 	mlo_dev_ctx = vdev->mlo_dev_ctx;
233 	sta_ctx = mlo_dev_ctx->sta_ctx;
234 	if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
235 		mlo_dev_lock_acquire(mlo_dev_ctx);
236 		status = mlo_validate_connect_req(mlo_dev_ctx, req);
237 
238 		if (!sta_ctx->orig_conn_req)
239 			sta_ctx->orig_conn_req = qdf_mem_malloc(
240 					sizeof(struct wlan_cm_connect_req));
241 
242 		mlo_debug("storing orig connect req");
243 		if (sta_ctx->orig_conn_req) {
244 			qdf_mem_copy(sta_ctx->orig_conn_req, req,
245 				     sizeof(struct wlan_cm_connect_req));
246 		} else {
247 			mlo_err("Failed to allocate orig connect req");
248 			return QDF_STATUS_E_NOMEM;
249 		}
250 
251 		if (QDF_IS_STATUS_SUCCESS(status))
252 			status = wlan_cm_start_connect(vdev, req);
253 
254 		mlo_dev_lock_release(mlo_dev_ctx);
255 		return status;
256 	}
257 
258 	return wlan_cm_start_connect(vdev, req);
259 }
260 
261 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
262 static inline void
263 mlo_update_connect_req_chan_info(struct wlan_cm_connect_req *req)
264 { }
265 #else
266 static inline void
267 mlo_update_connect_req_chan_info(struct wlan_cm_connect_req *req)
268 {
269 	req->chan_freq = 0;
270 	req->chan_freq_hint = 0;
271 }
272 #endif
273 
274 /**
275  * mlo_prepare_and_send_connect- Prepare and send the connect req
276  *
277  * @vdev: vdev pointer
278  * @ml_parnter_info: ml partner link info
279  * @link_info: link info on which connect req will be sent
280  * @ssid: ssid to connect
281  *
282  * Return: none
283  */
284 
285 static void
286 mlo_prepare_and_send_connect(struct wlan_objmgr_vdev *vdev,
287 			     struct mlo_partner_info ml_parnter_info,
288 			     struct mlo_link_info link_info,
289 			     struct wlan_ssid ssid)
290 {
291 	struct wlan_cm_connect_req req = {0};
292 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
293 	struct wlan_mlo_sta *sta_ctx = mlo_dev_ctx->sta_ctx;
294 
295 	mlo_debug("Partner link connect mac:" QDF_MAC_ADDR_FMT "vdev_id:%d",
296 		  QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
297 		  wlan_vdev_get_id(vdev));
298 
299 	qdf_mem_copy(&req, sta_ctx->orig_conn_req,
300 		     sizeof(struct wlan_cm_connect_req));
301 
302 	mlo_update_connect_req_chan_info(&req);
303 
304 	qdf_mem_copy(req.bssid.bytes,
305 		     link_info.link_addr.bytes,
306 		     QDF_MAC_ADDR_SIZE);
307 
308 	qdf_mem_copy(&req.ml_parnter_info,
309 		     &ml_parnter_info,
310 		     sizeof(struct mlo_partner_info));
311 
312 	req.ssid.length = ssid.length;
313 	qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length);
314 
315 	req.assoc_ie.len = sta_ctx->orig_conn_req->assoc_ie.len;
316 	req.assoc_ie.ptr = qdf_mem_malloc(req.assoc_ie.len);
317 	if (req.assoc_ie.ptr) {
318 		qdf_mem_copy(req.assoc_ie.ptr,
319 			     sta_ctx->orig_conn_req->assoc_ie.ptr,
320 			     req.assoc_ie.len);
321 	} else {
322 		req.assoc_ie.len = 0;
323 		mlo_err("Failed to allocate assoc IE");
324 	}
325 
326 	wlan_cm_start_connect(vdev, &req);
327 	if (req.assoc_ie.ptr) {
328 		qdf_mem_free(req.assoc_ie.ptr);
329 		req.assoc_ie.ptr = NULL;
330 		req.assoc_ie.len = 0;
331 	}
332 }
333 
334 /**
335  * mlo_send_link_connect- Create/Issue the connection on secondary link
336  *
337  * @vdev: vdev pointer
338  * @mlo_dev_ctx: ml dev context
339  * @assoc_rsp: assoc response
340  * @ml_parnter_info: ml partner link info
341  *
342  * Return: none
343  */
344 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
345 static void
346 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev,
347 		      struct wlan_mlo_dev_context *mlo_dev_ctx,
348 		      struct element_info *assoc_rsp,
349 		      struct mlo_partner_info ml_parnter_info)
350 {
351 	/* Create the secondary interface, Send keys if the last link */
352 	uint8_t i;
353 	struct wlan_ssid ssid = {0};
354 
355 	mlo_debug("Sending link connect on partner interface");
356 	wlan_vdev_mlme_get_ssid(
357 			vdev, ssid.ssid,
358 			&ssid.length);
359 
360 	if (!ml_parnter_info.num_partner_links) {
361 		mlo_err("No patner info in connect resp");
362 		return;
363 	}
364 
365 	if(wlan_vdev_mlme_is_mlo_link_vdev(vdev))
366 		return;
367 
368 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
369 		if (!mlo_dev_ctx->wlan_vdev_list[i] ||
370 		    (mlo_dev_ctx->wlan_vdev_list[i] == vdev))
371 			continue;
372 		wlan_vdev_mlme_feat_ext2_cap_set(mlo_dev_ctx->wlan_vdev_list[i],
373 						 WLAN_VDEV_FEXT2_MLO_STA_LINK);
374 		mlo_prepare_and_send_connect(
375 				mlo_dev_ctx->wlan_vdev_list[i],
376 				ml_parnter_info,
377 				ml_parnter_info.partner_link_info[i],
378 				ssid);
379 	}
380 }
381 #else
382 static void
383 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev,
384 		      struct wlan_mlo_dev_context *mlo_dev_ctx,
385 		      struct element_info *assoc_rsp,
386 		      struct mlo_partner_info ml_parnter_info)
387 {
388 	struct wlan_ssid ssid = {0};
389 	uint8_t i = 0;
390 	uint8_t j = 0;
391 
392 	if (!ml_parnter_info.num_partner_links) {
393 		mlo_err("No patner info in connect resp");
394 		return;
395 	}
396 
397 	mlo_dev_lock_acquire(mlo_dev_ctx);
398 	if (wlan_cm_is_vdev_connected(vdev)) {
399 		for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
400 			if (!mlo_dev_ctx->wlan_vdev_list[i])
401 				continue;
402 			/*
403 			 * mlo_connect: update wlan_connected_links bitmap from
404 			 * assoc resp parsing
405 			 */
406 			if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
407 				if (wlan_cm_is_vdev_disconnected(
408 					mlo_dev_ctx->wlan_vdev_list[i])) {
409 					for (j = 0; j < ml_parnter_info.num_partner_links; j++) {
410 						if (mlo_dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id ==
411 							ml_parnter_info.partner_link_info[j].link_id)
412 							break;
413 					}
414 					if (j < ml_parnter_info.num_partner_links) {
415 						wlan_vdev_mlme_get_ssid(
416 							vdev, ssid.ssid,
417 							&ssid.length);
418 						mlo_prepare_and_send_connect(
419 							mlo_dev_ctx->wlan_vdev_list[i],
420 							ml_parnter_info,
421 							ml_parnter_info.partner_link_info[j],
422 							ssid);
423 					}
424 					mlo_dev_lock_release(mlo_dev_ctx);
425 					return;
426 				}
427 			}
428 		}
429 	}
430 	mlo_dev_lock_release(mlo_dev_ctx);
431 }
432 #endif
433 
434 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
435 				 struct wlan_cm_connect_resp *rsp)
436 {
437 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
438 
439 	if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
440 		mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev));
441 		if (wlan_cm_is_vdev_disconnected(vdev)) {
442 			// Connect Failure
443 			if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) {
444 				return;
445 			} else {
446 				if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
447 				    rsp->reason == CM_HW_MODE_FAILURE ||
448 				    rsp->reason == CM_SER_FAILURE)
449 					mlo_disconnect_no_lock(
450 						vdev, CM_OSIF_DISCONNECT,
451 						REASON_UNSPEC_FAILURE, NULL);
452 				else
453 					mlo_disconnect(
454 						vdev, CM_OSIF_DISCONNECT,
455 						REASON_UNSPEC_FAILURE, NULL);
456 				return;
457 			}
458 		}
459 		if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) {
460 			if (mlo_dev_ctx->sta_ctx->assoc_rsp.ptr) {
461 				qdf_mem_free(mlo_dev_ctx->sta_ctx->assoc_rsp.ptr);
462 				mlo_dev_ctx->sta_ctx->assoc_rsp.ptr = NULL;
463 			}
464 			mlo_dev_ctx->sta_ctx->assoc_rsp.len =
465 				rsp->connect_ies.assoc_rsp.len;
466 			mlo_dev_ctx->sta_ctx->assoc_rsp.ptr =
467 				qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len);
468 			if (!mlo_dev_ctx->sta_ctx->assoc_rsp.ptr) {
469 				QDF_ASSERT(0);
470 				return;
471 			}
472 			qdf_mem_copy(mlo_dev_ctx->sta_ctx->assoc_rsp.ptr,
473 				     rsp->connect_ies.assoc_rsp.ptr,
474 				     rsp->connect_ies.assoc_rsp.len);
475 		}
476 		mlo_send_link_connect(vdev, mlo_dev_ctx,
477 				      &rsp->connect_ies.assoc_rsp,
478 				      rsp->ml_parnter_info);
479 	}
480 }
481 
482 /*
483  * mlo_get_connected_link_vdev - API to get 1st connected link vdev
484  *
485  * @mlo_dev_ctx: mlo dev ctx
486  *
487  * Return: 1st connected link vdev in ML dev, NULL if none of the link vdev
488  * is connected
489  */
490 static struct wlan_objmgr_vdev
491 *mlo_get_connected_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx)
492 {
493 	uint8_t i = 0;
494 
495 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
496 		if (!mlo_dev_ctx->wlan_vdev_list[i])
497 			continue;
498 
499 		if ((mlo_dev_ctx->wlan_vdev_list[i] !=
500 		    mlo_get_assoc_link_vdev(mlo_dev_ctx)) &&
501 		    wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i]))
502 			return mlo_dev_ctx->wlan_vdev_list[i];
503 	}
504 
505 	return NULL;
506 }
507 
508 /**
509  * mlo_send_link_disconnect- Issue the disconnect request on MLD links
510  *
511  * @mlo_dev_ctx: pointer to mlo dev context
512  * @source: disconnect source
513  * @reason_code: disconnect reason
514  * @bssid: bssid of AP to disconnect, can be null if not known
515  *
516  * Return: QDF_STATUS
517  */
518 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
519 static QDF_STATUS
520 mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx,
521 			 enum wlan_cm_source source,
522 			 enum wlan_reason_code reason_code,
523 			 struct qdf_mac_addr *bssid)
524 {
525 	uint8_t i = 0;
526 
527 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
528 		if (!mlo_dev_ctx->wlan_vdev_list[i])
529 			continue;
530 
531 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links) &&
532 		    mlo_dev_ctx->wlan_vdev_list[i] != mlo_get_assoc_link_vdev(mlo_dev_ctx))
533 			wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
534 					   source, reason_code, NULL);
535 	}
536 
537 	wlan_cm_disconnect(mlo_get_assoc_link_vdev(mlo_dev_ctx),
538 			   source, reason_code, NULL);
539 	return QDF_STATUS_SUCCESS;
540 }
541 
542 static QDF_STATUS
543 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
544 			      enum wlan_cm_source source,
545 			      enum wlan_reason_code reason_code,
546 			      struct qdf_mac_addr *bssid)
547 {
548 	uint8_t i = 0;
549 
550 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
551 		if (!mlo_dev_ctx->wlan_vdev_list[i])
552 			continue;
553 
554 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links) &&
555 		    mlo_dev_ctx->wlan_vdev_list[i] != mlo_get_assoc_link_vdev(mlo_dev_ctx))
556 			wlan_cm_disconnect_sync(mlo_dev_ctx->wlan_vdev_list[i],
557 						source, reason_code);
558 	}
559 
560 	wlan_cm_disconnect_sync(mlo_get_assoc_link_vdev(mlo_dev_ctx),
561 				source, reason_code);
562 	return QDF_STATUS_SUCCESS;
563 }
564 #else
565 static QDF_STATUS
566 mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx,
567 			 enum wlan_cm_source source,
568 			 enum wlan_reason_code reason_code,
569 			 struct qdf_mac_addr *bssid)
570 {
571 	uint8_t i = 0;
572 	QDF_STATUS status = QDF_STATUS_E_ALREADY;
573 
574 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
575 		if (!mlo_dev_ctx->wlan_vdev_list[i])
576 			continue;
577 
578 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
579 			if (wlan_cm_is_vdev_connecting(
580 					mlo_dev_ctx->wlan_vdev_list[i]) ||
581 			    wlan_cm_is_vdev_disconnecting(
582 					mlo_dev_ctx->wlan_vdev_list[i]) ||
583 			    wlan_cm_is_vdev_roaming(
584 					mlo_dev_ctx->wlan_vdev_list[i])) {
585 				wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
586 						   source, reason_code, NULL);
587 				return QDF_STATUS_SUCCESS;
588 			}
589 		}
590 	}
591 
592 	return status;
593 }
594 
595 static QDF_STATUS
596 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
597 			      enum wlan_cm_source source,
598 			      enum wlan_reason_code reason_code,
599 			      struct qdf_mac_addr *bssid)
600 {
601 	uint8_t i = 0;
602 	QDF_STATUS status = QDF_STATUS_E_ALREADY;
603 
604 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
605 		if (!mlo_dev_ctx->wlan_vdev_list[i])
606 			continue;
607 
608 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
609 			if (wlan_cm_is_vdev_connecting(
610 					mlo_dev_ctx->wlan_vdev_list[i]) ||
611 			    wlan_cm_is_vdev_disconnecting(
612 					mlo_dev_ctx->wlan_vdev_list[i]) ||
613 			    wlan_cm_is_vdev_roaming(
614 				mlo_dev_ctx->wlan_vdev_list[i])) {
615 				wlan_cm_disconnect_sync(
616 					mlo_dev_ctx->wlan_vdev_list[i],
617 					source, reason_code);
618 				return QDF_STATUS_SUCCESS;
619 			}
620 		}
621 	}
622 
623 	return status;
624 }
625 #endif
626 
627 static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
628 					 enum wlan_cm_source source,
629 					 enum wlan_reason_code reason_code,
630 					 struct qdf_mac_addr *bssid)
631 {
632 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
633 	struct wlan_objmgr_vdev *tmp_vdev = vdev;
634 	struct wlan_mlo_sta *sta_ctx = NULL;
635 	QDF_STATUS status = QDF_STATUS_SUCCESS;
636 
637 	if (mlo_dev_ctx) {
638 		sta_ctx = mlo_dev_ctx->sta_ctx;
639 		if (!sta_ctx)
640 			return QDF_STATUS_E_FAILURE;
641 
642 		if (sta_ctx->connect_req) {
643 			qdf_mem_free(sta_ctx->connect_req);
644 			sta_ctx->connect_req = NULL;
645 		}
646 
647 		if (sta_ctx->orig_conn_req) {
648 			qdf_mem_free(sta_ctx->orig_conn_req);
649 			sta_ctx->orig_conn_req = NULL;
650 		}
651 
652 		status = mlo_send_link_disconnect(mlo_dev_ctx, source,
653 						  reason_code, bssid);
654 
655 		if (QDF_IS_STATUS_SUCCESS(status))
656 			return status;
657 
658 		tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx);
659 		if (tmp_vdev) {
660 			status = wlan_cm_disconnect(tmp_vdev, source,
661 						    reason_code, NULL);
662 			return status;
663 		}
664 		tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
665 		if (tmp_vdev) {
666 			status = wlan_cm_disconnect(tmp_vdev, source,
667 						    reason_code, NULL);
668 			return status;
669 		}
670 	}
671 
672 	return status;
673 }
674 
675 QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
676 			  enum wlan_cm_source source,
677 			  enum wlan_reason_code reason_code,
678 			  struct qdf_mac_addr *bssid)
679 {
680 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
681 	struct wlan_objmgr_vdev *tmp_vdev = NULL;
682 	struct wlan_mlo_sta *sta_ctx = NULL;
683 	QDF_STATUS status = QDF_STATUS_SUCCESS;
684 
685 	if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
686 		sta_ctx = mlo_dev_ctx->sta_ctx;
687 		mlo_dev_lock_acquire(mlo_dev_ctx);
688 		if (sta_ctx->connect_req) {
689 			qdf_mem_free(sta_ctx->connect_req);
690 			sta_ctx->connect_req = NULL;
691 		}
692 
693 		if (sta_ctx->orig_conn_req) {
694 			qdf_mem_free(sta_ctx->orig_conn_req);
695 			sta_ctx->orig_conn_req = NULL;
696 		}
697 
698 		status = mlo_send_link_disconnect(mlo_dev_ctx, source,
699 						  reason_code, bssid);
700 
701 		if (QDF_IS_STATUS_SUCCESS(status)) {
702 			mlo_dev_lock_release(mlo_dev_ctx);
703 			return status;
704 		}
705 
706 		tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx);
707 		if (tmp_vdev) {
708 			status = wlan_cm_disconnect(tmp_vdev, source,
709 						    reason_code, NULL);
710 			mlo_dev_lock_release(mlo_dev_ctx);
711 			return status;
712 		}
713 		tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
714 		if (tmp_vdev) {
715 			status = wlan_cm_disconnect(tmp_vdev, source,
716 						    reason_code, NULL);
717 			mlo_dev_lock_release(mlo_dev_ctx);
718 			return status;
719 		}
720 		mlo_dev_lock_release(mlo_dev_ctx);
721 		return status;
722 	}
723 	return wlan_cm_disconnect(vdev, source,
724 				  reason_code, NULL);
725 }
726 
727 QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev,
728 			       enum wlan_cm_source source,
729 			       enum wlan_reason_code reason_code,
730 			       struct qdf_mac_addr *bssid)
731 {
732 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
733 	struct wlan_objmgr_vdev *tmp_vdev = NULL;
734 	struct wlan_mlo_sta *sta_ctx = NULL;
735 	QDF_STATUS status = QDF_STATUS_SUCCESS;
736 
737 	if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
738 		sta_ctx = mlo_dev_ctx->sta_ctx;
739 		if (sta_ctx->connect_req) {
740 			qdf_mem_free(sta_ctx->connect_req);
741 			sta_ctx->connect_req = NULL;
742 		}
743 
744 		if (sta_ctx->orig_conn_req) {
745 			qdf_mem_free(sta_ctx->orig_conn_req);
746 			sta_ctx->orig_conn_req = NULL;
747 		}
748 
749 		status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source,
750 						       reason_code, bssid);
751 
752 		if (QDF_IS_STATUS_SUCCESS(status))
753 			return status;
754 
755 		tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx);
756 		if (tmp_vdev) {
757 			status = wlan_cm_disconnect_sync(tmp_vdev, source,
758 							 reason_code);
759 			return status;
760 		}
761 		tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
762 		if (tmp_vdev) {
763 			status = wlan_cm_disconnect_sync(tmp_vdev, source,
764 							 reason_code);
765 			return status;
766 		}
767 		return status;
768 	}
769 	return wlan_cm_disconnect_sync(vdev, source,
770 				       reason_code);
771 }
772 
773 /**
774  * mlo_handle_disconnect_resp- Issue desired actions on partner link vdev
775  *
776  * @mlo_dev_ctx: pointer to mlo dev context
777  * @resp: disconnect resp
778  *
779  * Return: none
780  */
781 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
782 static
783 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx,
784 				struct wlan_cm_discon_rsp *resp)
785 {
786 /* If it is secondary link then delete vdev object from mlo device. */
787 }
788 #else
789 static
790 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx,
791 				struct wlan_cm_discon_rsp *resp)
792 {
793 	struct wlan_objmgr_vdev *assoc_vdev = NULL;
794 	enum wlan_cm_source source;
795 	enum wlan_reason_code reason_code;
796 	uint8_t i = 0;
797 
798 	mlo_dev_lock_acquire(mlo_dev_ctx);
799 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
800 		if (!mlo_dev_ctx->wlan_vdev_list[i])
801 			continue;
802 
803 		if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
804 			if (wlan_cm_is_vdev_connected(
805 					mlo_dev_ctx->wlan_vdev_list[i])) {
806 				if (wlan_vdev_mlme_is_mlo_link_vdev(
807 					mlo_dev_ctx->wlan_vdev_list[i])) {
808 					source = resp->req.req.source;
809 					reason_code = resp->req.req.reason_code;
810 					wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
811 							   source, reason_code, NULL);
812 					mlo_dev_lock_release(mlo_dev_ctx);
813 					return;
814 				}
815 			}
816 		}
817 	}
818 	assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
819 	if (assoc_vdev && wlan_cm_is_vdev_connected(assoc_vdev)) {
820 		source = resp->req.req.source;
821 		reason_code = resp->req.req.reason_code;
822 		wlan_cm_disconnect(assoc_vdev,
823 				   source, reason_code, NULL);
824 		mlo_dev_lock_release(mlo_dev_ctx);
825 		return;
826 	}
827 	mlo_dev_lock_release(mlo_dev_ctx);
828 }
829 #endif
830 
831 void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev,
832 				 struct wlan_cm_discon_rsp *resp)
833 {
834 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
835 	struct wlan_mlo_sta *sta_ctx = NULL;
836 
837 	if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev)))
838 		return;
839 
840 	sta_ctx = mlo_dev_ctx->sta_ctx;
841 	if (!sta_ctx)
842 		return;
843 
844 	if (!wlan_cm_is_vdev_disconnected(vdev))
845 		return;
846 
847 	if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) {
848 		if (sta_ctx->connect_req) {
849 			mlo_connect(mlo_get_assoc_link_vdev(mlo_dev_ctx),
850 				    sta_ctx->connect_req);
851 			qdf_mem_free(sta_ctx->connect_req);
852 			sta_ctx->connect_req = NULL;
853 		}
854 		return;
855 	}
856 
857 	mlo_handle_disconnect_resp(mlo_dev_ctx, resp);
858 }
859 
860 bool mlo_is_mld_sta(struct wlan_objmgr_vdev *vdev)
861 {
862 	if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) &&
863 	    wlan_vdev_mlme_is_mlo_vdev(vdev))
864 		return true;
865 
866 	return false;
867 }
868 
869 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
870 void mlo_iterate_connected_vdev_list(struct wlan_objmgr_vdev *vdev,
871 				     mlo_vdev_op_handler handler,
872 				     void *arg)
873 {
874 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
875 	struct wlan_mlo_sta *sta_ctx = NULL;
876 	uint8_t i = 0;
877 
878 	if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev)))
879 		return;
880 
881 	sta_ctx = mlo_dev_ctx->sta_ctx;
882 	if (!sta_ctx)
883 		return;
884 
885 	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
886 		if (!mlo_dev_ctx->wlan_vdev_list[i])
887 			continue;
888 		if (qdf_test_bit(i, sta_ctx->wlan_connected_links)) {
889 			if (handler)
890 				handler(mlo_dev_ctx->wlan_vdev_list[i], arg);
891 		}
892 	}
893 }
894 
895 
896 void mlo_update_connect_req_links(struct wlan_objmgr_vdev *vdev, uint8_t value)
897 {
898 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
899 	struct wlan_mlo_sta *sta_ctx = NULL;
900 	uint8_t i = 0;
901 
902 	if (!mlo_dev_ctx)
903 		return;
904 
905 	sta_ctx = mlo_dev_ctx->sta_ctx;
906 	if (!sta_ctx)
907 		return;
908 
909 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
910 		if (!mlo_dev_ctx->wlan_vdev_list[i])
911 			continue;
912 
913 		if (vdev == mlo_dev_ctx->wlan_vdev_list[i]) {
914 			if (value)
915 				qdf_set_bit(i, sta_ctx->wlan_connect_req_links);
916 			else
917 				qdf_clear_bit(i, sta_ctx->wlan_connect_req_links);
918 		}
919 	}
920 }
921 
922 void mlo_clear_connect_req_links_bmap(struct wlan_objmgr_vdev *vdev)
923 {
924 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
925 	struct wlan_mlo_sta *sta_ctx = NULL;
926 
927 	if (!mlo_dev_ctx)
928 		return;
929 
930 	sta_ctx = mlo_dev_ctx->sta_ctx;
931 	if (!sta_ctx)
932 		return;
933 
934 	qdf_mem_zero(sta_ctx->wlan_connect_req_links,
935 		     sizeof(sta_ctx->wlan_connect_req_links));
936 }
937 
938 void mlo_update_connected_links(struct wlan_objmgr_vdev *vdev, uint8_t value)
939 {
940 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
941 	struct wlan_mlo_sta *sta_ctx = NULL;
942 	uint8_t i = 0;
943 
944 	if (!mlo_dev_ctx)
945 		return;
946 
947 	sta_ctx = mlo_dev_ctx->sta_ctx;
948 	if (!sta_ctx)
949 		return;
950 
951 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
952 		if (!mlo_dev_ctx->wlan_vdev_list[i])
953 			continue;
954 
955 		if (vdev == mlo_dev_ctx->wlan_vdev_list[i]) {
956 			if (value)
957 				qdf_set_bit(i, sta_ctx->wlan_connected_links);
958 			else
959 				qdf_clear_bit(i, sta_ctx->wlan_connected_links);
960 		}
961 	}
962 }
963 
964 void mlo_clear_connected_links_bmap(struct wlan_objmgr_vdev *vdev)
965 {
966 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
967 	struct wlan_mlo_sta *sta_ctx = NULL;
968 
969 	if (!mlo_dev_ctx)
970 		return;
971 
972 	sta_ctx = mlo_dev_ctx->sta_ctx;
973 	if (!sta_ctx)
974 		return;
975 
976 	qdf_mem_zero(sta_ctx->wlan_connected_links,
977 		     sizeof(sta_ctx->wlan_connected_links));
978 }
979 
980 struct wlan_objmgr_vdev *
981 mlo_get_ml_vdev_by_mac(struct wlan_objmgr_vdev *vdev,
982 		       struct qdf_mac_addr *macaddr)
983 {
984 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
985 	uint8_t i = 0;
986 
987 	if (!mlo_dev_ctx)
988 		return NULL;
989 
990 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
991 		if (!mlo_dev_ctx->wlan_vdev_list[i])
992 			continue;
993 
994 		if(qdf_mem_cmp(macaddr,
995 			       wlan_vdev_mlme_get_macaddr(mlo_dev_ctx->wlan_vdev_list[i]),
996 			       QDF_MAC_ADDR_SIZE) == 0) {
997 			return mlo_dev_ctx->wlan_vdev_list[i];
998 		}
999 	}
1000 	return NULL;
1001 }
1002 #endif
1003 
1004 qdf_freq_t
1005 mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev *pdev,
1006 			   struct qdf_mac_addr *bssid)
1007 {
1008 	struct scan_filter *scan_filter;
1009 	int8_t ch_freq = 0;
1010 	qdf_list_t *list = NULL;
1011 	struct scan_cache_node *first_node = NULL;
1012 	qdf_list_node_t *cur_node = NULL;
1013 
1014 	scan_filter = qdf_mem_malloc(sizeof(*scan_filter));
1015 	if (!scan_filter)
1016 		return ch_freq;
1017 
1018 	scan_filter->num_of_bssid = 1;
1019 	qdf_mem_copy(scan_filter->bssid_list[0].bytes,
1020 		     bssid, sizeof(struct qdf_mac_addr));
1021 	list = wlan_scan_get_result(pdev, scan_filter);
1022 	qdf_mem_free(scan_filter);
1023 
1024 	if (!list || (list && !qdf_list_size(list))) {
1025 		mlo_debug("scan list empty");
1026 		goto error;
1027 	}
1028 
1029 	qdf_list_peek_front(list, &cur_node);
1030 	first_node = qdf_container_of(cur_node,
1031 				      struct scan_cache_node,
1032 				      node);
1033 	if (first_node && first_node->entry)
1034 		ch_freq = first_node->entry->channel.chan_freq;
1035 error:
1036 	if (list)
1037 		wlan_scan_purge_results(list);
1038 
1039 	return ch_freq;
1040 }
1041 
1042 void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev,
1043 		       struct element_info **assoc_rsp_frame)
1044 {
1045 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1046 	struct wlan_mlo_sta *sta_ctx = mlo_dev_ctx->sta_ctx;
1047 
1048 	if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx)
1049 		return;
1050 
1051 	if (!sta_ctx->assoc_rsp.len || !sta_ctx->assoc_rsp.ptr) {
1052 		mlo_err("Assoc Resp info is empty");
1053 		return;
1054 	}
1055 
1056 	*assoc_rsp_frame = &sta_ctx->assoc_rsp;
1057 }
1058 #endif
1059