1 /*
2  * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * DOC: contains MLO manager 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 #include <wlan_mlo_mgr_roam.h>
29 #endif
30 #include "host_diag_core_event.h"
31 
mlo_mgr_update_link_info_mac_addr(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_mac_update * ml_mac_update)32 void mlo_mgr_update_link_info_mac_addr(struct wlan_objmgr_vdev *vdev,
33 				       struct wlan_mlo_link_mac_update *ml_mac_update)
34 {
35 	struct mlo_link_info *link_info;
36 	uint8_t link_info_iter;
37 	struct mlo_vdev_link_mac_info *link_mac_info;
38 
39 	if (!vdev || !vdev->mlo_dev_ctx || !ml_mac_update)
40 		return;
41 
42 	link_mac_info = &ml_mac_update->link_mac_info[0];
43 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
44 
45 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
46 	     link_info_iter++) {
47 		qdf_mem_copy(&link_info->link_addr,
48 			     &link_mac_info->link_mac_addr,
49 			     QDF_MAC_ADDR_SIZE);
50 
51 		link_info->vdev_id = link_mac_info->vdev_id;
52 		mlo_debug("Update STA Link info for vdev_id %d, link_addr:" QDF_MAC_ADDR_FMT,
53 			  link_info->vdev_id,
54 			  QDF_MAC_ADDR_REF(link_info->link_addr.bytes));
55 		link_mac_info++;
56 		link_info++;
57 	}
58 }
59 
mlo_mgr_update_ap_link_info(struct wlan_objmgr_vdev * vdev,uint8_t link_id,uint8_t * ap_link_addr,struct wlan_channel channel)60 void mlo_mgr_update_ap_link_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id,
61 				 uint8_t *ap_link_addr,
62 				 struct wlan_channel channel)
63 {
64 	struct mlo_link_info *link_info;
65 	uint8_t link_info_iter;
66 
67 	if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr)
68 		return;
69 
70 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
71 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
72 	     link_info_iter++) {
73 		if (qdf_is_macaddr_zero(&link_info->ap_link_addr))
74 			break;
75 
76 		link_info++;
77 	}
78 
79 	if (link_info_iter == WLAN_MAX_ML_BSS_LINKS)
80 		return;
81 
82 	qdf_mem_copy(&link_info->ap_link_addr, ap_link_addr, QDF_MAC_ADDR_SIZE);
83 
84 	qdf_mem_copy(link_info->link_chan_info, &channel, sizeof(channel));
85 	link_info->link_status_flags = 0;
86 	link_info->link_id = link_id;
87 	link_info->is_link_active = false;
88 
89 	mlo_debug("Update AP Link info for link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT,
90 		  link_info->link_id, link_info->vdev_id,
91 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
92 }
93 
mlo_mgr_clear_ap_link_info(struct wlan_objmgr_vdev * vdev,uint8_t * ap_link_addr)94 void mlo_mgr_clear_ap_link_info(struct wlan_objmgr_vdev *vdev,
95 				uint8_t *ap_link_addr)
96 {
97 	struct mlo_link_info *link_info;
98 	uint8_t link_info_iter;
99 
100 	if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr)
101 		return;
102 
103 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
104 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
105 	     link_info_iter++) {
106 		if (qdf_is_macaddr_equal(&link_info->ap_link_addr,
107 					 (struct qdf_mac_addr *)ap_link_addr)) {
108 			mlo_debug("Clear AP link info for link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT,
109 				  link_info->link_id, link_info->vdev_id,
110 				  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
111 
112 			qdf_mem_zero(&link_info->ap_link_addr,
113 				     QDF_MAC_ADDR_SIZE);
114 			qdf_mem_zero(link_info->link_chan_info,
115 				     sizeof(*link_info->link_chan_info));
116 			link_info->link_id = WLAN_INVALID_LINK_ID;
117 			link_info->link_status_flags = 0;
118 
119 			return;
120 		}
121 
122 		link_info++;
123 	}
124 }
125 
mlo_mgr_update_ap_channel_info(struct wlan_objmgr_vdev * vdev,uint8_t link_id,uint8_t * ap_link_addr,struct wlan_channel channel)126 void mlo_mgr_update_ap_channel_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id,
127 				    uint8_t *ap_link_addr,
128 				    struct wlan_channel channel)
129 {
130 	struct mlo_link_info *link_info;
131 
132 	if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr)
133 		return;
134 
135 	link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id);
136 	if (!link_info)
137 		return;
138 
139 	qdf_mem_copy(link_info->link_chan_info, &channel,
140 		     sizeof(*link_info->link_chan_info));
141 
142 	mlo_debug("update AP channel info link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT,
143 		  link_info->link_id, link_info->vdev_id,
144 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
145 	mlo_debug("ch_freq: %d, freq1: %d, freq2: %d, phy_mode: %d",
146 		  link_info->link_chan_info->ch_freq,
147 		  link_info->link_chan_info->ch_cfreq1,
148 		  link_info->link_chan_info->ch_cfreq2,
149 		  link_info->link_chan_info->ch_phymode);
150 }
151 
mlo_mgr_update_link_info_reset(struct wlan_objmgr_psoc * psoc,struct wlan_mlo_dev_context * ml_dev)152 void mlo_mgr_update_link_info_reset(struct wlan_objmgr_psoc *psoc,
153 				    struct wlan_mlo_dev_context *ml_dev)
154 {
155 	struct mlo_link_info *link_info;
156 	uint8_t link_info_iter;
157 
158 	if (!ml_dev)
159 		return;
160 
161 	link_info = &ml_dev->link_ctx->links_info[0];
162 
163 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
164 	     link_info_iter++) {
165 		if (!qdf_is_macaddr_zero(&link_info->ap_link_addr) &&
166 		    !qdf_is_macaddr_zero(&link_info->link_addr))
167 			wlan_crypto_free_key_by_link_id(
168 						psoc,
169 						&link_info->link_addr,
170 						link_info->link_id);
171 		qdf_mem_zero(&link_info->link_addr, QDF_MAC_ADDR_SIZE);
172 		qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE);
173 		qdf_mem_zero(link_info->link_chan_info,
174 			     sizeof(*link_info->link_chan_info));
175 		link_info->vdev_id = WLAN_INVALID_VDEV_ID;
176 		link_info->link_id = WLAN_INVALID_LINK_ID;
177 		link_info->link_status_flags = 0;
178 		link_info++;
179 	}
180 }
181 
mlo_mgr_reset_ap_link_info(struct wlan_objmgr_vdev * vdev)182 void mlo_mgr_reset_ap_link_info(struct wlan_objmgr_vdev *vdev)
183 {
184 	struct mlo_link_info *link_info;
185 	uint8_t link_info_iter;
186 	struct wlan_objmgr_psoc *psoc;
187 
188 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx)
189 		return;
190 
191 	psoc = wlan_vdev_get_psoc(vdev);
192 	if (!psoc) {
193 		mlo_err("psoc NULL");
194 		return;
195 	}
196 
197 	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
198 
199 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
200 	     link_info_iter++) {
201 		if (!qdf_is_macaddr_zero(&link_info->ap_link_addr) &&
202 		    !qdf_is_macaddr_zero(&link_info->link_addr))
203 			wlan_crypto_free_key_by_link_id(
204 						psoc,
205 						&link_info->link_addr,
206 						link_info->link_id);
207 		qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE);
208 		qdf_mem_zero(link_info->link_chan_info,
209 			     sizeof(*link_info->link_chan_info));
210 		link_info->link_id = WLAN_INVALID_LINK_ID;
211 		link_info->link_status_flags = 0;
212 		link_info++;
213 	}
214 }
215 
216 struct mlo_link_info
mlo_mgr_get_ap_link(struct wlan_objmgr_vdev * vdev)217 *mlo_mgr_get_ap_link(struct wlan_objmgr_vdev *vdev)
218 {
219 	if (!vdev || !vdev->mlo_dev_ctx)
220 		return NULL;
221 
222 	return &vdev->mlo_dev_ctx->link_ctx->links_info[0];
223 }
224 
225 static
mlo_mgr_alloc_link_info_wmi_chan(struct wlan_mlo_dev_context * ml_dev)226 void mlo_mgr_alloc_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev)
227 {
228 	struct mlo_link_info *link_info;
229 	uint8_t link_info_iter;
230 
231 	if (!ml_dev)
232 		return;
233 
234 	link_info = &ml_dev->link_ctx->links_info[0];
235 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
236 	     link_info_iter++) {
237 		link_info->link_chan_info =
238 			qdf_mem_malloc(sizeof(*link_info->link_chan_info));
239 		if (!link_info->link_chan_info)
240 			return;
241 		link_info++;
242 	}
243 }
244 
245 static
mlo_mgr_free_link_info_wmi_chan(struct wlan_mlo_dev_context * ml_dev)246 void mlo_mgr_free_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev)
247 {
248 	struct mlo_link_info *link_info;
249 	uint8_t link_info_iter;
250 
251 	if (!ml_dev)
252 		return;
253 
254 	link_info = &ml_dev->link_ctx->links_info[0];
255 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
256 	     link_info_iter++) {
257 		if (link_info->link_chan_info)
258 			qdf_mem_free(link_info->link_chan_info);
259 		link_info++;
260 	}
261 }
262 
263 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
264 struct mlo_link_info
mlo_mgr_get_ap_link_by_link_id(struct wlan_mlo_dev_context * mlo_dev_ctx,int link_id)265 *mlo_mgr_get_ap_link_by_link_id(struct wlan_mlo_dev_context *mlo_dev_ctx,
266 				int link_id)
267 {
268 	struct mlo_link_info *link_info;
269 	uint8_t link_info_iter;
270 
271 	if (!mlo_dev_ctx || link_id < 0 || link_id > 15)
272 		return NULL;
273 
274 	link_info = &mlo_dev_ctx->link_ctx->links_info[0];
275 	for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS;
276 	     link_info_iter++) {
277 		if (link_info->link_id == link_id)
278 			return link_info;
279 		link_info++;
280 	}
281 
282 	return NULL;
283 }
284 
mlo_mgr_update_csa_link_info(struct wlan_objmgr_pdev * pdev,struct wlan_mlo_dev_context * mlo_dev_ctx,struct csa_offload_params * csa_param,uint8_t link_id)285 bool mlo_mgr_update_csa_link_info(struct wlan_objmgr_pdev *pdev,
286 				  struct wlan_mlo_dev_context *mlo_dev_ctx,
287 				  struct csa_offload_params *csa_param,
288 				  uint8_t link_id)
289 {
290 	struct mlo_link_info *link_info;
291 	uint16_t bw_val;
292 	uint32_t ch_cfreq1, ch_cfreq2;
293 
294 	if (!mlo_dev_ctx) {
295 		mlo_err("invalid mlo dev ctx");
296 		goto done;
297 	}
298 
299 	bw_val = wlan_reg_get_bw_value(csa_param->new_ch_width);
300 
301 	link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx, link_id);
302 	if (!link_info) {
303 		mlo_err("invalid link_info");
304 		goto done;
305 	}
306 
307 	link_info->link_chan_info->ch_freq = csa_param->csa_chan_freq;
308 
309 	if (wlan_reg_is_6ghz_chan_freq(csa_param->csa_chan_freq)) {
310 		ch_cfreq1 = wlan_reg_compute_6g_center_freq_from_cfi(
311 					csa_param->new_ch_freq_seg1);
312 		ch_cfreq2 = wlan_reg_compute_6g_center_freq_from_cfi(
313 					csa_param->new_ch_freq_seg2);
314 	} else {
315 		ch_cfreq1 = wlan_reg_legacy_chan_to_freq(pdev,
316 					csa_param->new_ch_freq_seg1);
317 		ch_cfreq2 = wlan_reg_legacy_chan_to_freq(pdev,
318 					csa_param->new_ch_freq_seg2);
319 	}
320 
321 	link_info->link_chan_info->ch_cfreq1 = ch_cfreq1;
322 	link_info->link_chan_info->ch_cfreq2 = ch_cfreq2;
323 
324 	link_info->link_chan_info->ch_phymode = wlan_eht_chan_phy_mode(
325 					csa_param->csa_chan_freq,
326 					bw_val, csa_param->new_ch_width);
327 
328 	mlo_debug("CSA: freq: %d, cfreq1: %d, cfreq2: %d, bw: %d, phymode:%d",
329 		  link_info->link_chan_info->ch_freq, ch_cfreq1, ch_cfreq2,
330 		  bw_val, link_info->link_chan_info->ch_phymode);
331 
332 	return true;
333 done:
334 	return false;
335 }
336 
337 struct wlan_objmgr_vdev *
mlo_mgr_link_switch_get_assoc_vdev(struct wlan_objmgr_vdev * vdev)338 mlo_mgr_link_switch_get_assoc_vdev(struct wlan_objmgr_vdev *vdev)
339 {
340 	uint8_t vdev_id;
341 	struct wlan_objmgr_psoc *psoc;
342 	struct wlan_objmgr_vdev *assoc_vdev;
343 
344 	if (!vdev)
345 		return NULL;
346 
347 	if (!mlo_mgr_is_link_switch_on_assoc_vdev(vdev))
348 		return NULL;
349 
350 	vdev_id = vdev->mlo_dev_ctx->link_ctx->last_req.vdev_id;
351 	psoc = wlan_vdev_get_psoc(vdev);
352 	if (!psoc) {
353 		mlo_err("PSOC NULL");
354 		return NULL;
355 	}
356 
357 	assoc_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
358 							  WLAN_MLO_MGR_ID);
359 
360 	return assoc_vdev;
361 }
362 
mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev * vdev)363 bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev)
364 {
365 	enum mlo_link_switch_req_state state;
366 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
367 
368 	if (!mlo_dev_ctx)
369 		return false;
370 
371 	state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx);
372 	return (state > MLO_LINK_SWITCH_STATE_INIT);
373 }
374 
mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev * vdev)375 bool mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev)
376 {
377 	if (!mlo_mgr_is_link_switch_in_progress(vdev))
378 		return false;
379 
380 	return vdev->mlo_dev_ctx->link_ctx->last_req.restore_vdev_flag;
381 }
382 
mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context * mlo_dev_ctx)383 void mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
384 {
385 	mlo_dev_lock_acquire(mlo_dev_ctx);
386 	mlo_dev_ctx->link_ctx->last_req.state = MLO_LINK_SWITCH_STATE_IDLE;
387 	mlo_dev_lock_release(mlo_dev_ctx);
388 }
389 
390 QDF_STATUS
mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context * mlo_dev_ctx)391 mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
392 {
393 	QDF_STATUS status = QDF_STATUS_SUCCESS;
394 	enum mlo_link_switch_req_state cur_state, next_state;
395 
396 	mlo_dev_lock_acquire(mlo_dev_ctx);
397 	cur_state = mlo_dev_ctx->link_ctx->last_req.state;
398 	switch (cur_state) {
399 	case MLO_LINK_SWITCH_STATE_IDLE:
400 		next_state = MLO_LINK_SWITCH_STATE_INIT;
401 		break;
402 	case MLO_LINK_SWITCH_STATE_INIT:
403 		next_state = MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK;
404 		break;
405 	case MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK:
406 		next_state = MLO_LINK_SWITCH_STATE_SET_MAC_ADDR;
407 		break;
408 	case MLO_LINK_SWITCH_STATE_SET_MAC_ADDR:
409 		next_state = MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK;
410 		break;
411 	case MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK:
412 		next_state = MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS;
413 		break;
414 	case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS:
415 		next_state = MLO_LINK_SWITCH_STATE_IDLE;
416 		break;
417 	case MLO_LINK_SWITCH_STATE_ABORT_TRANS:
418 		next_state = cur_state;
419 		status = QDF_STATUS_E_PERM;
420 		mlo_debug("State transition not allowed");
421 		break;
422 	default:
423 		QDF_ASSERT(0);
424 		break;
425 	}
426 	mlo_dev_ctx->link_ctx->last_req.state = next_state;
427 	mlo_dev_lock_release(mlo_dev_ctx);
428 
429 	return status;
430 }
431 
432 void
mlo_mgr_link_switch_trans_abort_state(struct wlan_mlo_dev_context * mlo_dev_ctx)433 mlo_mgr_link_switch_trans_abort_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
434 {
435 	enum mlo_link_switch_req_state next_state =
436 					MLO_LINK_SWITCH_STATE_ABORT_TRANS;
437 
438 	mlo_dev_lock_acquire(mlo_dev_ctx);
439 	mlo_dev_ctx->link_ctx->last_req.state = next_state;
440 	mlo_dev_lock_release(mlo_dev_ctx);
441 }
442 
443 enum mlo_link_switch_req_state
mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context * mlo_dev_ctx)444 mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
445 {
446 	enum mlo_link_switch_req_state state;
447 
448 	mlo_dev_lock_acquire(mlo_dev_ctx);
449 	state = mlo_dev_ctx->link_ctx->last_req.state;
450 	mlo_dev_lock_release(mlo_dev_ctx);
451 
452 	return state;
453 }
454 
455 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
456 static void
mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_vdev * assoc_vdev)457 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev,
458 				       struct wlan_objmgr_vdev *assoc_vdev)
459 {
460 	QDF_STATUS status;
461 
462 	status = wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
463 					   wlan_vdev_get_id(assoc_vdev),
464 					   WLAN_ROAM_DEINIT,
465 					   REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE);
466 	if (QDF_IS_STATUS_ERROR(status))
467 		mlo_err("vdev:%d failed to change RSO state to deinit",
468 			wlan_vdev_get_id(assoc_vdev));
469 }
470 
471 static void
mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev * vdev)472 mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev *vdev)
473 {
474 	wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
475 				  wlan_vdev_get_id(vdev),
476 				  WLAN_ROAM_RSO_ENABLED,
477 				  REASON_CONNECT);
478 }
479 #else
480 static inline void
mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_vdev * assoc_vdev)481 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev,
482 				       struct wlan_objmgr_vdev *assoc_vdev)
483 {}
484 
485 static inline void
mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev * vdev)486 mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev *vdev)
487 {}
488 #endif
489 
490 static QDF_STATUS
mlo_mgr_link_switch_osif_notification(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * lswitch_req)491 mlo_mgr_link_switch_osif_notification(struct wlan_objmgr_vdev *vdev,
492 				      struct wlan_mlo_link_switch_req *lswitch_req)
493 {
494 	uint8_t idx;
495 	uint16_t vdev_count;
496 	struct wlan_objmgr_vdev *assoc_vdev;
497 	struct wlan_mlo_sta *sta_ctx;
498 	struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
499 	QDF_STATUS status = QDF_STATUS_E_INVAL;
500 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
501 	QDF_STATUS(*cb)(struct wlan_objmgr_vdev *vdev,
502 			uint8_t non_trans_vdev_id);
503 
504 	if (!vdev->mlo_dev_ctx)
505 		return status;
506 
507 	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
508 	if (!sta_ctx)
509 		return status;
510 
511 	assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
512 	if (!assoc_vdev)
513 		return status;
514 
515 	cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_link_switch_notification;
516 
517 	if (lswitch_req->restore_vdev_flag) {
518 		wlan_vdev_mlme_clear_mlo_link_vdev(vdev);
519 		wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev);
520 		mlo_mgr_reset_roam_state_for_link_vdev(vdev, assoc_vdev);
521 
522 		lswitch_req->restore_vdev_flag = false;
523 
524 		status = cb(assoc_vdev, wlan_vdev_get_id(vdev));
525 		if (QDF_IS_STATUS_ERROR(status))
526 			mlo_debug("OSIF deflink restore failed");
527 
528 		return status;
529 	}
530 
531 	if (wlan_vdev_get_id(assoc_vdev) != lswitch_req->vdev_id) {
532 		mlo_debug("Not on assoc VDEV no need to swap");
533 		return QDF_STATUS_SUCCESS;
534 	}
535 
536 	mlo_sta_get_vdev_list(vdev, &vdev_count, vdev_list);
537 	for (idx = 0; idx < vdev_count; idx++) {
538 		if (wlan_vdev_get_id(vdev_list[idx]) != lswitch_req->vdev_id &&
539 		    qdf_test_bit(idx, sta_ctx->wlan_connected_links)) {
540 			wlan_vdev_mlme_clear_mlo_link_vdev(vdev_list[idx]);
541 			wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev);
542 			lswitch_req->restore_vdev_flag = true;
543 
544 			status = cb(assoc_vdev,
545 				    wlan_vdev_get_id(vdev_list[idx]));
546 			break;
547 		}
548 
549 		mlo_release_vdev_ref(vdev_list[idx]);
550 	}
551 
552 	for (; idx < vdev_count; idx++)
553 		mlo_release_vdev_ref(vdev_list[idx]);
554 
555 	return status;
556 }
557 
558 QDF_STATUS
mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * lswitch_req,enum wlan_mlo_link_switch_notify_reason notify_reason)559 mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev,
560 				 struct wlan_mlo_link_switch_req *lswitch_req,
561 				 enum wlan_mlo_link_switch_notify_reason notify_reason)
562 {
563 	QDF_STATUS status;
564 
565 	switch (notify_reason) {
566 	case MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER:
567 	case MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER:
568 		if (!mlo_check_if_all_vdev_up(vdev)) {
569 			mlo_debug("Not all VDEVs up");
570 			return QDF_STATUS_E_AGAIN;
571 		}
572 
573 		if (mlo_is_chan_switch_in_progress(vdev)) {
574 			mlo_debug("CSA is in progress on one of ML vdevs, abort link switch");
575 			return QDF_STATUS_E_AGAIN;
576 		}
577 
578 		if (notify_reason ==
579 		    MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER) {
580 			return QDF_STATUS_SUCCESS;
581 		}
582 
583 		break;
584 	default:
585 		break;
586 	}
587 
588 	status = mlo_mgr_link_switch_osif_notification(vdev, lswitch_req);
589 
590 	return status;
591 }
592 
mlo_mgr_link_switch_init(struct wlan_objmgr_psoc * psoc,struct wlan_mlo_dev_context * ml_dev)593 QDF_STATUS mlo_mgr_link_switch_init(struct wlan_objmgr_psoc *psoc,
594 				    struct wlan_mlo_dev_context *ml_dev)
595 {
596 	ml_dev->link_ctx =
597 		qdf_mem_malloc(sizeof(struct mlo_link_switch_context));
598 
599 	if (!ml_dev->link_ctx)
600 		return QDF_STATUS_E_NOMEM;
601 
602 	mlo_mgr_link_switch_init_state(ml_dev);
603 	mlo_mgr_alloc_link_info_wmi_chan(ml_dev);
604 	mlo_mgr_update_link_info_reset(psoc, ml_dev);
605 
606 	return QDF_STATUS_SUCCESS;
607 }
608 
mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context * ml_dev)609 QDF_STATUS mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev)
610 {
611 	mlo_mgr_free_link_info_wmi_chan(ml_dev);
612 	qdf_mem_free(ml_dev->link_ctx);
613 	ml_dev->link_ctx = NULL;
614 	return QDF_STATUS_SUCCESS;
615 }
616 
617 void
mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev * vdev,int32_t link_id)618 mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id)
619 {
620 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
621 	struct mlo_link_info *link_info;
622 	QDF_STATUS(*osif_bss_update_cb)(struct qdf_mac_addr *self_mac,
623 					struct qdf_mac_addr *bssid,
624 					int32_t link_id);
625 
626 	if (!g_mlo_ctx || !vdev->mlo_dev_ctx || !g_mlo_ctx->osif_ops ||
627 	    !g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info)
628 		return;
629 
630 	link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id);
631 	if (!link_info)
632 		return;
633 
634 	mlo_debug("VDEV ID %d, Link ID %d, STA MAC " QDF_MAC_ADDR_FMT ", BSSID " QDF_MAC_ADDR_FMT,
635 		  link_info->vdev_id, link_id,
636 		  QDF_MAC_ADDR_REF(link_info->link_addr.bytes),
637 		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
638 	osif_bss_update_cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info;
639 
640 	osif_bss_update_cb(&link_info->link_addr, &link_info->ap_link_addr,
641 			   link_id);
642 }
643 
mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev * vdev,QDF_STATUS discon_status,bool is_link_switch_resp)644 QDF_STATUS mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev *vdev,
645 					       QDF_STATUS discon_status,
646 					       bool is_link_switch_resp)
647 {
648 	QDF_STATUS status;
649 	enum mlo_link_switch_req_state cur_state;
650 	struct mlo_link_info *new_link_info;
651 	struct qdf_mac_addr mac_addr, mld_addr;
652 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
653 	struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req;
654 
655 	if (!is_link_switch_resp) {
656 		mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx);
657 		return QDF_STATUS_SUCCESS;
658 	}
659 
660 	cur_state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx);
661 	if (QDF_IS_STATUS_ERROR(discon_status) ||
662 	    cur_state != MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK) {
663 		mlo_err("VDEV %d link switch disconnect req failed",
664 			req->vdev_id);
665 		mlo_mgr_remove_link_switch_cmd(vdev);
666 		return QDF_STATUS_SUCCESS;
667 	}
668 
669 	mlo_debug("VDEV %d link switch disconnect complete",
670 		  wlan_vdev_get_id(vdev));
671 
672 	new_link_info =
673 		mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx,
674 					       req->new_ieee_link_id);
675 	if (!new_link_info) {
676 		mlo_err("New link not found in mlo dev ctx");
677 		mlo_mgr_remove_link_switch_cmd(vdev);
678 		return QDF_STATUS_E_INVAL;
679 	}
680 
681 	qdf_copy_macaddr(&mld_addr, &mlo_dev_ctx->mld_addr);
682 	qdf_copy_macaddr(&mac_addr, &new_link_info->link_addr);
683 
684 	status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx);
685 	if (QDF_IS_STATUS_ERROR(status)) {
686 		mlo_mgr_remove_link_switch_cmd(vdev);
687 		return status;
688 	}
689 
690 	status = wlan_vdev_mlme_send_set_mac_addr(mac_addr, mld_addr, vdev);
691 	if (QDF_IS_STATUS_ERROR(status)) {
692 		mlo_debug("VDEV %d set MAC addr FW request failed",
693 			  req->vdev_id);
694 		mlo_mgr_remove_link_switch_cmd(vdev);
695 	}
696 
697 	return status;
698 }
699 
mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev * vdev,uint8_t resp_status)700 QDF_STATUS mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev,
701 						 uint8_t resp_status)
702 {
703 	QDF_STATUS status = QDF_STATUS_E_INVAL;
704 	enum mlo_link_switch_req_state cur_state;
705 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
706 	struct wlan_mlo_link_switch_req *req;
707 	struct mlo_link_info *new_link_info;
708 
709 	if (resp_status) {
710 		mlo_err("VDEV %d set MAC address response %d",
711 			wlan_vdev_get_id(vdev), resp_status);
712 		mlo_mgr_remove_link_switch_cmd(vdev);
713 		return status;
714 	}
715 
716 	if (!g_mlo_ctx) {
717 		mlo_err("global mlo ctx NULL");
718 		mlo_mgr_remove_link_switch_cmd(vdev);
719 		return status;
720 	}
721 
722 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
723 	cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
724 	if (cur_state != MLO_LINK_SWITCH_STATE_SET_MAC_ADDR) {
725 		mlo_err("Link switch cmd flushed, there can be MAC addr mismatch with FW");
726 		mlo_mgr_remove_link_switch_cmd(vdev);
727 		return status;
728 	}
729 
730 	new_link_info =
731 		mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx,
732 					       req->new_ieee_link_id);
733 	if (!new_link_info) {
734 		mlo_mgr_remove_link_switch_cmd(vdev);
735 		return status;
736 	}
737 
738 	wlan_vdev_mlme_set_macaddr(vdev, new_link_info->link_addr.bytes);
739 	wlan_vdev_mlme_set_linkaddr(vdev, new_link_info->link_addr.bytes);
740 
741 	status = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_mac_addr(
742 							req->curr_ieee_link_id,
743 							req->new_ieee_link_id,
744 							req->vdev_id);
745 	if (QDF_IS_STATUS_ERROR(status)) {
746 		mlo_debug("VDEV %d OSIF MAC addr update failed %d",
747 			  req->vdev_id, status);
748 		mlo_mgr_remove_link_switch_cmd(vdev);
749 		return status;
750 	}
751 
752 	status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx);
753 	if (QDF_IS_STATUS_ERROR(status)) {
754 		mlo_mgr_remove_link_switch_cmd(vdev);
755 		return status;
756 	}
757 
758 	status = mlo_mgr_link_switch_start_connect(vdev);
759 
760 	return status;
761 }
762 
mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev * vdev)763 QDF_STATUS mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev *vdev)
764 {
765 	QDF_STATUS status = QDF_STATUS_E_INVAL;
766 	struct wlan_cm_connect_req conn_req = {0};
767 	struct mlo_link_info *mlo_link_info;
768 	uint8_t *vdev_mac;
769 	struct wlan_mlo_sta *sta_ctx;
770 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
771 	struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req;
772 	struct wlan_objmgr_vdev *assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
773 
774 	if (!assoc_vdev) {
775 		mlo_err("Assoc VDEV not found");
776 		goto out;
777 	}
778 
779 	mlo_link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx,
780 						       req->new_ieee_link_id);
781 
782 	if (!mlo_link_info) {
783 		mlo_err("New link ID not found");
784 		goto out;
785 	}
786 
787 	vdev_mac = wlan_vdev_mlme_get_linkaddr(vdev);
788 	if (!qdf_is_macaddr_equal(&mlo_link_info->link_addr,
789 				  (struct qdf_mac_addr *)vdev_mac)) {
790 		mlo_err("MAC address not equal for the new Link ID VDEV: " QDF_MAC_ADDR_FMT ", MLO_LINK: " QDF_MAC_ADDR_FMT,
791 			QDF_MAC_ADDR_REF(vdev_mac),
792 			QDF_MAC_ADDR_REF(mlo_link_info->link_addr.bytes));
793 		goto out;
794 	}
795 
796 	sta_ctx = mlo_dev_ctx->sta_ctx;
797 	copied_conn_req_lock_acquire(sta_ctx);
798 	if (sta_ctx->copied_conn_req) {
799 		qdf_mem_copy(&conn_req, sta_ctx->copied_conn_req,
800 			     sizeof(struct wlan_cm_connect_req));
801 	} else {
802 		copied_conn_req_lock_release(sta_ctx);
803 		goto out;
804 	}
805 	copied_conn_req_lock_release(sta_ctx);
806 
807 	conn_req.vdev_id = wlan_vdev_get_id(vdev);
808 	conn_req.source = CM_MLO_LINK_SWITCH_CONNECT;
809 	wlan_vdev_set_link_id(vdev, req->new_ieee_link_id);
810 
811 	qdf_copy_macaddr(&conn_req.bssid, &mlo_link_info->ap_link_addr);
812 	wlan_vdev_mlme_get_ssid(assoc_vdev, conn_req.ssid.ssid,
813 				&conn_req.ssid.length);
814 	status = wlan_vdev_get_bss_peer_mld_mac(assoc_vdev, &conn_req.mld_addr);
815 	if (QDF_IS_STATUS_ERROR(status)) {
816 		mlo_debug("Get MLD addr failed");
817 		goto out;
818 	}
819 
820 	conn_req.crypto.auth_type = 0;
821 	conn_req.ml_parnter_info = sta_ctx->ml_partner_info;
822 	mlo_allocate_and_copy_ies(&conn_req, sta_ctx->copied_conn_req);
823 
824 	status = wlan_cm_start_connect(vdev, &conn_req);
825 	if (QDF_IS_STATUS_SUCCESS(status))
826 		mlo_update_connected_links(vdev, 1);
827 
828 	wlan_cm_free_connect_req_param(&conn_req);
829 
830 out:
831 	if (QDF_IS_STATUS_ERROR(status)) {
832 		mlo_err("VDEV %d link switch connect request failed",
833 			wlan_vdev_get_id(vdev));
834 		mlo_mgr_remove_link_switch_cmd(vdev);
835 	}
836 
837 	return status;
838 }
839 
840 static void
mlo_mgr_link_switch_connect_success_trans_state(struct wlan_objmgr_vdev * vdev)841 mlo_mgr_link_switch_connect_success_trans_state(struct wlan_objmgr_vdev *vdev)
842 {
843 	enum mlo_link_switch_req_state curr_state;
844 
845 	/*
846 	 * If connection is success, then sending link switch failure to FW
847 	 * might result in not updating VDEV to link mapping in FW and FW may
848 	 * immediately send next link switch with params corresponding to
849 	 * pre-link switch which may vary post-link switch in host and might
850 	 * not be valid and results in Host-FW out-of-sync.
851 	 *
852 	 * Force the result of link switch in align with link switch connect
853 	 * so that Host and FW are not out of sync.
854 	 */
855 	mlo_dev_lock_acquire(vdev->mlo_dev_ctx);
856 	curr_state = vdev->mlo_dev_ctx->link_ctx->last_req.state;
857 	vdev->mlo_dev_ctx->link_ctx->last_req.state =
858 					MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS;
859 	mlo_dev_lock_release(vdev->mlo_dev_ctx);
860 
861 	if (curr_state != MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK)
862 		mlo_debug("Current link switch state %d changed", curr_state);
863 }
864 
mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev * vdev,QDF_STATUS status)865 void mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev,
866 				      QDF_STATUS status)
867 {
868 	struct wlan_mlo_link_switch_req *req;
869 
870 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
871 	if (QDF_IS_STATUS_SUCCESS(status)) {
872 		mlo_mgr_link_switch_connect_success_trans_state(vdev);
873 	} else {
874 		mlo_update_connected_links(vdev, 0);
875 		mlo_err("VDEV %d link switch connect failed", req->vdev_id);
876 	}
877 
878 	mlo_mgr_remove_link_switch_cmd(vdev);
879 
880 	if (QDF_IS_STATUS_ERROR(status))
881 		mlo_mgr_restore_rso_upon_link_switch_failure(
882 				wlan_mlo_get_assoc_link_vdev(vdev));
883 }
884 
885 static enum wlan_mlo_link_switch_notify_reason
mlo_mgr_link_switch_get_notify_reason(struct wlan_objmgr_vdev * vdev)886 mlo_mgr_link_switch_get_notify_reason(struct wlan_objmgr_vdev *vdev)
887 {
888 	enum mlo_link_switch_req_state curr_state;
889 	enum wlan_mlo_link_switch_notify_reason notify_reason;
890 
891 	curr_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
892 	switch (curr_state) {
893 	case MLO_LINK_SWITCH_STATE_IDLE:
894 		notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER;
895 		break;
896 	case MLO_LINK_SWITCH_STATE_INIT:
897 		notify_reason =
898 			MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER;
899 		break;
900 	case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS:
901 		notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_SUCCESS;
902 		break;
903 	default:
904 		notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_FAILURE;
905 		break;
906 	}
907 
908 	return notify_reason;
909 }
910 
911 static QDF_STATUS
mlo_mgr_start_link_switch(struct wlan_objmgr_vdev * vdev,struct wlan_serialization_command * cmd)912 mlo_mgr_start_link_switch(struct wlan_objmgr_vdev *vdev,
913 			  struct wlan_serialization_command *cmd)
914 {
915 	QDF_STATUS status = QDF_STATUS_E_INVAL;
916 	uint8_t vdev_id, old_link_id, new_link_id;
917 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
918 	struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req;
919 	struct qdf_mac_addr bssid;
920 
921 	vdev_id = wlan_vdev_get_id(vdev);
922 	old_link_id = req->curr_ieee_link_id;
923 	new_link_id = req->new_ieee_link_id;
924 
925 	mlo_debug("VDEV %d start link switch", vdev_id);
926 	mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx);
927 
928 	if (!wlan_cm_is_vdev_connected(vdev)) {
929 		mlo_err("VDEV %d not in connected state", vdev_id);
930 		return status;
931 	}
932 
933 	status = wlan_vdev_get_bss_peer_mac(vdev, &bssid);
934 	if (QDF_IS_STATUS_ERROR(status))
935 		return status;
936 
937 	status = wlan_vdev_get_bss_peer_mld_mac(vdev, &req->peer_mld_addr);
938 	if (QDF_IS_STATUS_ERROR(status))
939 		return status;
940 
941 	status = mlo_mgr_link_switch_notify(vdev, req);
942 	if (QDF_IS_STATUS_ERROR(status))
943 		return status;
944 
945 	wlan_vdev_mlme_set_mlo_link_switch_in_progress(vdev);
946 	status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx);
947 	if (QDF_IS_STATUS_ERROR(status))
948 		return status;
949 
950 	status = wlan_cm_disconnect(vdev, CM_MLO_LINK_SWITCH_DISCONNECT,
951 				    REASON_FW_TRIGGERED_LINK_SWITCH, &bssid);
952 
953 	if (QDF_IS_STATUS_ERROR(status))
954 		mlo_err("VDEV %d disconnect request not handled", req->vdev_id);
955 
956 	return status;
957 }
958 
959 static QDF_STATUS
mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command * cmd,enum wlan_serialization_cb_reason cb_reason)960 mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd,
961 			   enum wlan_serialization_cb_reason cb_reason)
962 {
963 	struct wlan_objmgr_vdev *vdev;
964 	QDF_STATUS status = QDF_STATUS_SUCCESS;
965 	struct wlan_mlo_link_switch_req *req;
966 	enum qdf_hang_reason reason = QDF_VDEV_ACTIVE_SER_LINK_SWITCH_TIMEOUT;
967 
968 	if (!cmd) {
969 		mlo_err("cmd is NULL, reason: %d", cb_reason);
970 		QDF_ASSERT(0);
971 		return QDF_STATUS_E_NULL_VALUE;
972 	}
973 
974 	vdev = cmd->vdev;
975 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
976 
977 	switch (cb_reason) {
978 	case WLAN_SER_CB_ACTIVATE_CMD:
979 		status = mlo_mgr_start_link_switch(vdev, cmd);
980 		if (QDF_IS_STATUS_ERROR(status)) {
981 			mlo_mgr_link_switch_trans_abort_state(vdev->mlo_dev_ctx);
982 			mlo_mgr_link_switch_notify(vdev, req);
983 		}
984 		break;
985 	case WLAN_SER_CB_RELEASE_MEM_CMD:
986 		mlo_mgr_link_switch_complete(vdev);
987 		break;
988 	case WLAN_SER_CB_CANCEL_CMD:
989 		mlo_err("Link switch cmd cancelled");
990 		break;
991 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
992 		mlo_err("Link switch active cmd timeout");
993 		wlan_cm_trigger_panic_on_cmd_timeout(vdev, reason);
994 		break;
995 	default:
996 		QDF_ASSERT(0);
997 		mlo_mgr_link_switch_complete(vdev);
998 		break;
999 	}
1000 
1001 	return status;
1002 }
1003 
mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev * vdev)1004 void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev)
1005 {
1006 	struct wlan_serialization_queued_cmd_info cmd_info;
1007 	enum mlo_link_switch_req_state cur_state;
1008 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
1009 	struct wlan_mlo_link_switch_req *req;
1010 
1011 	cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
1012 	if (cur_state == MLO_LINK_SWITCH_STATE_IDLE)
1013 		return;
1014 
1015 	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
1016 	mlo_mgr_link_switch_notify(vdev, req);
1017 
1018 	/* Force queue disconnect on failure */
1019 	if (cur_state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS &&
1020 	    cur_state >= MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK &&
1021 	    !wlan_cm_is_vdev_connected(vdev)) {
1022 		mlo_mgr_link_switch_defer_disconnect_req(vdev,
1023 							 CM_MLME_DISCONNECT,
1024 							 REASON_HOST_TRIGGERED_LINK_DELETE);
1025 	}
1026 
1027 	/* Handle any pending disconnect */
1028 	mlo_handle_pending_disconnect(vdev);
1029 
1030 	if (req->reason == MLO_LINK_SWITCH_REASON_HOST_FORCE) {
1031 		mlo_debug("Link switch not serialized");
1032 		mlo_mgr_link_switch_complete(vdev);
1033 		return;
1034 	}
1035 
1036 	cmd_info.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) +
1037 			  (req->curr_ieee_link_id);
1038 	cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
1039 	cmd_info.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH;
1040 	cmd_info.vdev = vdev;
1041 	cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
1042 
1043 	wlan_serialization_remove_cmd(&cmd_info);
1044 }
1045 
1046 #define MLO_MGR_MAX_LSWITCH_TIMEOUT	35000
1047 
mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * req)1048 QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev,
1049 				       struct wlan_mlo_link_switch_req *req)
1050 {
1051 	QDF_STATUS status;
1052 	enum wlan_serialization_status ser_cmd_status;
1053 	struct wlan_serialization_command cmd = {0};
1054 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
1055 	struct mlo_link_switch_context *link_ctx;
1056 
1057 	if (!vdev->mlo_dev_ctx) {
1058 		mlo_err("ML dev ctx NULL, reject link switch");
1059 		return QDF_STATUS_E_INVAL;
1060 	}
1061 
1062 	link_ctx = vdev->mlo_dev_ctx->link_ctx;
1063 	link_ctx->last_req = *req;
1064 
1065 	cmd.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH;
1066 	cmd.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) +
1067 		     (req->curr_ieee_link_id);
1068 	cmd.cmd_cb = mlo_mgr_ser_link_switch_cb;
1069 	cmd.source = WLAN_UMAC_COMP_MLO_MGR;
1070 	cmd.is_high_priority = false;
1071 	cmd.cmd_timeout_duration = MLO_MGR_MAX_LSWITCH_TIMEOUT;
1072 	cmd.vdev = vdev;
1073 	cmd.is_blocking = true;
1074 
1075 	if (req->reason == MLO_LINK_SWITCH_REASON_HOST_FORCE) {
1076 		mlo_debug("Do not serialize link switch");
1077 		status = mlo_mgr_start_link_switch(vdev, &cmd);
1078 		if (QDF_IS_STATUS_ERROR(status)) {
1079 			mlo_mgr_link_switch_trans_abort_state(vdev->mlo_dev_ctx);
1080 			mlo_mgr_link_switch_notify(vdev, req);
1081 		}
1082 		return status;
1083 	}
1084 
1085 	ser_cmd_status = wlan_serialization_request(&cmd);
1086 	switch (ser_cmd_status) {
1087 	case WLAN_SER_CMD_PENDING:
1088 		mlo_debug("Link switch cmd in pending queue");
1089 		break;
1090 	case WLAN_SER_CMD_ACTIVE:
1091 		mlo_debug("Link switch cmd in active queue");
1092 		break;
1093 	default:
1094 		return QDF_STATUS_E_INVAL;
1095 	}
1096 
1097 	return QDF_STATUS_SUCCESS;
1098 }
1099 
mlo_mgr_link_switch_notify(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * req)1100 QDF_STATUS mlo_mgr_link_switch_notify(struct wlan_objmgr_vdev *vdev,
1101 				      struct wlan_mlo_link_switch_req *req)
1102 {
1103 	int8_t i;
1104 	QDF_STATUS status, ret_status = QDF_STATUS_SUCCESS;
1105 	enum wlan_mlo_link_switch_notify_reason notify_reason;
1106 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
1107 
1108 	if (!mlo_mgr_ctx) {
1109 		mlo_err("Global mlo mgr NULL");
1110 		return QDF_STATUS_E_NULL_VALUE;
1111 	}
1112 
1113 	notify_reason = mlo_mgr_link_switch_get_notify_reason(vdev);
1114 	for (i = 0; i < WLAN_UMAC_COMP_ID_MAX; i++) {
1115 		if (!mlo_mgr_ctx->lswitch_notifier[i].in_use)
1116 			continue;
1117 
1118 		status = mlo_mgr_ctx->lswitch_notifier[i].cb(vdev, req,
1119 							     notify_reason);
1120 		if (QDF_IS_STATUS_SUCCESS(status))
1121 			continue;
1122 
1123 		mlo_debug("Link switch notify %d failed in %d",
1124 			  notify_reason, i);
1125 		ret_status = status;
1126 		if (notify_reason == MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER)
1127 			break;
1128 	}
1129 
1130 	return ret_status;
1131 }
1132 
1133 QDF_STATUS
mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_link_switch_req * req)1134 mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev,
1135 				     struct wlan_mlo_link_switch_req *req)
1136 {
1137 	QDF_STATUS status = QDF_STATUS_E_INVAL;
1138 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
1139 	struct mlo_link_info *new_link_info;
1140 
1141 	if (req->curr_ieee_link_id >= WLAN_INVALID_LINK_ID ||
1142 	    req->new_ieee_link_id >= WLAN_INVALID_LINK_ID) {
1143 		mlo_err("Invalid link params, curr link id %d, new link id %d",
1144 			req->curr_ieee_link_id, req->new_ieee_link_id);
1145 		return status;
1146 	}
1147 
1148 	new_link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx,
1149 						       req->new_ieee_link_id);
1150 	if (!new_link_info) {
1151 		mlo_err("New link id %d not part of association",
1152 			req->new_ieee_link_id);
1153 		return status;
1154 	}
1155 
1156 	if (new_link_info->vdev_id != WLAN_INVALID_VDEV_ID) {
1157 		mlo_err("requested link already active on other vdev:%d",
1158 			new_link_info->vdev_id);
1159 		return status;
1160 	}
1161 
1162 	if (!mlo_is_mld_sta(vdev)) {
1163 		mlo_err("Link switch req not valid for VDEV %d", vdev_id);
1164 		return status;
1165 	}
1166 
1167 	if (!wlan_cm_is_vdev_connected(vdev)) {
1168 		mlo_err("VDEV %d not in connected state", vdev_id);
1169 		return status;
1170 	}
1171 
1172 	if (mlo_mgr_is_link_switch_in_progress(vdev)) {
1173 		mlo_err("Link switch already in progress");
1174 		return status;
1175 	}
1176 
1177 	if (wlan_vdev_get_link_id(vdev) != req->curr_ieee_link_id) {
1178 		mlo_err("VDEV %d link id wrong, curr link id %d",
1179 			vdev_id, wlan_vdev_get_link_id(vdev));
1180 		return status;
1181 	}
1182 
1183 	/* Notify callers on the new link switch request before serializing */
1184 	status = mlo_mgr_link_switch_notify(vdev, req);
1185 	if (QDF_IS_STATUS_ERROR(status)) {
1186 		mlo_err("Link switch rejected in pre-serialize notify");
1187 		return status;
1188 	}
1189 
1190 	return QDF_STATUS_SUCCESS;
1191 }
1192 
mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc * psoc,void * evt_params)1193 QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc,
1194 					      void *evt_params)
1195 {
1196 	QDF_STATUS status;
1197 	struct wlan_mlo_link_switch_cnf cnf_params = {0};
1198 	struct wlan_mlo_link_switch_req *req;
1199 	struct wlan_objmgr_vdev *vdev;
1200 
1201 	if (!evt_params) {
1202 		mlo_err("Invalid params");
1203 		return QDF_STATUS_E_INVAL;
1204 	}
1205 
1206 	req = (struct wlan_mlo_link_switch_req *)evt_params;
1207 
1208 	/* The reference is released on Link Switch status confirm to FW */
1209 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id,
1210 						    WLAN_MLO_MGR_ID);
1211 	if (!vdev) {
1212 		mlo_err("Invalid link switch VDEV %d", req->vdev_id);
1213 
1214 		/* Fill reject params here and send to FW as VDEV is invalid */
1215 		cnf_params.vdev_id = req->vdev_id;
1216 		cnf_params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT;
1217 		mlo_mgr_link_switch_send_cnf_cmd(psoc, &cnf_params);
1218 		return QDF_STATUS_E_INVAL;
1219 	}
1220 
1221 	mlo_debug("VDEV %d, curr_link_id %d, new_link_id %d, new_freq %d, new_phymode: %d, reason %d",
1222 		  req->vdev_id, req->curr_ieee_link_id, req->new_ieee_link_id,
1223 		  req->new_primary_freq, req->new_phymode, req->reason);
1224 
1225 	status = mlo_mgr_link_switch_validate_request(vdev, req);
1226 	if (QDF_IS_STATUS_ERROR(status)) {
1227 		mlo_debug("Link switch params/request invalid");
1228 		mlo_mgr_link_switch_complete(vdev);
1229 		return QDF_STATUS_E_INVAL;
1230 	}
1231 
1232 	status = mlo_mgr_ser_link_switch_cmd(vdev, req);
1233 	if (QDF_IS_STATUS_ERROR(status)) {
1234 		mlo_err("Failed to serialize link switch command");
1235 		mlo_mgr_link_switch_complete(vdev);
1236 	}
1237 
1238 	return status;
1239 }
1240 
1241 #define IS_LINK_SET(link_bitmap, link_id) ((link_bitmap) & (BIT(link_id)))
1242 
mlo_mgr_update_link_state(struct wlan_mlo_dev_context * mld_ctx,uint32_t active_link_bitmap)1243 static void mlo_mgr_update_link_state(struct wlan_mlo_dev_context *mld_ctx,
1244 				      uint32_t active_link_bitmap)
1245 {
1246 	uint8_t i;
1247 	struct mlo_link_info *link_info;
1248 
1249 	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
1250 		link_info = &mld_ctx->link_ctx->links_info[i];
1251 
1252 		if (IS_LINK_SET(active_link_bitmap, link_info->link_id))
1253 			link_info->is_link_active = true;
1254 		else
1255 			link_info->is_link_active = false;
1256 	}
1257 }
1258 
1259 QDF_STATUS
mlo_mgr_link_state_switch_info_handler(struct wlan_objmgr_psoc * psoc,struct mlo_link_switch_state_info * info)1260 mlo_mgr_link_state_switch_info_handler(struct wlan_objmgr_psoc *psoc,
1261 				       struct mlo_link_switch_state_info *info)
1262 {
1263 	uint8_t i;
1264 	struct wlan_mlo_dev_context *mld_ctx = NULL;
1265 
1266 	wlan_mlo_get_mlpeer_by_peer_mladdr(
1267 			&info->link_switch_param[0].mld_addr, &mld_ctx);
1268 
1269 	if (!mld_ctx) {
1270 		mlo_err("mlo dev ctx for mld_mac: " QDF_MAC_ADDR_FMT " not found",
1271 			QDF_MAC_ADDR_REF(info->link_switch_param[0].mld_addr.bytes));
1272 		return QDF_STATUS_E_INVAL;
1273 	}
1274 
1275 	for (i = 0; i < info->num_params; i++) {
1276 		wlan_connectivity_mld_link_status_event(
1277 				psoc,
1278 				&info->link_switch_param[i]);
1279 		mlo_mgr_update_link_state(
1280 				mld_ctx,
1281 				info->link_switch_param[i].active_link_bitmap);
1282 	}
1283 
1284 	return QDF_STATUS_SUCCESS;
1285 }
1286 
mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev * vdev)1287 QDF_STATUS mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev)
1288 {
1289 	enum mlo_link_switch_req_state state;
1290 	struct wlan_mlo_link_switch_cnf params = {0};
1291 	struct mlo_link_switch_context *link_ctx;
1292 	struct wlan_mlo_link_switch_req *req;
1293 	struct wlan_objmgr_psoc *psoc;
1294 
1295 	/* Not checking NULL value as reference is already taken for vdev */
1296 	psoc = wlan_vdev_get_psoc(vdev);
1297 
1298 	link_ctx = vdev->mlo_dev_ctx->link_ctx;
1299 	req = &link_ctx->last_req;
1300 
1301 	state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
1302 	if (state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS)
1303 		params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT;
1304 	else
1305 		params.status = MLO_LINK_SWITCH_CNF_STATUS_ACCEPT;
1306 
1307 	params.vdev_id = wlan_vdev_get_id(vdev);
1308 	params.reason = MLO_LINK_SWITCH_CNF_REASON_BSS_PARAMS_CHANGED;
1309 
1310 	mlo_mgr_link_switch_send_cnf_cmd(psoc, &params);
1311 
1312 	mlo_mgr_link_switch_init_state(vdev->mlo_dev_ctx);
1313 	wlan_vdev_mlme_clear_mlo_link_switch_in_progress(vdev);
1314 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1315 	return QDF_STATUS_SUCCESS;
1316 }
1317 
1318 QDF_STATUS
mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc * psoc,struct wlan_mlo_link_switch_cnf * cnf_params)1319 mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc *psoc,
1320 				 struct wlan_mlo_link_switch_cnf *cnf_params)
1321 {
1322 	QDF_STATUS status;
1323 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
1324 
1325 	mlo_debug("VDEV %d link switch completed, %s", cnf_params->vdev_id,
1326 		  (cnf_params->status == MLO_LINK_SWITCH_CNF_STATUS_ACCEPT) ?
1327 		  "success" : "fail");
1328 
1329 	mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
1330 	if (!mlo_tx_ops || !mlo_tx_ops->send_mlo_link_switch_cnf_cmd) {
1331 		mlo_err("handler is not registered");
1332 		return QDF_STATUS_E_INVAL;
1333 	}
1334 
1335 	status = mlo_tx_ops->send_mlo_link_switch_cnf_cmd(psoc, cnf_params);
1336 	if (QDF_IS_STATUS_ERROR(status))
1337 		mlo_err("Link switch status update to FW failed");
1338 
1339 	return status;
1340 }
1341 
1342 QDF_STATUS
mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev * vdev,enum wlan_cm_source source,enum wlan_reason_code reason)1343 mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev *vdev,
1344 					 enum wlan_cm_source source,
1345 					 enum wlan_reason_code reason)
1346 {
1347 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1348 	struct wlan_mlo_sta *sta_ctx;
1349 
1350 	if (!mlo_mgr_is_link_switch_in_progress(vdev)) {
1351 		mlo_info("Link switch not in progress");
1352 		return QDF_STATUS_E_INVAL;
1353 	}
1354 
1355 	mlo_dev_ctx = vdev->mlo_dev_ctx;
1356 	sta_ctx = mlo_dev_ctx->sta_ctx;
1357 
1358 	if (!sta_ctx) {
1359 		mlo_err("sta ctx null");
1360 		return QDF_STATUS_E_NULL_VALUE;
1361 	}
1362 
1363 	/* Move current link switch to abort state */
1364 	mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx);
1365 
1366 	if (sta_ctx->disconn_req) {
1367 		mlo_debug("Pending disconnect from source %d, reason %d",
1368 			  sta_ctx->disconn_req->source,
1369 			  sta_ctx->disconn_req->reason_code);
1370 		return QDF_STATUS_E_ALREADY;
1371 	}
1372 
1373 	sta_ctx->disconn_req =
1374 			qdf_mem_malloc(sizeof(struct wlan_cm_disconnect_req));
1375 	if (!sta_ctx->disconn_req)
1376 		return QDF_STATUS_E_NOMEM;
1377 
1378 	sta_ctx->disconn_req->vdev_id = wlan_vdev_get_id(vdev);
1379 	sta_ctx->disconn_req->source = source;
1380 	sta_ctx->disconn_req->reason_code = reason;
1381 
1382 	mlo_debug("Deferred disconnect source: %d, reason: %d", source, reason);
1383 	return QDF_STATUS_SUCCESS;
1384 }
1385 #endif
1386