1 /*
2 * Copyright (c) 2021-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 roaming related functionality
19 */
20 #include <wlan_cmn.h>
21 #include <wlan_cm_public_struct.h>
22 #include <wlan_cm_roam_public_struct.h>
23 #include "wlan_mlo_mgr_cmn.h"
24 #include "wlan_mlo_mgr_main.h"
25 #include "wlan_mlo_mgr_roam.h"
26 #include "wlan_mlo_mgr_public_structs.h"
27 #include "wlan_mlo_mgr_sta.h"
28 #include <../../core/src/wlan_cm_roam_i.h>
29 #include "wlan_cm_roam_api.h"
30 #include "wlan_mlme_vdev_mgr_interface.h"
31 #include <include/wlan_mlme_cmn.h>
32 #include <wlan_cm_api.h>
33 #include <utils_mlo.h>
34 #include <wlan_mlo_mgr_peer.h>
35 #include "wlan_mlo_link_force.h"
36
37 #ifdef WLAN_FEATURE_11BE_MLO
38 static bool
mlo_check_connect_req_bmap(struct wlan_objmgr_vdev * vdev)39 mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev)
40 {
41 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
42 struct wlan_mlo_sta *sta_ctx;
43 uint8_t i = 0;
44
45 if (!mlo_dev_ctx)
46 return false;
47
48 sta_ctx = mlo_dev_ctx->sta_ctx;
49
50 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
51 if (!mlo_dev_ctx->wlan_vdev_list[i])
52 continue;
53
54 if (vdev == mlo_dev_ctx->wlan_vdev_list[i])
55 return qdf_test_bit(i, sta_ctx->wlan_connect_req_links);
56 }
57
58 mlo_err("vdev:%d not found in ml dev ctx list", wlan_vdev_get_id(vdev));
59
60 return false;
61 }
62
63 static void
mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t ml_link_vdev_id)64 mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc *psoc,
65 uint8_t vdev_id,
66 uint8_t ml_link_vdev_id)
67 {
68 struct wlan_objmgr_vdev *vdev;
69
70 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
71 ml_link_vdev_id,
72 WLAN_MLME_SB_ID);
73 if (!vdev) {
74 mlo_err("VDEV is null");
75 return;
76 }
77
78 if (vdev_id == ml_link_vdev_id) {
79 wlan_vdev_mlme_set_mlo_vdev(vdev);
80 goto end;
81 }
82
83 wlan_vdev_mlme_set_mlo_vdev(vdev);
84 wlan_vdev_mlme_set_mlo_link_vdev(vdev);
85
86 mlo_update_connect_req_links(vdev, true);
87
88 end:
89 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
90 }
91
92 static void
mlo_cleanup_link(struct wlan_objmgr_vdev * vdev,uint8_t num_setup_links)93 mlo_cleanup_link(struct wlan_objmgr_vdev *vdev, uint8_t num_setup_links)
94 {
95 /*
96 * Cleanup the non-assoc link link in below cases,
97 * 1. Roamed to single link-MLO AP
98 * 2. Roamed to an MLO AP but 4-way handshake is offloaded to
99 * userspace, i.e.auth_status = ROAM_AUTH_STATUS_CONNECTED
100 * 3. Roamed to non-MLO AP(num_setup_links = 0)
101 * This covers all supported combinations. So cleanup the link always.
102 */
103 if (wlan_vdev_mlme_is_mlo_link_vdev(vdev))
104 cm_cleanup_mlo_link(vdev);
105 /*
106 * Clear the MLO vdev flag when roam to a non-MLO AP to prepare the
107 * roam done indication to userspace in non-MLO format
108 * i.e. without MLD/link info
109 */
110 else if (wlan_vdev_mlme_is_mlo_vdev(vdev) && !num_setup_links)
111 wlan_vdev_mlme_clear_mlo_vdev(vdev);
112 }
113
114 static void
mlo_update_vdev_after_roam(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t num_setup_links)115 mlo_update_vdev_after_roam(struct wlan_objmgr_psoc *psoc,
116 uint8_t vdev_id, uint8_t num_setup_links)
117 {
118 struct wlan_mlo_dev_context *mlo_dev_ctx;
119 uint8_t i;
120 struct wlan_objmgr_vdev *vdev, *tmp_vdev;
121
122 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
123 vdev_id,
124 WLAN_MLME_SB_ID);
125 if (!vdev) {
126 mlo_err("VDEV:%d is null", vdev_id);
127 return;
128 }
129
130 if (!vdev->mlo_dev_ctx)
131 goto end;
132
133 mlo_dev_ctx = vdev->mlo_dev_ctx;
134 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
135 if (!mlo_dev_ctx->wlan_vdev_list[i])
136 continue;
137
138 tmp_vdev = mlo_dev_ctx->wlan_vdev_list[i];
139 mlo_cleanup_link(tmp_vdev, num_setup_links);
140 }
141
142 end:
143 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
144 }
145
146 static void
mlo_clear_link_bmap(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)147 mlo_clear_link_bmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
148 {
149 struct wlan_objmgr_vdev *vdev;
150
151 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
152 vdev_id,
153 WLAN_MLME_SB_ID);
154 if (!vdev) {
155 mlo_err("VDEV is null");
156 return;
157 }
158
159 mlo_clear_connect_req_links_bmap(vdev);
160 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
161 }
162
163 static QDF_STATUS
mlo_roam_abort_req(struct wlan_objmgr_psoc * psoc,uint8_t * event,uint8_t vdev_id)164 mlo_roam_abort_req(struct wlan_objmgr_psoc *psoc,
165 uint8_t *event, uint8_t vdev_id)
166 {
167 struct roam_offload_synch_ind *sync_ind = NULL;
168
169 sync_ind = (struct roam_offload_synch_ind *)event;
170
171 if (!sync_ind) {
172 mlme_err("Roam Sync ind ptr is NULL");
173 return QDF_STATUS_E_NULL_VALUE;
174 }
175
176 wlan_mlo_roam_abort_on_link(psoc, event, sync_ind->roamed_vdev_id);
177
178 return QDF_STATUS_SUCCESS;
179 }
180 #else
181 static inline void
mlo_clear_link_bmap(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)182 mlo_clear_link_bmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
183 {}
184
185 static inline void
mlo_update_vdev_after_roam(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t num_setup_links)186 mlo_update_vdev_after_roam(struct wlan_objmgr_psoc *psoc,
187 uint8_t vdev_id, uint8_t num_setup_links)
188 {}
189
190 static inline void
mlo_cleanup_link(struct wlan_objmgr_vdev * vdev,uint8_t num_setup_links)191 mlo_cleanup_link(struct wlan_objmgr_vdev *vdev, uint8_t num_setup_links)
192 {}
193
194 static inline void
mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t ml_link_vdev_id)195 mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc *psoc,
196 uint8_t vdev_id,
197 uint8_t ml_link_vdev_id)
198 {}
199
200 static inline bool
mlo_check_connect_req_bmap(struct wlan_objmgr_vdev * vdev)201 mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev)
202 {
203 return false;
204 }
205
206 static inline QDF_STATUS
mlo_roam_abort_req(struct wlan_objmgr_psoc * psoc,uint8_t * event,uint8_t vdev_id)207 mlo_roam_abort_req(struct wlan_objmgr_psoc *psoc,
208 uint8_t *event, uint8_t vdev_id)
209 {
210 return QDF_STATUS_E_NOSUPPORT;
211 }
212 #endif
213
mlo_roam_update_vdev_macaddr(struct wlan_objmgr_psoc * psoc,struct roam_offload_synch_ind * sync_ind,uint8_t vdev_id,bool is_non_ml_connection)214 static void mlo_roam_update_vdev_macaddr(struct wlan_objmgr_psoc *psoc,
215 struct roam_offload_synch_ind *sync_ind,
216 uint8_t vdev_id,
217 bool is_non_ml_connection)
218 {
219 struct wlan_objmgr_vdev *vdev;
220 struct qdf_mac_addr *mld_mac;
221
222 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
223 vdev_id,
224 WLAN_MLO_MGR_ID);
225 if (!vdev) {
226 mlo_err("VDEV is null");
227 return;
228 }
229
230 if (is_non_ml_connection) {
231 mld_mac = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
232 if (!qdf_is_macaddr_zero(mld_mac))
233 wlan_vdev_mlme_set_macaddr(vdev, mld_mac->bytes);
234 } else {
235 struct qdf_mac_addr *vdev_link_addr;
236 uint8_t i;
237
238 wlan_vdev_mlme_set_macaddr(vdev,
239 wlan_vdev_mlme_get_linkaddr(vdev));
240 /* Update the link address received from fw to assoc vdev */
241 for (i = 0; i < sync_ind->num_setup_links; i++) {
242 if (vdev_id != sync_ind->ml_link[i].vdev_id)
243 continue;
244
245 vdev_link_addr = &sync_ind->ml_link[i].self_link_addr;
246 if (qdf_is_macaddr_zero(vdev_link_addr) ||
247 qdf_is_macaddr_broadcast(vdev_link_addr))
248 continue;
249
250 wlan_vdev_mlme_set_macaddr(vdev, vdev_link_addr->bytes);
251 wlan_vdev_mlme_set_linkaddr(vdev,
252 vdev_link_addr->bytes);
253 }
254 }
255
256 mlme_debug("vdev_id %d self mac " QDF_MAC_ADDR_FMT,
257 vdev_id,
258 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)));
259 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
260 }
261
mlo_fw_roam_sync_req(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,void * event,uint32_t event_data_len)262 QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
263 void *event, uint32_t event_data_len)
264 {
265 struct roam_offload_synch_ind *sync_ind;
266 QDF_STATUS status;
267 uint8_t i;
268 bool is_non_mlo_ap = false;
269
270 sync_ind = (struct roam_offload_synch_ind *)event;
271 if (!sync_ind)
272 return QDF_STATUS_E_FAILURE;
273
274 for (i = 0; i < sync_ind->num_setup_links; i++)
275 mlo_update_for_multi_link_roam(psoc, vdev_id,
276 sync_ind->ml_link[i].vdev_id);
277
278 if (!sync_ind->num_setup_links) {
279 mlo_debug("MLO_ROAM: Roamed to Legacy");
280 is_non_mlo_ap = true;
281 mlo_set_single_link_ml_roaming(psoc, vdev_id, false);
282 } else if (sync_ind->num_setup_links == 1 ||
283 sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) {
284 mlo_debug("MLO_ROAM: Roamed to single link MLO");
285 mlo_set_single_link_ml_roaming(psoc, vdev_id, true);
286 } else {
287 mlo_debug("MLO_ROAM: Roamed to MLO with %d links",
288 sync_ind->num_setup_links);
289 mlo_set_single_link_ml_roaming(psoc, vdev_id, false);
290 }
291
292 mlo_roam_update_vdev_macaddr(psoc, sync_ind, vdev_id, is_non_mlo_ap);
293 ml_nlink_conn_change_notify(
294 psoc, vdev_id, ml_nlink_roam_sync_start_evt, NULL);
295
296 status = cm_fw_roam_sync_req(psoc, vdev_id, event, event_data_len);
297
298 if (QDF_IS_STATUS_ERROR(status))
299 mlo_clear_link_bmap(psoc, vdev_id);
300
301 return status;
302 }
303
304 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
305 static struct mlo_link_info *
mlo_mgr_get_link_info_by_self_addr(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * self_addr)306 mlo_mgr_get_link_info_by_self_addr(struct wlan_objmgr_vdev *vdev,
307 struct qdf_mac_addr *self_addr)
308 {
309 uint8_t iter;
310 struct mlo_link_info *mlo_link;
311
312 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx ||
313 !self_addr || qdf_is_macaddr_zero(self_addr))
314 return NULL;
315
316 for (iter = 0; iter < WLAN_MAX_ML_BSS_LINKS; iter++) {
317 mlo_link = &vdev->mlo_dev_ctx->link_ctx->links_info[iter];
318
319 if (qdf_is_macaddr_equal(&mlo_link->link_addr, self_addr))
320 return mlo_link;
321 }
322
323 return NULL;
324 }
325
326 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
mlo_mgr_num_roam_links(struct wlan_objmgr_vdev * vdev)327 uint8_t mlo_mgr_num_roam_links(struct wlan_objmgr_vdev *vdev)
328 {
329 struct wlan_cm_connect_resp *reassoc_rsp;
330
331 if (!vdev->mlo_dev_ctx)
332 return 1;
333
334 if (!vdev->mlo_dev_ctx->sta_ctx)
335 return 0;
336
337 reassoc_rsp = vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp;
338 if (!reassoc_rsp || !reassoc_rsp->roaming_info)
339 return 0;
340
341 return reassoc_rsp->roaming_info->num_setup_links;
342 }
343 #endif
344
mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev * vdev,struct ml_setup_link_param * src_link_info,struct wlan_channel * channel)345 void mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev *vdev,
346 struct ml_setup_link_param *src_link_info,
347 struct wlan_channel *channel)
348 {
349 struct mlo_link_info *link_info;
350
351 if (!src_link_info)
352 return;
353
354 link_info = mlo_mgr_get_link_info_by_self_addr(vdev,
355 &src_link_info->self_link_addr);
356 if (!link_info) {
357 mlo_err("No link info found for vdev %d with " QDF_MAC_ADDR_FMT,
358 src_link_info->vdev_id,
359 QDF_MAC_ADDR_REF(src_link_info->self_link_addr.bytes));
360 QDF_BUG(0);
361 return;
362 }
363
364 if (link_info->vdev_id != src_link_info->vdev_id) {
365 mlo_err("Host(%d)-FW(%d) VDEV-MAC addr mismatch",
366 link_info->vdev_id, src_link_info->vdev_id);
367 QDF_BUG(0);
368 return;
369 }
370
371 link_info->link_id = src_link_info->link_id;
372 qdf_copy_macaddr(&link_info->ap_link_addr, &src_link_info->link_addr);
373 qdf_mem_copy(link_info->link_chan_info, channel, sizeof(*channel));
374
375 mlo_debug("link_id: %d, vdev_id:%d freq:%d ap_link_addr: "QDF_MAC_ADDR_FMT", self_link_addr: "QDF_MAC_ADDR_FMT,
376 link_info->link_id, link_info->vdev_id,
377 link_info->link_chan_info->ch_freq,
378 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes),
379 QDF_MAC_ADDR_REF(link_info->link_addr.bytes));
380 }
381
mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev * vdev,void * event,uint32_t event_data_len)382 QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev,
383 void *event, uint32_t event_data_len)
384 {
385 QDF_STATUS status;
386 struct roam_offload_synch_ind *sync_ind;
387 struct wlan_objmgr_psoc *psoc;
388 struct wlan_objmgr_vdev *link_vdev = NULL;
389 uint8_t i;
390 uint8_t vdev_id;
391
392 sync_ind = (struct roam_offload_synch_ind *)event;
393 vdev_id = wlan_vdev_get_id(vdev);
394 psoc = wlan_vdev_get_psoc(vdev);
395
396 /* Clean up link vdev in following cases
397 * 1. When roamed to legacy, num_setup_links = 0
398 * 2. When roamed to single link, num_setup_links = 1
399 * 3. Roamed to AP with auth_status = ROAMED_AUTH_STATUS_CONNECTED
400 */
401 if (sync_ind->num_setup_links < 2 ||
402 sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) {
403 mlme_debug("Roam auth status %d", sync_ind->auth_status);
404 mlo_update_vdev_after_roam(psoc, vdev_id,
405 sync_ind->num_setup_links);
406 }
407
408 /* If EAPOL is offloaded to supplicant, link vdev/s are not up
409 * at FW, in that case complete roam sync on assoc vdev
410 * link vdev will be initialized after set key is complete.
411 */
412 if (sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED)
413 return QDF_STATUS_SUCCESS;
414
415 for (i = 0; i < sync_ind->num_setup_links; i++) {
416 if (vdev_id == sync_ind->ml_link[i].vdev_id)
417 continue;
418
419 /* Standby Link */
420 if (sync_ind->ml_link[i].vdev_id == WLAN_INVALID_VDEV_ID)
421 continue;
422
423 link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
424 sync_ind->ml_link[i].vdev_id,
425 WLAN_MLME_SB_ID);
426 if (!link_vdev) {
427 mlo_err("Link vdev:%d is null",
428 sync_ind->ml_link[i].vdev_id);
429 return QDF_STATUS_E_FAILURE;
430 }
431
432 if (mlo_check_connect_req_bmap(link_vdev)) {
433 struct qdf_mac_addr *vdev_link_addr;
434
435 mlo_update_connect_req_links(link_vdev, false);
436
437 vdev_link_addr = &sync_ind->ml_link[i].self_link_addr;
438 if (!qdf_is_macaddr_zero(vdev_link_addr) &&
439 !qdf_is_macaddr_broadcast(vdev_link_addr)) {
440 wlan_vdev_mlme_set_macaddr(link_vdev,
441 vdev_link_addr->bytes);
442 wlan_vdev_mlme_set_linkaddr(link_vdev,
443 vdev_link_addr->bytes);
444 }
445
446 status = cm_fw_roam_sync_req(psoc,
447 sync_ind->ml_link[i].vdev_id,
448 event, event_data_len);
449 if (QDF_IS_STATUS_ERROR(status)) {
450 mlo_clear_connect_req_links_bmap(link_vdev);
451 mlo_roam_abort_req(psoc, event,
452 sync_ind->ml_link[i].vdev_id);
453 wlan_objmgr_vdev_release_ref(link_vdev,
454 WLAN_MLME_SB_ID);
455 return QDF_STATUS_E_FAILURE;
456 }
457 }
458 wlan_objmgr_vdev_release_ref(link_vdev,
459 WLAN_MLME_SB_ID);
460 }
461
462 return QDF_STATUS_SUCCESS;
463 }
464 #endif
465
466 void
mlo_fw_ho_fail_req(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,struct qdf_mac_addr bssid)467 mlo_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc,
468 uint8_t vdev_id, struct qdf_mac_addr bssid)
469 {
470 struct wlan_objmgr_vdev *vdev;
471 struct wlan_mlo_dev_context *mlo_dev_ctx;
472 uint8_t i;
473
474 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
475 vdev_id,
476 WLAN_MLME_SB_ID);
477
478 if (!vdev) {
479 mlo_err("vdev is null");
480 return;
481 }
482
483 if (!vdev->mlo_dev_ctx)
484 goto end;
485
486 mlo_dev_ctx = vdev->mlo_dev_ctx;
487
488 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
489 if (!mlo_dev_ctx->wlan_vdev_list[i] ||
490 mlo_dev_ctx->wlan_vdev_list[i] == vdev)
491 continue;
492 cm_fw_ho_fail_req(psoc,
493 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]),
494 bssid);
495 }
496
497 end:
498 cm_fw_ho_fail_req(psoc, vdev_id, bssid);
499 wlan_objmgr_vdev_release_ref(vdev,
500 WLAN_MLME_SB_ID);
501 }
502
503 QDF_STATUS
mlo_get_sta_link_mac_addr(uint8_t vdev_id,struct roam_offload_synch_ind * sync_ind,struct qdf_mac_addr * link_mac_addr)504 mlo_get_sta_link_mac_addr(uint8_t vdev_id,
505 struct roam_offload_synch_ind *sync_ind,
506 struct qdf_mac_addr *link_mac_addr)
507 {
508 QDF_STATUS status = QDF_STATUS_SUCCESS;
509 uint8_t i;
510
511 if (!sync_ind || !sync_ind->num_setup_links)
512 return QDF_STATUS_E_FAILURE;
513
514 for (i = 0; i < sync_ind->num_setup_links; i++) {
515 if (sync_ind->ml_link[i].vdev_id == vdev_id) {
516 qdf_copy_macaddr(link_mac_addr,
517 &sync_ind->ml_link[i].link_addr);
518 return status;
519 }
520 }
521
522 if (i == sync_ind->num_setup_links) {
523 mlo_err("Link mac addr not found");
524 status = QDF_STATUS_E_FAILURE;
525 }
526
527 return status;
528 }
529
530 uint32_t
mlo_roam_get_chan_freq(uint8_t vdev_id,struct roam_offload_synch_ind * sync_ind)531 mlo_roam_get_chan_freq(uint8_t vdev_id,
532 struct roam_offload_synch_ind *sync_ind)
533 {
534 uint8_t i;
535
536 if (!sync_ind || !sync_ind->num_setup_links)
537 return 0;
538
539 for (i = 0; i < sync_ind->num_setup_links; i++) {
540 if (sync_ind->ml_link[i].vdev_id == vdev_id)
541 return sync_ind->ml_link[i].channel.mhz;
542 }
543
544 return 0;
545 }
546
547 uint32_t
mlo_roam_get_link_id(uint8_t vdev_id,struct roam_offload_synch_ind * sync_ind)548 mlo_roam_get_link_id(uint8_t vdev_id,
549 struct roam_offload_synch_ind *sync_ind)
550 {
551 uint8_t i;
552
553 if (!sync_ind || !sync_ind->num_setup_links)
554 return 0;
555
556 for (i = 0; i < sync_ind->num_setup_links; i++) {
557 if (sync_ind->ml_link[i].vdev_id == vdev_id)
558 return sync_ind->ml_link[i].link_id;
559 }
560
561 return 0;
562 }
563
is_multi_link_roam(struct roam_offload_synch_ind * sync_ind)564 bool is_multi_link_roam(struct roam_offload_synch_ind *sync_ind)
565 {
566 if (!sync_ind)
567 return false;
568
569 if (sync_ind->num_setup_links)
570 return true;
571
572 return false;
573 }
574
575 uint8_t
mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind * sync_ind)576 mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind *sync_ind)
577 {
578 if (!sync_ind) {
579 mlo_err("Roam Sync ind is null");
580 return WLAN_INVALID_VDEV_ID;
581 }
582
583 return sync_ind->num_setup_links;
584 }
585
586 uint32_t
mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind * sync_ind,uint8_t * link_mac_addr)587 mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind *sync_ind,
588 uint8_t *link_mac_addr)
589 {
590 uint8_t i;
591
592 if (!sync_ind)
593 return 0;
594
595 /* Non-MLO roaming */
596 if (!sync_ind->num_setup_links)
597 return sync_ind->chan_freq;
598
599 if (!link_mac_addr) {
600 mlo_debug("link_mac_addr is NULL");
601 return 0;
602 }
603
604 for (i = 0; i < sync_ind->num_setup_links; i++)
605 if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes,
606 link_mac_addr,
607 QDF_MAC_ADDR_SIZE))
608 return sync_ind->ml_link[i].channel.mhz;
609
610 mlo_debug("Mac address not found in ml_link info" QDF_MAC_ADDR_FMT,
611 QDF_MAC_ADDR_REF(link_mac_addr));
612
613 return 0;
614 }
615
616 QDF_STATUS
mlo_roam_get_link_id_from_mac_addr(struct roam_offload_synch_ind * sync_ind,uint8_t * link_mac_addr,uint32_t * link_id)617 mlo_roam_get_link_id_from_mac_addr(struct roam_offload_synch_ind *sync_ind,
618 uint8_t *link_mac_addr, uint32_t *link_id)
619 {
620 uint8_t i;
621
622 if (!sync_ind || !sync_ind->num_setup_links || !link_mac_addr)
623 return QDF_STATUS_E_INVAL;
624
625 for (i = 0; i < sync_ind->num_setup_links; i++)
626 if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes,
627 link_mac_addr,
628 QDF_MAC_ADDR_SIZE)) {
629 *link_id = sync_ind->ml_link[i].link_id;
630 return QDF_STATUS_SUCCESS;
631 }
632
633 return QDF_STATUS_E_INVAL;
634 }
635
mlo_enable_rso(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * rsp)636 QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev,
637 struct wlan_objmgr_vdev *vdev,
638 struct wlan_cm_connect_resp *rsp)
639 {
640 struct wlan_objmgr_vdev *assoc_vdev;
641 uint8_t num_partner_links;
642
643 if (!rsp) {
644 mlo_err("Connect resp is null");
645 return QDF_STATUS_E_NULL_VALUE;
646 }
647
648 num_partner_links = rsp->ml_parnter_info.num_partner_links;
649
650 if (num_partner_links &&
651 (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) ||
652 !mlo_check_if_all_links_up(vdev)))
653 return QDF_STATUS_SUCCESS;
654
655 assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
656 if (!assoc_vdev) {
657 mlo_err("Assoc vdev is null");
658 return QDF_STATUS_E_NULL_VALUE;
659 }
660 cm_roam_start_init_on_connect(pdev, wlan_vdev_get_id(assoc_vdev));
661
662 return QDF_STATUS_SUCCESS;
663 }
664
665 void
mlo_roam_copy_partner_info(struct mlo_partner_info * partner_info,struct roam_offload_synch_ind * sync_ind,uint8_t skip_vdev_id,bool fill_all_links)666 mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info,
667 struct roam_offload_synch_ind *sync_ind,
668 uint8_t skip_vdev_id, bool fill_all_links)
669 {
670 uint8_t i, j;
671 struct mlo_link_info *link;
672
673 if (!sync_ind)
674 return;
675
676 for (i = 0, j = 0; i < sync_ind->num_setup_links; i++) {
677 if (!fill_all_links &&
678 sync_ind->ml_link[i].vdev_id == skip_vdev_id)
679 continue;
680
681 link = &partner_info->partner_link_info[j];
682 link->link_id = sync_ind->ml_link[i].link_id;
683 link->vdev_id = sync_ind->ml_link[i].vdev_id;
684
685 qdf_copy_macaddr(&link->link_addr,
686 &sync_ind->ml_link[i].link_addr);
687 link->chan_freq = sync_ind->ml_link[i].channel.mhz;
688 mlo_debug("vdev_id %d link_id %d freq %d bssid" QDF_MAC_ADDR_FMT,
689 link->vdev_id, link->link_id, link->chan_freq,
690 QDF_MAC_ADDR_REF(link->link_addr.bytes));
691 j++;
692 }
693 partner_info->num_partner_links = j;
694 mlo_debug("vdev_to_skip:%d num_setup_links %d fill_all_links:%d",
695 skip_vdev_id, partner_info->num_partner_links,
696 fill_all_links);
697 }
698
mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev * vdev,struct roam_offload_synch_ind * sync_ind)699 void mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev *vdev,
700 struct roam_offload_synch_ind *sync_ind)
701 {
702 uint8_t i;
703 struct wlan_mlo_dev_context *mlo_dev_ctx;
704
705 if (!vdev) {
706 mlo_err("vdev is NULL");
707 return;
708 }
709
710 mlo_dev_ctx = vdev->mlo_dev_ctx;
711 if (!mlo_dev_ctx) {
712 mlo_err("ML dev ctx is NULL");
713 return;
714 }
715
716 mlo_clear_cu_bpcc(vdev);
717 for (i = 0; i < sync_ind->num_setup_links; i++)
718 mlo_init_cu_bpcc(mlo_dev_ctx, sync_ind->ml_link[i].vdev_id);
719
720 mlo_debug("update cu info from roam sync");
721 }
722
723 void
mlo_roam_update_connected_links(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * connect_rsp)724 mlo_roam_update_connected_links(struct wlan_objmgr_vdev *vdev,
725 struct wlan_cm_connect_resp *connect_rsp)
726 {
727 mlo_clear_connected_links_bmap(vdev);
728 if (mlo_get_single_link_ml_roaming(wlan_vdev_get_psoc(vdev),
729 wlan_vdev_get_id(vdev)))
730 mlo_update_connected_links(vdev, 1);
731 else
732 mlo_update_connected_links_bmap(vdev->mlo_dev_ctx,
733 connect_rsp->ml_parnter_info);
734 }
735
736 QDF_STATUS
wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc * psoc,uint8_t * event,uint8_t vdev_id)737 wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc *psoc,
738 uint8_t *event, uint8_t vdev_id)
739 {
740 uint8_t i;
741 QDF_STATUS status;
742 struct roam_offload_synch_ind *sync_ind = NULL;
743
744 sync_ind = (struct roam_offload_synch_ind *)event;
745
746 if (!sync_ind) {
747 mlo_err("Roam Sync ind ptr is NULL");
748 return QDF_STATUS_E_NULL_VALUE;
749 }
750
751 for (i = 0; i < sync_ind->num_setup_links; i++) {
752 if (sync_ind->ml_link[i].vdev_id != vdev_id) {
753 status = cm_fw_roam_abort_req(psoc,
754 sync_ind->ml_link[i].vdev_id);
755 if (QDF_IS_STATUS_ERROR(status)) {
756 mlo_err("LFR3: Fail to abort roam on vdev: %u",
757 sync_ind->ml_link[i].vdev_id);
758 }
759 }
760 }
761
762 return QDF_STATUS_SUCCESS;
763 }
764
765 void
mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,bool is_single_link_ml_roaming)766 mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc,
767 uint8_t vdev_id,
768 bool is_single_link_ml_roaming)
769 {
770 struct wlan_objmgr_vdev *vdev;
771
772 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
773 vdev_id,
774 WLAN_MLME_SB_ID);
775 if (!vdev) {
776 mlo_err("VDEV is null");
777 return;
778 }
779
780 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
781 mlme_set_single_link_mlo_roaming(vdev,
782 is_single_link_ml_roaming);
783
784 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
785 }
786
787 bool
mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)788 mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc,
789 uint8_t vdev_id)
790 {
791 bool is_single_link_ml_roaming = false;
792 struct wlan_objmgr_vdev *vdev;
793
794 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
795 vdev_id,
796 WLAN_MLME_SB_ID);
797 if (!vdev) {
798 mlo_err("VDEV is null");
799 return is_single_link_ml_roaming;
800 }
801
802 is_single_link_ml_roaming = mlme_get_single_link_mlo_roaming(vdev);
803 mlo_debug("MLO:is_single_link_ml_roaming %d",
804 is_single_link_ml_roaming);
805 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
806
807 return is_single_link_ml_roaming;
808 }
809
810 QDF_STATUS
mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id,struct roam_offload_synch_ind * sync_ind,struct qdf_mac_addr * bssid,wmi_channel * chan)811 mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id,
812 struct roam_offload_synch_ind *sync_ind,
813 struct qdf_mac_addr *bssid,
814 wmi_channel *chan)
815 {
816 QDF_STATUS status = QDF_STATUS_SUCCESS;
817 uint8_t i;
818
819 if (!sync_ind || !sync_ind->num_setup_links)
820 return QDF_STATUS_E_FAILURE;
821
822 for (i = 0; i < sync_ind->num_setup_links; i++) {
823 if (vdev_id == sync_ind->ml_link[i].vdev_id) {
824 qdf_mem_copy(chan, &sync_ind->ml_link[i].channel,
825 sizeof(wmi_channel));
826 qdf_copy_macaddr(bssid,
827 &sync_ind->ml_link[i].link_addr);
828 return status;
829 }
830 }
831
832 if (i == sync_ind->num_setup_links) {
833 mlo_err("roam sync info not found for vdev id %d", vdev_id);
834 status = QDF_STATUS_E_FAILURE;
835 }
836
837 return status;
838 }
839
840 bool
mlo_check_if_all_links_up(struct wlan_objmgr_vdev * vdev)841 mlo_check_if_all_links_up(struct wlan_objmgr_vdev *vdev)
842 {
843 struct wlan_mlo_dev_context *mlo_dev_ctx;
844 struct wlan_mlo_sta *sta_ctx;
845 uint8_t i;
846
847 if (!vdev || !vdev->mlo_dev_ctx) {
848 mlo_err("Vdev is null");
849 return false;
850 }
851
852 mlo_dev_ctx = vdev->mlo_dev_ctx;
853 if (!mlo_dev_ctx->sta_ctx) {
854 mlo_err("mlo sta ctx is null");
855 return false;
856 }
857
858 sta_ctx = mlo_dev_ctx->sta_ctx;
859 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
860 if (!mlo_dev_ctx->wlan_vdev_list[i])
861 continue;
862
863 if (qdf_test_bit(i, sta_ctx->wlan_connected_links) &&
864 !wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) {
865 mlo_debug("Vdev id %d is not in connected state",
866 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]));
867 return false;
868 }
869 }
870
871 if (i == WLAN_UMAC_MLO_MAX_VDEVS) {
872 mlo_debug("all links are up");
873 return true;
874 }
875
876 return false;
877 }
878
879 bool
mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev * vdev)880 mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev *vdev)
881 {
882 struct wlan_mlo_dev_context *mlo_dev_ctx;
883 struct wlan_mlo_sta *sta_ctx;
884 uint8_t i;
885
886 if (!vdev || !vdev->mlo_dev_ctx) {
887 mlo_err("Vdev is null");
888 return false;
889 }
890
891 if (QDF_IS_STATUS_ERROR(wlan_vdev_is_up(vdev))) {
892 mlo_debug("Vdev id %d is not in up state",
893 wlan_vdev_get_id(vdev));
894 return false;
895 }
896
897 mlo_dev_ctx = vdev->mlo_dev_ctx;
898 if (!mlo_dev_ctx->sta_ctx) {
899 mlo_err("mlo sta ctx is null");
900 return false;
901 }
902 sta_ctx = mlo_dev_ctx->sta_ctx;
903 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
904 if (!mlo_dev_ctx->wlan_vdev_list[i])
905 continue;
906
907 if ((qdf_test_bit(i, sta_ctx->wlan_connected_links) ||
908 qdf_test_bit(i, sta_ctx->wlan_connect_req_links)) &&
909 !QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(mlo_dev_ctx->wlan_vdev_list[i]))) {
910 mlo_debug("Vdev id %d is not in up state",
911 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]));
912 return false;
913 }
914 }
915
916 if (i == WLAN_UMAC_MLO_MAX_VDEVS) {
917 mlo_debug("all links are up");
918 return true;
919 }
920
921 return false;
922 }
923
924 void
mlo_roam_set_link_id(struct wlan_objmgr_vdev * vdev,struct roam_offload_synch_ind * sync_ind)925 mlo_roam_set_link_id(struct wlan_objmgr_vdev *vdev,
926 struct roam_offload_synch_ind *sync_ind)
927 {
928 uint8_t i;
929 uint8_t j;
930 struct wlan_mlo_dev_context *mlo_dev_ctx;
931
932 if (!vdev || !sync_ind || !vdev->mlo_dev_ctx) {
933 mlo_debug("Invalid input");
934 return;
935 }
936
937 mlo_dev_ctx = vdev->mlo_dev_ctx;
938 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
939 vdev = mlo_dev_ctx->wlan_vdev_list[i];
940 if (!vdev)
941 continue;
942
943 wlan_vdev_set_link_id(vdev, WLAN_LINK_ID_INVALID);
944 for (j = 0; j < sync_ind->num_setup_links; j++) {
945 if (sync_ind->ml_link[j].vdev_id ==
946 wlan_vdev_get_id(vdev)) {
947 wlan_vdev_set_link_id(
948 vdev, sync_ind->ml_link[j].link_id);
949 mlme_debug("Set link for vdev id %d link id %d",
950 wlan_vdev_get_id(vdev),
951 sync_ind->ml_link[j].link_id);
952 }
953 }
954 }
955 }
956
957 QDF_STATUS
mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * link_mac_addr)958 mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
959 struct qdf_mac_addr *link_mac_addr)
960 {
961 uint8_t i;
962 struct wlan_mlo_sta *sta_ctx;
963 struct wlan_cm_connect_resp *rsp;
964 struct mlo_partner_info parnter_info;
965 uint8_t vdev_id;
966
967 if (!vdev)
968 return QDF_STATUS_E_NULL_VALUE;
969
970 vdev_id = wlan_vdev_get_id(vdev);
971
972 if (!vdev->mlo_dev_ctx) {
973 mlo_err("mlo dev ctx is null, vdev id %d", vdev_id);
974 return QDF_STATUS_E_NULL_VALUE;
975 }
976
977 sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
978 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
979 !sta_ctx->copied_reassoc_rsp->roaming_info) {
980 mlo_debug("sta ctx or copied reassoc rsp is null for vdev id %d", vdev_id);
981 return QDF_STATUS_E_NULL_VALUE;
982 }
983
984 rsp = sta_ctx->copied_reassoc_rsp;
985 if (rsp->roaming_info->auth_status != ROAM_AUTH_STATUS_CONNECTED) {
986 mlo_debug("Roam auth status is not connected");
987 return QDF_STATUS_E_FAILURE;
988 }
989
990 parnter_info = rsp->ml_parnter_info;
991 for (i = 0; i < parnter_info.num_partner_links; i++) {
992 if (parnter_info.partner_link_info[i].vdev_id == vdev_id) {
993 qdf_copy_macaddr(link_mac_addr,
994 &parnter_info.partner_link_info[i].link_addr);
995 return QDF_STATUS_SUCCESS;
996 }
997 }
998
999 if (i == parnter_info.num_partner_links) {
1000 mlo_debug("Link mac addr not found");
1001 return QDF_STATUS_E_FAILURE;
1002 }
1003
1004 return QDF_STATUS_SUCCESS;
1005 }
1006
1007 QDF_STATUS
mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * reassoc_rsp)1008 mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
1009 struct wlan_cm_connect_resp *reassoc_rsp)
1010 {
1011 struct wlan_mlo_dev_context *mlo_dev_ctx;
1012 struct wlan_mlo_sta *sta_ctx;
1013 struct wlan_connect_rsp_ies *connect_ies;
1014
1015 if (!vdev)
1016 return QDF_STATUS_E_NULL_VALUE;
1017
1018 if (!reassoc_rsp)
1019 return QDF_STATUS_E_NULL_VALUE;
1020
1021 /* Store reassoc rsp only if roamed to 2 link AP */
1022 if (reassoc_rsp->ml_parnter_info.num_partner_links < 2)
1023 return QDF_STATUS_E_INVAL;
1024
1025 mlo_dev_ctx = vdev->mlo_dev_ctx;
1026 if (!mlo_dev_ctx)
1027 return QDF_STATUS_E_NULL_VALUE;
1028
1029 sta_ctx = mlo_dev_ctx->sta_ctx;
1030 if (!sta_ctx)
1031 return QDF_STATUS_E_NULL_VALUE;
1032
1033 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1034 /* Free assoc rsp, so that reassoc rsp can be used during
1035 * reassociation.
1036 */
1037 if (sta_ctx->assoc_rsp.ptr) {
1038 qdf_mem_free(sta_ctx->assoc_rsp.ptr);
1039 sta_ctx->assoc_rsp.ptr = NULL;
1040 sta_ctx->assoc_rsp.len = 0;
1041 }
1042
1043 sta_ctx->ml_partner_info = reassoc_rsp->ml_parnter_info;
1044
1045 sta_ctx->copied_reassoc_rsp = qdf_mem_malloc(
1046 sizeof(struct wlan_cm_connect_resp));
1047 if (!sta_ctx->copied_reassoc_rsp)
1048 return QDF_STATUS_E_NOMEM;
1049
1050 qdf_mem_copy(sta_ctx->copied_reassoc_rsp, reassoc_rsp,
1051 sizeof(struct wlan_cm_connect_resp));
1052
1053 sta_ctx->copied_reassoc_rsp->roaming_info = qdf_mem_malloc(
1054 sizeof(struct wlan_roam_sync_info));
1055
1056 if (!sta_ctx->copied_reassoc_rsp->roaming_info) {
1057 qdf_mem_free(sta_ctx->copied_reassoc_rsp);
1058 sta_ctx->copied_reassoc_rsp = NULL;
1059 return QDF_STATUS_E_NOMEM;
1060 }
1061
1062 qdf_mem_copy(sta_ctx->copied_reassoc_rsp->roaming_info,
1063 reassoc_rsp->roaming_info,
1064 sizeof(struct wlan_roam_sync_info));
1065
1066 connect_ies = &sta_ctx->copied_reassoc_rsp->connect_ies;
1067
1068 connect_ies->assoc_rsp.len =
1069 reassoc_rsp->connect_ies.assoc_rsp.len;
1070
1071 connect_ies->assoc_rsp.ptr = qdf_mem_malloc(
1072 connect_ies->assoc_rsp.len);
1073
1074 if (!connect_ies->assoc_rsp.ptr) {
1075 qdf_mem_free(sta_ctx->copied_reassoc_rsp->roaming_info);
1076 sta_ctx->copied_reassoc_rsp->roaming_info = NULL;
1077 qdf_mem_free(sta_ctx->copied_reassoc_rsp);
1078 sta_ctx->copied_reassoc_rsp = NULL;
1079 return QDF_STATUS_E_NOMEM;
1080 }
1081
1082 qdf_mem_copy(connect_ies->assoc_rsp.ptr,
1083 reassoc_rsp->connect_ies.assoc_rsp.ptr,
1084 reassoc_rsp->connect_ies.assoc_rsp.len);
1085
1086 connect_ies->assoc_req.len = 0;
1087 connect_ies->assoc_req.ptr = NULL;
1088 connect_ies->bcn_probe_rsp.len = 0;
1089 connect_ies->bcn_probe_rsp.ptr = NULL;
1090 connect_ies->link_bcn_probe_rsp.len = 0;
1091 connect_ies->link_bcn_probe_rsp.ptr = NULL;
1092 connect_ies->fils_ie = NULL;
1093
1094 mlo_debug("Copied reassoc response for vdev: %d len: %d",
1095 wlan_vdev_get_id(vdev), connect_ies->assoc_rsp.len);
1096
1097 return QDF_STATUS_SUCCESS;
1098 }
1099
1100 static bool
mlo_roam_is_internal_disconnect(struct wlan_objmgr_vdev * link_vdev)1101 mlo_roam_is_internal_disconnect(struct wlan_objmgr_vdev *link_vdev)
1102 {
1103 struct wlan_cm_vdev_discon_req *disconn_req;
1104
1105 if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) &&
1106 wlan_cm_is_vdev_disconnecting(link_vdev)) {
1107 mlo_debug("Disconnect is ongoing on vdev %d",
1108 wlan_vdev_get_id(link_vdev));
1109
1110 disconn_req = qdf_mem_malloc(sizeof(*disconn_req));
1111 if (!disconn_req) {
1112 mlme_err("Malloc failed for disconnect req");
1113 return false;
1114 }
1115
1116 if (!wlan_cm_get_active_disconnect_req(link_vdev,
1117 disconn_req)) {
1118 mlme_err("vdev: %d: Active disconnect not found",
1119 wlan_vdev_get_id(link_vdev));
1120 qdf_mem_free(disconn_req);
1121 return false;
1122 }
1123
1124 mlo_debug("Disconnect source %d", disconn_req->req.source);
1125
1126 if (disconn_req->req.source == CM_MLO_ROAM_INTERNAL_DISCONNECT) {
1127 qdf_mem_free(disconn_req);
1128 return true;
1129 }
1130
1131 qdf_mem_free(disconn_req);
1132 }
1133 /* Disconnect is not ongoing */
1134 return true;
1135 }
1136
1137 static QDF_STATUS
mlo_roam_validate_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_vdev * link_vdev,struct wlan_cm_connect_resp * rsp)1138 mlo_roam_validate_req(struct wlan_objmgr_vdev *vdev,
1139 struct wlan_objmgr_vdev *link_vdev,
1140 struct wlan_cm_connect_resp *rsp)
1141 {
1142 struct wlan_mlo_dev_context *mlo_dev_ctx;
1143 struct wlan_mlo_sta *sta_ctx;
1144
1145 if (!vdev) {
1146 mlo_debug_rl("vdev is NULL");
1147 return QDF_STATUS_E_NULL_VALUE;
1148 }
1149
1150 mlo_dev_ctx = vdev->mlo_dev_ctx;
1151 if (!mlo_dev_ctx) {
1152 mlo_debug_rl("mlo_dev_ctx is NULL");
1153 return QDF_STATUS_E_NULL_VALUE;
1154 }
1155
1156 sta_ctx = mlo_dev_ctx->sta_ctx;
1157 if (sta_ctx && sta_ctx->disconn_req) {
1158 mlo_debug("Handle pending disconnect for vdev %d",
1159 wlan_vdev_get_id(vdev));
1160 mlo_handle_pending_disconnect(vdev);
1161 return QDF_STATUS_E_FAILURE;
1162 }
1163
1164 if (wlan_cm_is_vdev_disconnected(vdev) ||
1165 (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) &&
1166 (wlan_cm_is_vdev_connecting(link_vdev) ||
1167 !mlo_roam_is_internal_disconnect(link_vdev)))) {
1168 if (sta_ctx) {
1169 if (sta_ctx->copied_reassoc_rsp) {
1170 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1171 sta_ctx->copied_reassoc_rsp = NULL;
1172 }
1173 copied_conn_req_lock_acquire(sta_ctx);
1174 if (sta_ctx->copied_conn_req) {
1175 wlan_cm_free_connect_req(sta_ctx->copied_conn_req);
1176 sta_ctx->copied_conn_req = NULL;
1177 }
1178 copied_conn_req_lock_release(sta_ctx);
1179 }
1180 }
1181
1182 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1183 mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev));
1184 if (wlan_cm_is_vdev_disconnected(vdev)) {
1185 mlo_handle_sta_link_connect_failure(vdev, rsp);
1186 return QDF_STATUS_E_FAILURE;
1187 } else if (!wlan_cm_is_vdev_connected(vdev)) {
1188 /* If vdev is not in disconnected or connected state,
1189 * then the event is received due to connect req being
1190 * flushed. Hence, ignore this event
1191 */
1192 if (sta_ctx && sta_ctx->copied_reassoc_rsp) {
1193 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1194 sta_ctx->copied_reassoc_rsp = NULL;
1195 }
1196 return QDF_STATUS_E_FAILURE;
1197 }
1198 }
1199
1200 if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) &&
1201 (wlan_cm_is_vdev_connecting(link_vdev) ||
1202 !mlo_roam_is_internal_disconnect(link_vdev))) {
1203 return QDF_STATUS_E_FAILURE;
1204 }
1205
1206 if (sta_ctx && !wlan_vdev_mlme_is_mlo_link_vdev(vdev)) {
1207 if (sta_ctx->assoc_rsp.ptr) {
1208 qdf_mem_free(sta_ctx->assoc_rsp.ptr);
1209 sta_ctx->assoc_rsp.ptr = NULL;
1210 }
1211 sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len;
1212 sta_ctx->assoc_rsp.ptr =
1213 qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len);
1214 if (!sta_ctx->assoc_rsp.ptr)
1215 return QDF_STATUS_E_FAILURE;
1216 if (rsp->connect_ies.assoc_rsp.ptr)
1217 qdf_mem_copy(sta_ctx->assoc_rsp.ptr,
1218 rsp->connect_ies.assoc_rsp.ptr,
1219 rsp->connect_ies.assoc_rsp.len);
1220 /* Update connected_links_bmap for all vdev taking
1221 * part in association
1222 */
1223 mlo_update_connected_links(vdev, 1);
1224 mlo_update_connected_links_bmap(mlo_dev_ctx,
1225 rsp->ml_parnter_info);
1226 }
1227
1228 return QDF_STATUS_SUCCESS;
1229 }
1230
1231 static QDF_STATUS
mlo_roam_prepare_and_send_link_connect_req(struct wlan_objmgr_vdev * assoc_vdev,struct wlan_objmgr_vdev * link_vdev,struct wlan_cm_connect_resp * rsp,struct qdf_mac_addr * link_addr,uint16_t chan_freq)1232 mlo_roam_prepare_and_send_link_connect_req(struct wlan_objmgr_vdev *assoc_vdev,
1233 struct wlan_objmgr_vdev *link_vdev,
1234 struct wlan_cm_connect_resp *rsp,
1235 struct qdf_mac_addr *link_addr,
1236 uint16_t chan_freq)
1237 {
1238 struct wlan_mlo_sta *sta_ctx;
1239 struct wlan_cm_connect_req req = {0};
1240 struct wlan_ssid ssid = {0};
1241 struct rso_config *rso_cfg;
1242 QDF_STATUS status = QDF_STATUS_SUCCESS;
1243
1244 if (!assoc_vdev->mlo_dev_ctx || !assoc_vdev->mlo_dev_ctx->sta_ctx)
1245 return QDF_STATUS_E_FAILURE;
1246
1247 sta_ctx = assoc_vdev->mlo_dev_ctx->sta_ctx;
1248
1249 wlan_vdev_mlme_get_ssid(assoc_vdev, ssid.ssid,
1250 &ssid.length);
1251
1252 req.vdev_id = wlan_vdev_get_id(link_vdev);
1253 req.source = CM_MLO_LINK_VDEV_CONNECT;
1254 req.chan_freq = chan_freq;
1255 qdf_mem_copy(&req.bssid.bytes, link_addr->bytes, QDF_MAC_ADDR_SIZE);
1256
1257 req.ssid.length = ssid.length;
1258 qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length);
1259 qdf_copy_macaddr(&req.mld_addr, &rsp->mld_addr);
1260
1261 req.ml_parnter_info = rsp->ml_parnter_info;
1262
1263 rso_cfg = wlan_cm_get_rso_config(assoc_vdev);
1264 if (rso_cfg) {
1265 req.crypto.rsn_caps = rso_cfg->orig_sec_info.rsn_caps;
1266 req.crypto.auth_type = rso_cfg->orig_sec_info.authmodeset;
1267 req.crypto.ciphers_pairwise =
1268 rso_cfg->orig_sec_info.ucastcipherset;
1269 req.crypto.group_cipher = rso_cfg->orig_sec_info.mcastcipherset;
1270 req.crypto.mgmt_ciphers = rso_cfg->orig_sec_info.mgmtcipherset;
1271 req.crypto.akm_suites = rso_cfg->orig_sec_info.key_mgmt;
1272 req.assoc_ie.len = rso_cfg->assoc_ie.len;
1273
1274 req.assoc_ie.ptr = qdf_mem_malloc(req.assoc_ie.len);
1275 if (!req.assoc_ie.ptr)
1276 return QDF_STATUS_E_NOMEM;
1277
1278 if (rso_cfg->assoc_ie.len)
1279 qdf_mem_copy(req.assoc_ie.ptr, rso_cfg->assoc_ie.ptr,
1280 rso_cfg->assoc_ie.len);
1281 }
1282
1283 mlme_cm_osif_roam_get_scan_params(assoc_vdev, &req.scan_ie,
1284 &req.dot11mode_filter);
1285
1286 mlme_info("vdev:%d Connecting to " QDF_SSID_FMT " link_addr: " QDF_MAC_ADDR_FMT " freq %d rsn_caps:0x%x auth_type:0x%x pairwise:0x%x grp:0x%x mcast:0x%x akms:0x%x assoc_ie_len:%d f_rsne:%d is_wps:%d dot11_filter:%d",
1287 req.vdev_id, QDF_SSID_REF(req.ssid.length, req.ssid.ssid),
1288 QDF_MAC_ADDR_REF(link_addr->bytes),
1289 req.chan_freq, req.crypto.rsn_caps, req.crypto.auth_type,
1290 req.crypto.ciphers_pairwise, req.crypto.group_cipher,
1291 req.crypto.mgmt_ciphers, req.crypto.akm_suites,
1292 req.assoc_ie.len, req.force_rsne_override,
1293 req.is_wps_connection, req.dot11mode_filter);
1294
1295 copied_conn_req_lock_acquire(sta_ctx);
1296 if (!sta_ctx->copied_conn_req)
1297 sta_ctx->copied_conn_req =
1298 qdf_mem_malloc(sizeof(struct wlan_cm_connect_req));
1299 else
1300 wlan_cm_free_connect_req_param(sta_ctx->copied_conn_req);
1301
1302 if (!sta_ctx->copied_conn_req) {
1303 mlo_err("MLO_ROAM: vdev:%d Failed to allocate connect req",
1304 req.vdev_id);
1305 copied_conn_req_lock_release(sta_ctx);
1306 status = QDF_STATUS_E_NOMEM;
1307 goto err;
1308 }
1309
1310 qdf_mem_copy(sta_ctx->copied_conn_req, &req,
1311 sizeof(struct wlan_cm_connect_req));
1312 mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req, &req);
1313 copied_conn_req_lock_release(sta_ctx);
1314
1315 status = mlo_roam_validate_req(assoc_vdev, link_vdev, rsp);
1316 if (QDF_IS_STATUS_ERROR(status))
1317 goto err;
1318
1319 status = wlan_cm_start_connect(link_vdev, &req);
1320 if (QDF_IS_STATUS_ERROR(status))
1321 goto err;
1322
1323 mlo_update_connected_links(link_vdev, 1);
1324 err:
1325 qdf_mem_free(req.assoc_ie.ptr);
1326
1327 return status;
1328 }
1329
mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev * vdev)1330 void mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev *vdev)
1331 {
1332 struct wlan_mlo_sta *sta_ctx;
1333
1334 if (!vdev)
1335 return;
1336
1337 if (!vdev->mlo_dev_ctx)
1338 return;
1339
1340 sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1341 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
1342 !sta_ctx->copied_reassoc_rsp->roaming_info)
1343 return;
1344
1345 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1346 sta_ctx->copied_reassoc_rsp = NULL;
1347 }
1348
mlo_roam_connect_complete(struct wlan_objmgr_vdev * vdev)1349 void mlo_roam_connect_complete(struct wlan_objmgr_vdev *vdev)
1350 {
1351 struct wlan_mlo_sta *sta_ctx;
1352 uint8_t auth_status;
1353
1354 if (!vdev)
1355 return;
1356
1357 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
1358 return;
1359
1360 if (!vdev->mlo_dev_ctx)
1361 return;
1362
1363 sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1364 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
1365 !sta_ctx->copied_reassoc_rsp->roaming_info)
1366 return;
1367
1368 auth_status = sta_ctx->copied_reassoc_rsp->roaming_info->auth_status;
1369 if (!mlo_check_connect_req_bmap(vdev) &&
1370 auth_status == ROAM_AUTH_STATUS_CONNECTED) {
1371 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1372 sta_ctx->copied_reassoc_rsp = NULL;
1373 }
1374 }
1375
1376 bool
mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)1377 mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1378 {
1379 bool status = false;
1380 struct wlan_mlo_sta *sta_ctx;
1381 struct wlan_cm_connect_resp *rsp;
1382 struct wlan_objmgr_vdev *vdev;
1383
1384 if (!psoc)
1385 return status;
1386
1387 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1388 WLAN_MLME_SB_ID);
1389 if (!vdev)
1390 return status;
1391
1392 if (!vdev->mlo_dev_ctx)
1393 goto end;
1394
1395 sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1396 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp ||
1397 !sta_ctx->copied_reassoc_rsp->roaming_info)
1398 goto end;
1399
1400 rsp = sta_ctx->copied_reassoc_rsp;
1401 if (rsp->roaming_info->auth_status == ROAM_AUTH_STATUS_CONNECTED)
1402 status = true;
1403
1404 end:
1405 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
1406 return status;
1407 }
1408
1409 QDF_STATUS
mlo_roam_link_connect_notify(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)1410 mlo_roam_link_connect_notify(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1411 {
1412 struct wlan_mlo_sta *sta_ctx = NULL;
1413 struct wlan_cm_connect_resp *rsp;
1414 struct wlan_objmgr_vdev *assoc_vdev;
1415 struct wlan_objmgr_vdev *link_vdev = NULL;
1416 struct wlan_objmgr_vdev *vdev;
1417 struct mlo_partner_info partner_info;
1418 QDF_STATUS status = QDF_STATUS_SUCCESS;
1419 uint8_t i;
1420 uint8_t assoc_vdev_id;
1421 uint8_t link_vdev_id;
1422
1423 if (!psoc)
1424 return QDF_STATUS_E_NULL_VALUE;
1425
1426 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1427 WLAN_MLME_SB_ID);
1428 if (!vdev)
1429 return QDF_STATUS_E_NULL_VALUE;
1430
1431 if (!vdev->mlo_dev_ctx) {
1432 mlo_err("mlo dev ctx is null");
1433 status = QDF_STATUS_E_FAILURE;
1434 goto err;
1435 }
1436
1437 sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
1438 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1439 mlo_debug("MLO_ROAM: Ignore if not mlo vdev");
1440 status = QDF_STATUS_E_FAILURE;
1441 goto err;
1442 }
1443
1444 assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
1445 if (!assoc_vdev) {
1446 status = QDF_STATUS_E_NULL_VALUE;
1447 goto err;
1448 }
1449
1450 assoc_vdev_id = wlan_vdev_get_id(assoc_vdev);
1451 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp) {
1452 status = QDF_STATUS_E_NULL_VALUE;
1453 goto err;
1454 }
1455
1456 rsp = sta_ctx->copied_reassoc_rsp;
1457 partner_info = rsp->ml_parnter_info;
1458 mlo_debug("partner links %d", partner_info.num_partner_links);
1459
1460 for (i = 0; i < partner_info.num_partner_links; i++) {
1461 link_vdev_id = partner_info.partner_link_info[i].vdev_id;
1462 if (assoc_vdev_id == link_vdev_id)
1463 continue;
1464 link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
1465 link_vdev_id,
1466 WLAN_MLME_SB_ID);
1467 if (!link_vdev) {
1468 mlo_err("Link vdev is null");
1469 status = QDF_STATUS_E_NULL_VALUE;
1470 goto err;
1471 }
1472
1473 if (mlo_check_connect_req_bmap(link_vdev)) {
1474 status = mlo_roam_prepare_and_send_link_connect_req(assoc_vdev,
1475 link_vdev,
1476 rsp,
1477 &partner_info.partner_link_info[i].link_addr,
1478 partner_info.partner_link_info[i].chan_freq);
1479 if (QDF_IS_STATUS_ERROR(status))
1480 goto err;
1481 else {
1482 mlo_update_connect_req_links(link_vdev, false);
1483 goto end;
1484 }
1485 }
1486 }
1487 err:
1488 if (link_vdev)
1489 mlo_clear_connect_req_links_bmap(link_vdev);
1490 if (sta_ctx && sta_ctx->copied_reassoc_rsp) {
1491 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
1492 sta_ctx->copied_reassoc_rsp = NULL;
1493 }
1494 end:
1495 if (link_vdev)
1496 wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLME_SB_ID);
1497 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
1498 return status;
1499 }
1500
1501 bool
mlo_is_roaming_in_progress(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)1502 mlo_is_roaming_in_progress(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1503 {
1504 struct wlan_objmgr_vdev *vdev;
1505 struct wlan_mlo_dev_context *mlo_dev_ctx;
1506 bool is_roaming_in_progress = false;
1507 uint8_t link_vdev_id;
1508 uint8_t i;
1509
1510 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1511 WLAN_MLME_OBJMGR_ID);
1512 if (!vdev) {
1513 mlme_err("vdev object is NULL for vdev %d", vdev_id);
1514 return false;
1515 }
1516
1517 mlo_dev_ctx = vdev->mlo_dev_ctx;
1518 if (!mlo_dev_ctx) {
1519 mlme_err("mlo_dev_ctx object is NULL for vdev %d", vdev_id);
1520 goto end;
1521 }
1522
1523 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1524 if (!mlo_dev_ctx->wlan_vdev_list[i])
1525 continue;
1526
1527 link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
1528 if (link_vdev_id == WLAN_INVALID_VDEV_ID) {
1529 mlme_err("invalid vdev id");
1530 goto end;
1531 }
1532
1533 if (wlan_cm_is_roam_sync_in_progress(psoc, link_vdev_id)) {
1534 is_roaming_in_progress = true;
1535 goto end;
1536 }
1537 }
1538
1539 end:
1540 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
1541 return is_roaming_in_progress;
1542 }
1543
1544 QDF_STATUS
mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc * psoc,struct roam_scan_candidate_frame * rcvd_frame)1545 mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc,
1546 struct roam_scan_candidate_frame *rcvd_frame)
1547 {
1548 uint8_t *ml_ie, link_id, idx, ies_offset;
1549 qdf_size_t ml_ie_total_len, gen_frame_len;
1550 QDF_STATUS status;
1551 struct mlo_partner_info ml_partner_info = {0};
1552 struct element_info rcvd_probe_rsp, gen_probe_rsp = {0, NULL};
1553 struct roam_scan_candidate_frame entry = {0};
1554 struct qdf_mac_addr self_link_addr;
1555 struct wlan_objmgr_vdev *vdev;
1556
1557 /* Add the received scan entry as it is */
1558 wlan_cm_add_frame_to_scan_db(psoc, rcvd_frame);
1559
1560 ies_offset = WLAN_MAC_HDR_LEN_3A + WLAN_PROBE_RESP_IES_OFFSET;
1561 if (rcvd_frame->frame_length < ies_offset) {
1562 mlme_err("No IEs in probe rsp");
1563 return QDF_STATUS_E_FAILURE;
1564 }
1565
1566 status = util_find_mlie(rcvd_frame->frame + ies_offset,
1567 rcvd_frame->frame_length - ies_offset,
1568 &ml_ie, &ml_ie_total_len);
1569 if (QDF_IS_STATUS_ERROR(status))
1570 return QDF_STATUS_SUCCESS;
1571
1572 status = util_get_bvmlie_persta_partner_info(ml_ie,
1573 ml_ie_total_len,
1574 &ml_partner_info);
1575 if (QDF_IS_STATUS_ERROR(status)) {
1576 mlme_err("Per STA profile parsing failed");
1577 return status;
1578 }
1579
1580 gen_frame_len = MAX_MGMT_MPDU_LEN;
1581
1582 gen_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len);
1583 if (!gen_probe_rsp.ptr)
1584 return QDF_STATUS_E_NOMEM;
1585
1586 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rcvd_frame->vdev_id,
1587 WLAN_MLME_CM_ID);
1588 if (!vdev) {
1589 mlme_err("vdev object is NULL");
1590 status = QDF_STATUS_E_NULL_VALUE;
1591 goto done;
1592 }
1593 qdf_mem_copy(self_link_addr.bytes,
1594 wlan_vdev_mlme_get_macaddr(vdev),
1595 QDF_MAC_ADDR_SIZE);
1596 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
1597
1598 rcvd_probe_rsp.ptr = rcvd_frame->frame + WLAN_MAC_HDR_LEN_3A;
1599 rcvd_probe_rsp.len = rcvd_frame->frame_length - WLAN_MAC_HDR_LEN_3A;
1600
1601 for (idx = 0; idx < ml_partner_info.num_partner_links; idx++) {
1602 link_id = ml_partner_info.partner_link_info[idx].link_id;
1603 status = util_gen_link_probe_rsp(rcvd_probe_rsp.ptr,
1604 rcvd_probe_rsp.len,
1605 link_id,
1606 self_link_addr,
1607 gen_probe_rsp.ptr,
1608 gen_frame_len,
1609 (qdf_size_t *)&gen_probe_rsp.len);
1610 if (QDF_IS_STATUS_ERROR(status)) {
1611 mlme_err("MLO: Link %d probe resp gen failed %d",
1612 link_id, status);
1613 status = QDF_STATUS_E_FAILURE;
1614 goto done;
1615 }
1616
1617 mlme_debug("MLO: link probe rsp size:%u orig probe rsp :%u",
1618 gen_probe_rsp.len, rcvd_probe_rsp.len);
1619
1620 entry.vdev_id = rcvd_frame->vdev_id;
1621 entry.frame = gen_probe_rsp.ptr;
1622 entry.frame_length = gen_probe_rsp.len;
1623 entry.rssi = rcvd_frame->rssi;
1624
1625 wlan_cm_add_frame_to_scan_db(psoc, &entry);
1626 }
1627 done:
1628 qdf_mem_free(gen_probe_rsp.ptr);
1629
1630 return status;
1631 }
1632
1633 bool
mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev * vdev)1634 mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev *vdev)
1635 {
1636 struct mlo_partner_info *partner_info;
1637
1638 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
1639 return true;
1640
1641 if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx ||
1642 !vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp)
1643 return true;
1644
1645 partner_info =
1646 &vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp->ml_parnter_info;
1647 if (partner_info->num_partner_links <= 1)
1648 return true;
1649
1650 /* Roamed to MLO AP, do nothing if link vdev is disconnected */
1651 return false;
1652 }
1653
1654 bool
mlo_check_is_given_vdevs_on_same_mld(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id_1,uint8_t vdev_id_2)1655 mlo_check_is_given_vdevs_on_same_mld(struct wlan_objmgr_psoc *psoc,
1656 uint8_t vdev_id_1, uint8_t vdev_id_2)
1657 {
1658 struct wlan_objmgr_vdev *vdev1;
1659 struct wlan_mlo_dev_context *ml_dev_ctx1;
1660 struct wlan_objmgr_vdev **vdev_list;
1661 bool is_same_mld = false;
1662 uint8_t i;
1663
1664 vdev1 = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id_1,
1665 WLAN_MLME_CM_ID);
1666 if (!vdev1)
1667 return false;
1668
1669 ml_dev_ctx1 = vdev1->mlo_dev_ctx;
1670 if (!ml_dev_ctx1)
1671 goto end;
1672
1673 vdev_list = ml_dev_ctx1->wlan_vdev_list;
1674 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1675 if (!vdev_list[i])
1676 continue;
1677
1678 if (wlan_vdev_get_id(vdev_list[i]) == vdev_id_2) {
1679 is_same_mld = true;
1680 goto end;
1681 }
1682 }
1683
1684 end:
1685 if (vdev1)
1686 wlan_objmgr_vdev_release_ref(vdev1, WLAN_MLME_CM_ID);
1687
1688 return is_same_mld;
1689 }
1690