xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c (revision 06f9ae280111c1da9db0809f457076854959e02d)
1 /*
2  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * DOC: contains MLO manager Link Switch related functionality
19  */
20 #include <wlan_mlo_mgr_link_switch.h>
21 #include <wlan_mlo_mgr_main.h>
22 #include <wlan_mlo_mgr_sta.h>
23 #include <wlan_serialization_api.h>
24 #include <wlan_cm_api.h>
25 #include <wlan_crypto_def_i.h>
26 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
27 #include "wlan_cm_roam_api.h"
28 #endif
29 
30 void mlo_mgr_update_link_info_mac_addr(struct wlan_objmgr_vdev *vdev,
31 				       struct wlan_mlo_link_mac_update *ml_mac_update)
32 {
33 	struct mlo_link_info *link_info;
34 	uint8_t link_info_iter;
35 	struct mlo_vdev_link_mac_info *link_mac_info;
36 
37 	if (!vdev || !vdev->mlo_dev_ctx || !ml_mac_update)
38 		return;
39 
40 	link_mac_info = &ml_mac_update->link_mac_info[0];
41 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
42 
43 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
44 	     link_info_iter++) {
45 		qdf_mem_copy(&link_info->link_addr,
46 			     &link_mac_info->link_mac_addr,
47 			     QDF_MAC_ADDR_SIZE);
48 
49 		link_info->vdev_id = link_mac_info->vdev_id;
50 		mlo_debug("Update STA Link info for vdev_id %d, link_addr:" QDF_MAC_ADDR_FMT,
51 			  link_info->vdev_id,
52 			  QDF_MAC_ADDR_REF(link_info->link_addr.bytes));
53 		link_mac_info++;
54 		link_info++;
55 	}
56 }
57 
58 void mlo_mgr_update_ap_link_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id,
59 				 uint8_t *ap_link_addr,
60 				 struct wlan_channel channel)
61 {
62 	struct mlo_link_info *link_info;
63 	uint8_t link_info_iter;
64 
65 	if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr)
66 		return;
67 
68 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
69 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
70 	     link_info_iter++) {
71 		if (qdf_is_macaddr_zero(&link_info->ap_link_addr))
72 			break;
73 
74 		link_info++;
75 	}
76 
77 	if (link_info_iter == WLAN_MAX_ML_BSS_LINKS)
78 		return;
79 
80 	qdf_mem_copy(&link_info->ap_link_addr, ap_link_addr, QDF_MAC_ADDR_SIZE);
81 
82 	qdf_mem_copy(link_info->link_chan_info, &channel, sizeof(channel));
83 	link_info->link_status_flags = 0;
84 	link_info->link_id = link_id;
85 
86 	mlo_debug("Update AP Link info for link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT,
87 		  link_info->link_id, link_info->vdev_id,
88 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
89 }
90 
91 void mlo_mgr_update_ap_channel_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id,
92 				    uint8_t *ap_link_addr,
93 				    struct wlan_channel channel)
94 {
95 	struct mlo_link_info *link_info;
96 
97 	if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr)
98 		return;
99 
100 	link_info = mlo_mgr_get_ap_link_by_link_id(vdev, link_id);
101 	if (!link_info)
102 		return;
103 
104 	qdf_mem_copy(link_info->link_chan_info, &channel,
105 		     sizeof(*link_info->link_chan_info));
106 
107 	mlo_debug("Update AP Channel info link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT,
108 		  link_info->link_id, link_info->vdev_id,
109 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
110 	mlo_debug("Ch_freq: %d, freq1: %d, freq2: %d phy_mode: %d",
111 		  link_info->link_chan_info->ch_freq,
112 		  link_info->link_chan_info->ch_cfreq1,
113 		  link_info->link_chan_info->ch_cfreq2,
114 		  link_info->link_chan_info->ch_phymode);
115 }
116 
117 void mlo_mgr_update_link_info_reset(struct wlan_mlo_dev_context *ml_dev)
118 {
119 	struct mlo_link_info *link_info;
120 	uint8_t link_info_iter;
121 
122 	if (!ml_dev)
123 		return;
124 
125 	link_info = &ml_dev->link_ctx->links_info[0];
126 
127 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
128 	     link_info_iter++) {
129 		qdf_mem_zero(&link_info->link_addr, QDF_MAC_ADDR_SIZE);
130 		qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE);
131 		qdf_mem_zero(link_info->link_chan_info,
132 			     sizeof(*link_info->link_chan_info));
133 		link_info->vdev_id = WLAN_INVALID_VDEV_ID;
134 		link_info->link_id = WLAN_INVALID_LINK_ID;
135 		link_info->link_status_flags = 0;
136 		link_info++;
137 	}
138 }
139 
140 void mlo_mgr_reset_ap_link_info(struct wlan_objmgr_vdev *vdev)
141 {
142 	struct mlo_link_info *link_info;
143 	uint8_t link_info_iter;
144 	struct wlan_objmgr_psoc *psoc;
145 
146 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx)
147 		return;
148 
149 	psoc = wlan_vdev_get_psoc(vdev);
150 	if (!psoc) {
151 		mlo_err("psoc NULL");
152 		return;
153 	}
154 
155 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
156 
157 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
158 	     link_info_iter++) {
159 		if (!qdf_is_macaddr_zero(&link_info->ap_link_addr) &&
160 		    !qdf_is_macaddr_zero(&link_info->link_addr))
161 			wlan_crypto_free_key_by_link_id(
162 						psoc,
163 						&link_info->link_addr,
164 						link_info->link_id);
165 		qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE);
166 		qdf_mem_zero(link_info->link_chan_info,
167 			     sizeof(*link_info->link_chan_info));
168 		link_info->link_id = WLAN_INVALID_LINK_ID;
169 		link_info->link_status_flags = 0;
170 		link_info++;
171 	}
172 }
173 
174 struct mlo_link_info
175 *mlo_mgr_get_ap_link_by_link_id(struct wlan_objmgr_vdev *vdev, int link_id)
176 {
177 	struct mlo_link_info *link_info;
178 	uint8_t link_info_iter;
179 
180 	if (!vdev || link_id < 0 || link_id > 15)
181 		return NULL;
182 
183 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
184 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
185 	     link_info_iter++) {
186 		if (link_info->link_id == link_id)
187 			return link_info;
188 		link_info++;
189 	}
190 
191 	return NULL;
192 }
193 
194 struct mlo_link_info
195 *mlo_mgr_get_ap_link(struct wlan_objmgr_vdev *vdev)
196 {
197 	if (!vdev || !vdev->mlo_dev_ctx)
198 		return NULL;
199 
200 	return &vdev->mlo_dev_ctx->link_ctx->links_info[0];
201 }
202 
203 static
204 void mlo_mgr_alloc_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev)
205 {
206 	struct mlo_link_info *link_info;
207 	uint8_t link_info_iter;
208 
209 	if (!ml_dev)
210 		return;
211 
212 	link_info = &ml_dev->link_ctx->links_info[0];
213 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
214 	     link_info_iter++) {
215 		link_info->link_chan_info =
216 			qdf_mem_malloc(sizeof(*link_info->link_chan_info));
217 		if (!link_info->link_chan_info)
218 			return;
219 		link_info++;
220 	}
221 }
222 
223 static
224 void mlo_mgr_free_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev)
225 {
226 	struct mlo_link_info *link_info;
227 	uint8_t link_info_iter;
228 
229 	if (!ml_dev)
230 		return;
231 
232 	link_info = &ml_dev->link_ctx->links_info[0];
233 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
234 	     link_info_iter++) {
235 		if (link_info->link_chan_info)
236 			qdf_mem_free(link_info->link_chan_info);
237 		link_info++;
238 	}
239 }
240 
241 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
242 struct wlan_objmgr_vdev *
243 mlo_mgr_link_switch_get_assoc_vdev(struct wlan_objmgr_vdev *vdev)
244 {
245 	uint8_t vdev_id;
246 	struct wlan_objmgr_psoc *psoc;
247 	struct wlan_objmgr_vdev *assoc_vdev;
248 
249 	if (!vdev)
250 		return NULL;
251 
252 	if (!mlo_mgr_is_link_switch_on_assoc_vdev(vdev))
253 		return NULL;
254 
255 	vdev_id = vdev->mlo_dev_ctx->link_ctx->last_req.vdev_id;
256 	psoc = wlan_vdev_get_psoc(vdev);
257 	if (!psoc) {
258 		mlo_err("PSOC NULL");
259 		return NULL;
260 	}
261 
262 	assoc_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
263 							  WLAN_MLO_MGR_ID);
264 
265 	return assoc_vdev;
266 }
267 
268 bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev)
269 {
270 	enum mlo_link_switch_req_state state;
271 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
272 
273 	if (!mlo_dev_ctx)
274 		return false;
275 
276 	state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx);
277 	return (state != MLO_LINK_SWITCH_STATE_IDLE);
278 }
279 
280 bool mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev)
281 {
282 	if (!mlo_mgr_is_link_switch_in_progress(vdev))
283 		return false;
284 
285 	return vdev->mlo_dev_ctx->link_ctx->last_req.restore_vdev_flag;
286 }
287 
288 void mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
289 {
290 	mlo_dev_lock_acquire(mlo_dev_ctx);
291 	mlo_dev_ctx->link_ctx->last_req.state = MLO_LINK_SWITCH_STATE_IDLE;
292 	mlo_dev_lock_release(mlo_dev_ctx);
293 }
294 
295 QDF_STATUS
296 mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
297 {
298 	QDF_STATUS status = QDF_STATUS_SUCCESS;
299 	enum mlo_link_switch_req_state cur_state, next_state;
300 
301 	mlo_dev_lock_acquire(mlo_dev_ctx);
302 	cur_state = mlo_dev_ctx->link_ctx->last_req.state;
303 	switch (cur_state) {
304 	case MLO_LINK_SWITCH_STATE_IDLE:
305 		next_state = MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK;
306 		break;
307 	case MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK:
308 		next_state = MLO_LINK_SWITCH_STATE_SET_MAC_ADDR;
309 		break;
310 	case MLO_LINK_SWITCH_STATE_SET_MAC_ADDR:
311 		next_state = MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK;
312 		break;
313 	case MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK:
314 		next_state = MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS;
315 		break;
316 	case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS:
317 		next_state = MLO_LINK_SWITCH_STATE_IDLE;
318 		break;
319 	case MLO_LINK_SWITCH_STATE_ABORT_TRANS:
320 		next_state = MLO_LINK_SWITCH_STATE_ABORT_TRANS;
321 		status = QDF_STATUS_E_PERM;
322 		mlo_debug("State transition not allowed");
323 		break;
324 	default:
325 		QDF_ASSERT(0);
326 		break;
327 	}
328 	mlo_dev_ctx->link_ctx->last_req.state = next_state;
329 	mlo_dev_lock_release(mlo_dev_ctx);
330 
331 	return status;
332 }
333 
334 void
335 mlo_mgr_link_switch_trans_abort_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
336 {
337 	enum mlo_link_switch_req_state next_state =
338 					MLO_LINK_SWITCH_STATE_ABORT_TRANS;
339 
340 	mlo_dev_lock_acquire(mlo_dev_ctx);
341 	mlo_dev_ctx->link_ctx->last_req.state = next_state;
342 	mlo_dev_lock_release(mlo_dev_ctx);
343 }
344 
345 enum mlo_link_switch_req_state
346 mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
347 {
348 	enum mlo_link_switch_req_state state;
349 
350 	mlo_dev_lock_acquire(mlo_dev_ctx);
351 	state = mlo_dev_ctx->link_ctx->last_req.state;
352 	mlo_dev_lock_release(mlo_dev_ctx);
353 
354 	return state;
355 }
356 
357 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
358 static void
359 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev,
360 				       struct wlan_objmgr_vdev *assoc_vdev)
361 {
362 	QDF_STATUS status;
363 
364 	status = wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
365 					   wlan_vdev_get_id(assoc_vdev),
366 					   WLAN_ROAM_DEINIT,
367 					   REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE);
368 	if (QDF_IS_STATUS_ERROR(status))
369 		mlo_err("vdev:%d failed to change RSO state to deinit",
370 			wlan_vdev_get_id(assoc_vdev));
371 }
372 #else
373 static inline void
374 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev,
375 				       struct wlan_objmgr_vdev *assoc_vdev)
376 {}
377 #endif
378 
379 QDF_STATUS mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev,
380 					    struct wlan_mlo_link_switch_req *lswitch_req)
381 {
382 	uint8_t idx;
383 	uint16_t vdev_count;
384 	struct wlan_objmgr_vdev *assoc_vdev;
385 	struct wlan_mlo_sta *sta_ctx;
386 	struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
387 	QDF_STATUS status = QDF_STATUS_E_INVAL;
388 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
389 	QDF_STATUS(*cb)(struct wlan_objmgr_vdev *vdev,
390 			uint8_t non_trans_vdev_id);
391 
392 	if (!vdev->mlo_dev_ctx)
393 		return status;
394 
395 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
396 	if (!sta_ctx)
397 		return status;
398 
399 	assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
400 	if (!assoc_vdev)
401 		return status;
402 
403 	cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_link_switch_notification;
404 
405 	if (lswitch_req->restore_vdev_flag) {
406 		wlan_vdev_mlme_clear_mlo_link_vdev(vdev);
407 		wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev);
408 		mlo_mgr_reset_roam_state_for_link_vdev(vdev, assoc_vdev);
409 
410 		lswitch_req->restore_vdev_flag = false;
411 
412 		status = cb(assoc_vdev, wlan_vdev_get_id(vdev));
413 		return status;
414 	}
415 
416 	if (wlan_vdev_get_id(assoc_vdev) != lswitch_req->vdev_id) {
417 		mlo_debug("Not on assoc VDEV no need to swap");
418 		return QDF_STATUS_SUCCESS;
419 	}
420 
421 	mlo_sta_get_vdev_list(vdev, &vdev_count, vdev_list);
422 	for (idx = 0; idx < vdev_count; idx++) {
423 		if (wlan_vdev_get_id(vdev_list[idx]) != lswitch_req->vdev_id &&
424 		    qdf_test_bit(idx, sta_ctx->wlan_connected_links)) {
425 			wlan_vdev_mlme_clear_mlo_link_vdev(vdev_list[idx]);
426 			wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev);
427 			lswitch_req->restore_vdev_flag = true;
428 
429 			status = cb(assoc_vdev,
430 				    wlan_vdev_get_id(vdev_list[idx]));
431 			break;
432 		}
433 
434 		mlo_release_vdev_ref(vdev_list[idx]);
435 	}
436 
437 	for (; idx < vdev_count; idx++)
438 		mlo_release_vdev_ref(vdev_list[idx]);
439 
440 	return status;
441 }
442 
443 QDF_STATUS mlo_mgr_link_switch_init(struct wlan_mlo_dev_context *ml_dev)
444 {
445 	ml_dev->link_ctx =
446 		qdf_mem_malloc(sizeof(struct mlo_link_switch_context));
447 
448 	if (!ml_dev->link_ctx)
449 		return QDF_STATUS_E_NOMEM;
450 
451 	mlo_mgr_link_switch_init_state(ml_dev);
452 	mlo_mgr_alloc_link_info_wmi_chan(ml_dev);
453 	mlo_mgr_update_link_info_reset(ml_dev);
454 
455 	return QDF_STATUS_SUCCESS;
456 }
457 
458 QDF_STATUS mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev)
459 {
460 	mlo_mgr_free_link_info_wmi_chan(ml_dev);
461 	qdf_mem_free(ml_dev->link_ctx);
462 	ml_dev->link_ctx = NULL;
463 	return QDF_STATUS_SUCCESS;
464 }
465 
466 void
467 mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id)
468 {
469 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
470 	struct mlo_link_info *link_info;
471 	QDF_STATUS(*osif_bss_update_cb)(struct qdf_mac_addr *self_mac,
472 					struct qdf_mac_addr *bssid,
473 					int32_t link_id);
474 
475 	if (!g_mlo_ctx || !vdev->mlo_dev_ctx || !g_mlo_ctx->osif_ops ||
476 	    !g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info)
477 		return;
478 
479 	link_info = mlo_mgr_get_ap_link_by_link_id(vdev, link_id);
480 	if (!link_info)
481 		return;
482 
483 	mlo_debug("VDEV ID %d, Link ID %d, STA MAC " QDF_MAC_ADDR_FMT ", BSSID " QDF_MAC_ADDR_FMT,
484 		  link_info->vdev_id, link_id,
485 		  QDF_MAC_ADDR_REF(link_info->link_addr.bytes),
486 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
487 	osif_bss_update_cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info;
488 
489 	osif_bss_update_cb(&link_info->link_addr, &link_info->ap_link_addr,
490 			   link_id);
491 }
492 
493 QDF_STATUS mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev *vdev,
494 					       QDF_STATUS discon_status,
495 					       bool is_link_switch_resp)
496 {
497 	QDF_STATUS status;
498 	enum mlo_link_switch_req_state cur_state;
499 	struct mlo_link_info *new_link_info;
500 	struct qdf_mac_addr mac_addr, mld_addr;
501 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
502 	struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req;
503 
504 	if (!is_link_switch_resp) {
505 		mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx);
506 		return QDF_STATUS_SUCCESS;
507 	}
508 
509 	cur_state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx);
510 	if (QDF_IS_STATUS_ERROR(discon_status) ||
511 	    cur_state != MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK) {
512 		mlo_err("VDEV %d link switch disconnect req failed",
513 			req->vdev_id);
514 		mlo_mgr_remove_link_switch_cmd(vdev);
515 		return QDF_STATUS_SUCCESS;
516 	}
517 
518 	mlo_debug("VDEV %d link switch disconnect complete",
519 		  wlan_vdev_get_id(vdev));
520 
521 	new_link_info =
522 		mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id);
523 	if (!new_link_info) {
524 		mlo_err("New link not found in mlo dev ctx");
525 		mlo_mgr_remove_link_switch_cmd(vdev);
526 		return QDF_STATUS_E_INVAL;
527 	}
528 
529 	qdf_copy_macaddr(&mld_addr, &mlo_dev_ctx->mld_addr);
530 	qdf_copy_macaddr(&mac_addr, &new_link_info->link_addr);
531 
532 	status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx);
533 	if (QDF_IS_STATUS_ERROR(status)) {
534 		mlo_mgr_remove_link_switch_cmd(vdev);
535 		return status;
536 	}
537 
538 	status = wlan_vdev_mlme_send_set_mac_addr(mac_addr, mld_addr, vdev);
539 	if (QDF_IS_STATUS_ERROR(status))
540 		mlo_mgr_remove_link_switch_cmd(vdev);
541 
542 	return status;
543 }
544 
545 QDF_STATUS mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev,
546 						 uint8_t resp_status)
547 {
548 	QDF_STATUS status = QDF_STATUS_E_INVAL;
549 	enum mlo_link_switch_req_state cur_state;
550 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
551 	struct wlan_mlo_link_switch_req *req;
552 	struct mlo_link_info *new_link_info;
553 
554 	if (resp_status) {
555 		mlo_err("VDEV %d set MAC address response %d",
556 			wlan_vdev_get_id(vdev), resp_status);
557 		mlo_mgr_remove_link_switch_cmd(vdev);
558 		return status;
559 	}
560 
561 	if (!g_mlo_ctx) {
562 		mlo_err("global mlo ctx NULL");
563 		mlo_mgr_remove_link_switch_cmd(vdev);
564 		return status;
565 	}
566 
567 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
568 	cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
569 	if (cur_state != MLO_LINK_SWITCH_STATE_SET_MAC_ADDR) {
570 		mlo_err("Link switch cmd flushed, there can be MAC addr mismatch with FW");
571 		mlo_mgr_remove_link_switch_cmd(vdev);
572 		return status;
573 	}
574 
575 	new_link_info =
576 		mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id);
577 	if (!new_link_info) {
578 		mlo_mgr_remove_link_switch_cmd(vdev);
579 		return status;
580 	}
581 
582 	wlan_vdev_mlme_set_macaddr(vdev, new_link_info->link_addr.bytes);
583 	wlan_vdev_mlme_set_linkaddr(vdev, new_link_info->link_addr.bytes);
584 
585 	status = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_mac_addr(
586 							req->curr_ieee_link_id,
587 							req->new_ieee_link_id,
588 							req->vdev_id);
589 
590 	status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx);
591 	if (QDF_IS_STATUS_ERROR(status)) {
592 		mlo_mgr_remove_link_switch_cmd(vdev);
593 		return status;
594 	}
595 
596 	status = mlo_mgr_link_switch_start_connect(vdev);
597 
598 	return status;
599 }
600 
601 QDF_STATUS mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev *vdev)
602 {
603 	QDF_STATUS status = QDF_STATUS_E_INVAL;
604 	struct wlan_cm_connect_req conn_req = {0};
605 	struct mlo_link_info *mlo_link_info;
606 	uint8_t *vdev_mac;
607 	struct wlan_mlo_sta *sta_ctx;
608 	struct wlan_mlo_link_switch_req *req =
609 					&vdev->mlo_dev_ctx->link_ctx->last_req;
610 
611 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
612 
613 	mlo_link_info =
614 		mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id);
615 
616 	if (!mlo_link_info) {
617 		mlo_err("New link ID not found");
618 		goto out;
619 	}
620 
621 	vdev_mac = wlan_vdev_mlme_get_linkaddr(vdev);
622 	if (!qdf_is_macaddr_equal(&mlo_link_info->link_addr,
623 				  (struct qdf_mac_addr *)vdev_mac)) {
624 		mlo_err("MAC address not equal for the new Link ID VDEV: " QDF_MAC_ADDR_FMT ", MLO_LINK: " QDF_MAC_ADDR_FMT,
625 			QDF_MAC_ADDR_REF(vdev_mac),
626 			QDF_MAC_ADDR_REF(mlo_link_info->link_addr.bytes));
627 		goto out;
628 	}
629 
630 	wlan_vdev_set_link_id(vdev, req->new_ieee_link_id);
631 	copied_conn_req_lock_acquire(sta_ctx);
632 	if (sta_ctx->copied_conn_req) {
633 		qdf_mem_copy(&conn_req, sta_ctx->copied_conn_req,
634 			     sizeof(struct wlan_cm_connect_req));
635 	} else {
636 		copied_conn_req_lock_release(sta_ctx);
637 		goto out;
638 	}
639 	copied_conn_req_lock_release(sta_ctx);
640 
641 	conn_req.vdev_id = wlan_vdev_get_id(vdev);
642 	conn_req.source = CM_MLO_LINK_SWITCH_CONNECT;
643 	qdf_copy_macaddr(&conn_req.bssid, &mlo_link_info->ap_link_addr);
644 	mlo_allocate_and_copy_ies(&conn_req, sta_ctx->copied_conn_req);
645 	conn_req.crypto.auth_type = 0;
646 	conn_req.ml_parnter_info = sta_ctx->ml_partner_info;
647 	status = wlan_cm_start_connect(vdev, &conn_req);
648 	if (QDF_IS_STATUS_SUCCESS(status))
649 		mlo_update_connected_links(vdev, 1);
650 
651 	wlan_cm_free_connect_req_param(&conn_req);
652 
653 out:
654 	if (QDF_IS_STATUS_ERROR(status)) {
655 		mlo_err("VDEV %d link switch connect request failed",
656 			wlan_vdev_get_id(vdev));
657 		mlo_mgr_remove_link_switch_cmd(vdev);
658 	}
659 
660 	return status;
661 }
662 
663 void mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev,
664 				      QDF_STATUS status)
665 {
666 	struct wlan_mlo_link_switch_req *req;
667 
668 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
669 	if (QDF_IS_STATUS_SUCCESS(status))
670 		mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx);
671 	else
672 		mlo_err("VDEV %d link switch connect failed", req->vdev_id);
673 
674 	mlo_mgr_remove_link_switch_cmd(vdev);
675 }
676 
677 static QDF_STATUS
678 mlo_mgr_start_link_switch(struct wlan_objmgr_vdev *vdev,
679 			  struct wlan_serialization_command *cmd)
680 {
681 	int i;
682 	QDF_STATUS status = QDF_STATUS_E_INVAL;
683 	uint8_t vdev_id, old_link_id, new_link_id;
684 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
685 	struct mlo_link_switch_context *link_ctx = vdev->mlo_dev_ctx->link_ctx;
686 	struct wlan_mlo_link_switch_req *req = &link_ctx->last_req;
687 	struct qdf_mac_addr bssid;
688 
689 	if (!mlo_mgr_ctx) {
690 		mlo_err("Global mlo mgr NULL");
691 		return status;
692 	}
693 
694 	vdev_id = wlan_vdev_get_id(vdev);
695 	old_link_id = req->curr_ieee_link_id;
696 	new_link_id = req->new_ieee_link_id;
697 
698 	mlo_debug("VDEV %d start link switch", vdev_id);
699 	if (!wlan_cm_is_vdev_connected(vdev) ||
700 	    wlan_vdev_get_link_id(vdev) != old_link_id) {
701 		mlo_err("Link switch req link id mismatch, curr link id %d",
702 			wlan_vdev_get_link_id(vdev));
703 		return status;
704 	}
705 
706 	if (!wlan_cm_is_vdev_connected(vdev)) {
707 		mlo_err("VDEV %d not in connected state", vdev_id);
708 		return status;
709 	}
710 
711 	status = wlan_vdev_get_bss_peer_mac(vdev, &bssid);
712 	if (QDF_IS_STATUS_ERROR(status))
713 		return status;
714 
715 	status = wlan_vdev_get_bss_peer_mld_mac(vdev, &req->peer_mld_addr);
716 	if (QDF_IS_STATUS_ERROR(status))
717 		return status;
718 
719 	for (i = 0; i < WLAN_UMAC_COMP_ID_MAX; i++) {
720 		if (!mlo_mgr_ctx->lswitch_notifier[i].in_use)
721 			continue;
722 
723 		status = mlo_mgr_ctx->lswitch_notifier[i].cb(vdev, req);
724 		if (QDF_IS_STATUS_ERROR(status)) {
725 			mlme_err("Link switch start rejected by %d", i);
726 			return status;
727 		}
728 	}
729 
730 	wlan_vdev_mlme_set_mlo_link_switch_in_progress(vdev);
731 	status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx);
732 	if (QDF_IS_STATUS_ERROR(status))
733 		return status;
734 
735 	status = wlan_cm_disconnect(vdev, CM_MLO_LINK_SWITCH_DISCONNECT,
736 				    REASON_FW_TRIGGERED_LINK_SWITCH, &bssid);
737 
738 	if (QDF_IS_STATUS_ERROR(status))
739 		mlo_err("VDEV %d disconnect request not handled", req->vdev_id);
740 
741 	return status;
742 }
743 
744 static QDF_STATUS
745 mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd,
746 			   enum wlan_serialization_cb_reason reason)
747 {
748 	struct wlan_objmgr_vdev *vdev;
749 	QDF_STATUS status = QDF_STATUS_SUCCESS;
750 
751 	if (!cmd) {
752 		mlo_err("cmd is NULL, reason: %d", reason);
753 		QDF_ASSERT(0);
754 		return QDF_STATUS_E_NULL_VALUE;
755 	}
756 
757 	vdev = cmd->vdev;
758 	switch (reason) {
759 	case WLAN_SER_CB_ACTIVATE_CMD:
760 		status = mlo_mgr_start_link_switch(vdev, cmd);
761 		break;
762 	case WLAN_SER_CB_RELEASE_MEM_CMD:
763 		mlo_mgr_link_switch_complete(vdev);
764 		break;
765 	case WLAN_SER_CB_CANCEL_CMD:
766 		mlo_err("Link switch cmd cancelled");
767 		break;
768 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
769 		mlo_err("Link switch active cmd timeout");
770 		break;
771 	default:
772 		QDF_ASSERT(0);
773 		mlo_mgr_link_switch_complete(vdev);
774 		break;
775 	}
776 
777 	return status;
778 }
779 
780 void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev)
781 {
782 	QDF_STATUS status;
783 	struct wlan_serialization_queued_cmd_info cmd_info;
784 	enum mlo_link_switch_req_state cur_state;
785 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
786 	struct wlan_mlo_link_switch_req *req;
787 
788 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
789 	if (req->restore_vdev_flag) {
790 		status = mlo_mgr_link_switch_notification(vdev, req);
791 		if (QDF_IS_STATUS_ERROR(status)) {
792 			mlo_err("Failed to restore deflink in OSIF");
793 			req->restore_vdev_flag = false;
794 		}
795 	}
796 
797 	cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
798 	if (cur_state == MLO_LINK_SWITCH_STATE_IDLE)
799 		return;
800 
801 	cmd_info.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) +
802 			  (req->curr_ieee_link_id);
803 	cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
804 	cmd_info.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH;
805 	cmd_info.vdev = vdev;
806 	cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
807 
808 	wlan_serialization_remove_cmd(&cmd_info);
809 }
810 
811 #define MLO_MGR_MAX_LSWITCH_TIMEOUT	35000
812 
813 QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev,
814 				       struct wlan_mlo_link_switch_req *req)
815 {
816 	enum wlan_serialization_status ser_cmd_status;
817 	struct wlan_serialization_command cmd = {0};
818 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
819 	struct mlo_link_switch_context *link_ctx;
820 
821 	if (!vdev->mlo_dev_ctx) {
822 		mlo_err("ML dev ctx NULL, reject link switch");
823 		return QDF_STATUS_E_INVAL;
824 	}
825 
826 	link_ctx = vdev->mlo_dev_ctx->link_ctx;
827 	link_ctx->last_req = *req;
828 
829 	cmd.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH;
830 	cmd.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) +
831 		     (req->curr_ieee_link_id);
832 	cmd.cmd_cb = mlo_mgr_ser_link_switch_cb;
833 	cmd.source = WLAN_UMAC_COMP_MLO_MGR;
834 	cmd.is_high_priority = false;
835 	cmd.cmd_timeout_duration = MLO_MGR_MAX_LSWITCH_TIMEOUT;
836 	cmd.vdev = vdev;
837 	cmd.is_blocking = true;
838 
839 	ser_cmd_status = wlan_serialization_request(&cmd);
840 	switch (ser_cmd_status) {
841 	case WLAN_SER_CMD_PENDING:
842 		mlo_debug("Link switch cmd in pending queue");
843 		break;
844 	case WLAN_SER_CMD_ACTIVE:
845 		mlo_debug("Link switch cmd in active queue");
846 		break;
847 	default:
848 		return QDF_STATUS_E_INVAL;
849 	}
850 
851 	return QDF_STATUS_SUCCESS;
852 }
853 
854 QDF_STATUS
855 mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev,
856 				     struct wlan_mlo_link_switch_req *req)
857 {
858 	QDF_STATUS status = QDF_STATUS_E_INVAL;
859 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
860 
861 	if (req->curr_ieee_link_id >= WLAN_INVALID_LINK_ID ||
862 	    req->new_ieee_link_id >= WLAN_INVALID_LINK_ID) {
863 		mlo_err("Invalid link params, curr link id %d, new link id %d",
864 			req->curr_ieee_link_id, req->new_ieee_link_id);
865 		return status;
866 	}
867 
868 	if (!mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id)) {
869 		mlo_err("New link id %d not part of association",
870 			req->new_ieee_link_id);
871 		return status;
872 	}
873 
874 	if (!mlo_is_mld_sta(vdev)) {
875 		mlo_err("Link switch req not valid for VDEV %d", vdev_id);
876 		return status;
877 	}
878 
879 	if (!wlan_cm_is_vdev_connected(vdev)) {
880 		mlo_err("VDEV %d not in connected state", vdev_id);
881 		return status;
882 	}
883 
884 	if (mlo_mgr_is_link_switch_in_progress(vdev)) {
885 		mlo_err("Link switch already in progress");
886 		return status;
887 	}
888 
889 	if (wlan_vdev_get_link_id(vdev) != req->curr_ieee_link_id) {
890 		mlo_err("VDEV %d link id wrong, curr link id %d",
891 			vdev_id, wlan_vdev_get_link_id(vdev));
892 		return status;
893 	}
894 
895 	return QDF_STATUS_SUCCESS;
896 }
897 
898 QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc,
899 					      void *evt_params)
900 {
901 	QDF_STATUS status;
902 	struct wlan_mlo_link_switch_cnf cnf_params = {0};
903 	struct wlan_mlo_link_switch_req *req;
904 	struct wlan_objmgr_vdev *vdev;
905 
906 	if (!evt_params) {
907 		mlo_err("Invalid params");
908 		return QDF_STATUS_E_INVAL;
909 	}
910 
911 	req = (struct wlan_mlo_link_switch_req *)evt_params;
912 
913 	/* The reference is released on Link Switch status confirm to FW */
914 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id,
915 						    WLAN_MLO_MGR_ID);
916 	if (!vdev) {
917 		mlo_err("Invalid link switch VDEV %d", req->vdev_id);
918 
919 		/* Fill reject params here and send to FW as VDEV is invalid */
920 		cnf_params.vdev_id = req->vdev_id;
921 		cnf_params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT;
922 		mlo_mgr_link_switch_send_cnf_cmd(psoc, &cnf_params);
923 		return QDF_STATUS_E_INVAL;
924 	}
925 
926 	status = mlo_mgr_link_switch_validate_request(vdev, req);
927 	if (QDF_IS_STATUS_ERROR(status)) {
928 		mlo_debug("Link switch params/request invalid");
929 		mlo_mgr_link_switch_complete(vdev);
930 		return QDF_STATUS_E_INVAL;
931 	}
932 
933 	mlo_debug("VDEV %d, curr_link_id %d, new_link_id %d, new_freq %d, new_phymode: %d, reason %d",
934 		  req->vdev_id, req->curr_ieee_link_id, req->new_ieee_link_id,
935 		  req->new_primary_freq, req->new_phymode, req->reason);
936 
937 	status = mlo_mgr_ser_link_switch_cmd(vdev, req);
938 	if (QDF_IS_STATUS_ERROR(status)) {
939 		mlo_err("Failed to serialize link switch command");
940 		mlo_mgr_link_switch_complete(vdev);
941 	}
942 
943 	return status;
944 }
945 
946 QDF_STATUS mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev)
947 {
948 	enum mlo_link_switch_req_state state;
949 	struct wlan_mlo_link_switch_cnf params = {0};
950 	struct mlo_link_switch_context *link_ctx;
951 	struct wlan_mlo_link_switch_req *req;
952 	struct wlan_objmgr_psoc *psoc;
953 
954 	/* Not checking NULL value as reference is already taken for vdev */
955 	psoc = wlan_vdev_get_psoc(vdev);
956 
957 	link_ctx = vdev->mlo_dev_ctx->link_ctx;
958 	req = &link_ctx->last_req;
959 
960 	state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
961 	if (state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS)
962 		params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT;
963 	else
964 		params.status = MLO_LINK_SWITCH_CNF_STATUS_ACCEPT;
965 
966 	params.vdev_id = wlan_vdev_get_id(vdev);
967 	params.reason = MLO_LINK_SWITCH_CNF_REASON_BSS_PARAMS_CHANGED;
968 
969 	mlo_mgr_link_switch_send_cnf_cmd(psoc, &params);
970 
971 	mlo_mgr_link_switch_init_state(vdev->mlo_dev_ctx);
972 	wlan_vdev_mlme_clear_mlo_link_switch_in_progress(vdev);
973 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
974 	return QDF_STATUS_SUCCESS;
975 }
976 
977 QDF_STATUS
978 mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc *psoc,
979 				 struct wlan_mlo_link_switch_cnf *cnf_params)
980 {
981 	QDF_STATUS status;
982 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
983 
984 	mlo_debug("VDEV %d link switch completed, %s", cnf_params->vdev_id,
985 		  (cnf_params->status == MLO_LINK_SWITCH_CNF_STATUS_ACCEPT) ?
986 		  "success" : "fail");
987 
988 	mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
989 	if (!mlo_tx_ops || !mlo_tx_ops->send_mlo_link_switch_cnf_cmd) {
990 		mlo_err("handler is not registered");
991 		return QDF_STATUS_E_INVAL;
992 	}
993 
994 	status = mlo_tx_ops->send_mlo_link_switch_cnf_cmd(psoc, cnf_params);
995 	if (QDF_IS_STATUS_ERROR(status))
996 		mlo_err("Link switch status update to FW failed");
997 
998 	return status;
999 }
1000 #endif
1001