1 /*
2 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /*
19 * DOC: contains MLO manager STA related api's
20 */
21
22 #include <wlan_cmn.h>
23 #include <wlan_mlo_mgr_sta.h>
24 #include <wlan_cm_public_struct.h>
25 #include <wlan_mlo_mgr_main.h>
26 #include <wlan_cm_api.h>
27 #include <wlan_mlo_mgr_cmn.h>
28 #include <wlan_scan_api.h>
29 #include <scheduler_api.h>
30 #include <wlan_crypto_global_api.h>
31 #include <utils_mlo.h>
32 #include <wlan_mlme_cmn.h>
33 #include <wlan_scan_utils_api.h>
34 #include <qdf_time.h>
35 #include <wlan_objmgr_peer_obj.h>
36 #include <wlan_scan_api.h>
37 #include <wlan_mlo_mgr_peer.h>
38 #include <qdf_module.h>
39 #include <wlan_mlo_mgr_public_api.h>
40
41 #ifdef WLAN_FEATURE_11BE_MLO
42 static QDF_STATUS mlo_disconnect_req(struct wlan_objmgr_vdev *vdev,
43 enum wlan_cm_source source,
44 enum wlan_reason_code reason_code,
45 struct qdf_mac_addr *bssid,
46 bool validate_req);
47
48 void
mlo_allocate_and_copy_ies(struct wlan_cm_connect_req * target,struct wlan_cm_connect_req * source)49 mlo_allocate_and_copy_ies(struct wlan_cm_connect_req *target,
50 struct wlan_cm_connect_req *source)
51 {
52 target->assoc_ie.ptr = NULL;
53 target->scan_ie.ptr = NULL;
54 target->crypto.wep_keys.key = NULL;
55 target->crypto.wep_keys.seq = NULL;
56 target->crypto.wep_keys.key_len = 0;
57 target->crypto.wep_keys.seq_len = 0;
58
59 if (source->scan_ie.ptr) {
60 target->scan_ie.ptr = qdf_mem_malloc(source->scan_ie.len);
61 if (!target->scan_ie.ptr)
62 target->scan_ie.len = 0;
63 else
64 qdf_mem_copy(target->scan_ie.ptr,
65 source->scan_ie.ptr, source->scan_ie.len);
66 }
67
68 if (source->assoc_ie.ptr) {
69 target->assoc_ie.ptr = qdf_mem_malloc(source->assoc_ie.len);
70 if (!target->assoc_ie.ptr)
71 target->assoc_ie.len = 0;
72 else
73 qdf_mem_copy(target->assoc_ie.ptr, source->assoc_ie.ptr,
74 source->assoc_ie.len);
75 }
76 }
77
78 /*
79 * mlo_get_tdls_link_vdev() - API to get tdls link vdev
80 * @mlo_dev_ctx: pointer to mlo dev context
81 *
82 * Return: MLD tdls link vdev
83 */
84 static inline struct wlan_objmgr_vdev *
mlo_get_tdls_link_vdev(struct wlan_mlo_dev_context * mlo_dev_ctx)85 mlo_get_tdls_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx)
86 {
87 uint8_t i = 0;
88
89 if (!mlo_dev_ctx)
90 return NULL;
91
92 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
93 if (!mlo_dev_ctx->wlan_vdev_list[i])
94 continue;
95
96 if (wlan_vdev_mlme_is_tdls_vdev(mlo_dev_ctx->wlan_vdev_list[i]))
97 return mlo_dev_ctx->wlan_vdev_list[i];
98 }
99 return NULL;
100 }
101
102 struct wlan_objmgr_vdev *
wlan_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev * vdev)103 wlan_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev)
104 {
105 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
106
107 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
108 return NULL;
109
110 return mlo_get_tdls_link_vdev(mlo_dev_ctx);
111 }
112
113 /*
114 * mlo_get_assoc_link_vdev - API to get assoc link vdev
115 *
116 * @mlo_dev_ctx: pointer to mlo dev context
117 *
118 * Return: MLD assoc link vdev
119 */
120 static inline struct wlan_objmgr_vdev *
mlo_get_assoc_link_vdev(struct wlan_mlo_dev_context * mlo_dev_ctx)121 mlo_get_assoc_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx)
122 {
123 uint8_t i = 0;
124
125 if (!mlo_dev_ctx)
126 return NULL;
127
128 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
129 if (!mlo_dev_ctx->wlan_vdev_list[i])
130 continue;
131
132 if (wlan_vdev_mlme_is_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]) &&
133 !wlan_vdev_mlme_is_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i]))
134 return mlo_dev_ctx->wlan_vdev_list[i];
135 }
136 return NULL;
137 }
138
139 struct wlan_objmgr_vdev *
wlan_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev * vdev)140 wlan_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev)
141 {
142 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
143
144 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
145 return NULL;
146
147 return mlo_get_assoc_link_vdev(mlo_dev_ctx);
148 }
149
150 struct wlan_objmgr_vdev *
ucfg_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev * vdev)151 ucfg_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev)
152 {
153 return wlan_mlo_get_assoc_link_vdev(vdev);
154 }
155
156 /**
157 * mlo_is_mld_disconnected - Check whether MLD is disconnected
158 *
159 * @vdev: pointer to vdev
160 *
161 * Return: true if mld is disconnected, false otherwise
162 */
163 static inline
mlo_is_mld_disconnected(struct wlan_objmgr_vdev * vdev)164 bool mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev)
165 {
166 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
167 uint8_t i = 0;
168
169 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
170 return true;
171
172 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
173 if (!mlo_dev_ctx->wlan_vdev_list[i])
174 continue;
175
176 if (!wlan_cm_is_vdev_disconnected(mlo_dev_ctx->wlan_vdev_list[i]))
177 return false;
178 }
179 return true;
180 }
181
mlo_is_mld_disconnecting_connecting(struct wlan_objmgr_vdev * vdev)182 bool mlo_is_mld_disconnecting_connecting(struct wlan_objmgr_vdev *vdev)
183 {
184 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
185 uint8_t i = 0;
186
187 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
188 return false;
189
190 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
191 if (!mlo_dev_ctx->wlan_vdev_list[i])
192 continue;
193 if (wlan_cm_is_vdev_disconnecting(mlo_dev_ctx->wlan_vdev_list[i]) ||
194 wlan_cm_is_vdev_connecting(mlo_dev_ctx->wlan_vdev_list[i]))
195 return true;
196 }
197 return false;
198 }
199
mlo_is_ml_connection_in_progress(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)200 bool mlo_is_ml_connection_in_progress(struct wlan_objmgr_psoc *psoc,
201 uint8_t vdev_id)
202 {
203 struct wlan_objmgr_vdev *vdev;
204 struct wlan_mlo_dev_context *mlo_dev_ctx;
205 uint8_t i = 0;
206 bool val = false;
207
208 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
209 WLAN_MLO_MGR_ID);
210
211 if (!vdev) {
212 mlo_err("Invalid vdev");
213 return false;
214 }
215
216 mlo_dev_ctx = vdev->mlo_dev_ctx;
217 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
218 goto end;
219
220 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
221 if (!mlo_dev_ctx->wlan_vdev_list[i])
222 continue;
223 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
224 if (!wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) {
225 val = true;
226 goto end;
227 }
228 }
229 }
230
231 end:
232 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
233 return val;
234 }
235
ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev * vdev)236 bool ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev)
237 {
238 return mlo_is_mld_disconnected(vdev);
239 }
240
241 /**
242 * mlo_send_link_disconnect- Issue the disconnect request on MLD links
243 *
244 * @vdev: pointer to vdev
245 * @source: disconnect source
246 * @reason_code: disconnect reason
247 * @bssid: bssid of AP to disconnect, can be null if not known
248 *
249 * Return: QDF_STATUS
250 */
251 static QDF_STATUS
mlo_send_link_disconnect(struct wlan_objmgr_vdev * vdev,enum wlan_cm_source source,enum wlan_reason_code reason_code,struct qdf_mac_addr * bssid)252 mlo_send_link_disconnect(struct wlan_objmgr_vdev *vdev,
253 enum wlan_cm_source source,
254 enum wlan_reason_code reason_code,
255 struct qdf_mac_addr *bssid)
256 {
257 uint8_t i = 0;
258 enum wlan_cm_source link_source = source;
259 struct wlan_objmgr_vdev *assoc_vdev =
260 mlo_get_assoc_link_vdev(vdev->mlo_dev_ctx);
261 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
262 uint16_t vdev_count = 0;
263 struct wlan_mlo_sta *sta_ctx = NULL;
264
265 sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
266 if (!sta_ctx) {
267 mlo_err("Invalid sta_ctx");
268 return QDF_STATUS_E_FAILURE;
269 }
270
271 if (!assoc_vdev && mlo_mgr_is_link_switch_supported(vdev)) {
272 if (!wlan_mlo_mgr_is_link_switch_on_assoc_vdev(vdev))
273 return QDF_STATUS_E_FAILURE;
274
275 assoc_vdev = wlan_mlo_mgr_link_switch_get_assoc_vdev(vdev);
276 mlo_release_vdev_ref(assoc_vdev);
277 }
278
279 /*
280 * Change the source for the link vdev to make sure it's handled as a
281 * Northbound disconnect in VDEV/PEER state machine.
282 */
283 if (source != CM_OSIF_DISCONNECT)
284 link_source = CM_MLO_LINK_VDEV_DISCONNECT;
285
286 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
287 for (i = 0; i < vdev_count; i++) {
288 if ((wlan_vdev_list[i] != assoc_vdev) &&
289 (qdf_test_bit(i, sta_ctx->wlan_connected_links) ||
290 (wlan_cm_is_vdev_connected(wlan_vdev_list[i]) &&
291 !wlan_peer_is_mlo(wlan_vdev_get_bsspeer(wlan_vdev_list[i]))) ||
292 wlan_cm_is_vdev_idle_due_to_link_switch(wlan_vdev_list[i])))
293 wlan_cm_disconnect(wlan_vdev_list[i],
294 link_source, reason_code,
295 NULL);
296 mlo_release_vdev_ref(wlan_vdev_list[i]);
297 }
298
299 if (assoc_vdev)
300 wlan_cm_disconnect(assoc_vdev, source, reason_code, NULL);
301
302 return QDF_STATUS_SUCCESS;
303 }
304
mlo_free_copied_conn_req(struct wlan_mlo_sta * sta_ctx)305 static void mlo_free_copied_conn_req(struct wlan_mlo_sta *sta_ctx)
306 {
307 if (sta_ctx) {
308 mlo_debug("enter");
309 copied_conn_req_lock_acquire(sta_ctx);
310 if (sta_ctx->copied_conn_req) {
311 wlan_cm_free_connect_req(sta_ctx->copied_conn_req);
312 sta_ctx->copied_conn_req = NULL;
313 }
314 copied_conn_req_lock_release(sta_ctx);
315 }
316 }
317
318 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
mlo_mgr_get_per_link_chan_info(struct wlan_objmgr_vdev * vdev,int link_id,struct wlan_channel * chan_info)319 int mlo_mgr_get_per_link_chan_info(struct wlan_objmgr_vdev *vdev, int link_id,
320 struct wlan_channel *chan_info)
321 {
322 struct mlo_link_info *ml_link_info;
323
324 ml_link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx,
325 link_id);
326 if (!ml_link_info) {
327 mlo_debug("ml_link_info null for link_id: %d", link_id);
328 return -EINVAL;
329 }
330
331 qdf_mem_copy(chan_info, ml_link_info->link_chan_info,
332 sizeof(*chan_info));
333
334 return 0;
335 }
336
337 static QDF_STATUS
mlo_validate_connect_req(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_dev_context * mlo_dev_ctx,struct wlan_cm_connect_req * req)338 mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev,
339 struct wlan_mlo_dev_context *mlo_dev_ctx,
340 struct wlan_cm_connect_req *req)
341 {
342 /* check back to back connect handling */
343 return QDF_STATUS_SUCCESS;
344 }
345
346 static QDF_STATUS
mlo_validate_disconn_req(struct wlan_objmgr_vdev * vdev,enum wlan_cm_source source,enum wlan_reason_code reason_code,struct qdf_mac_addr * bssid)347 mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev,
348 enum wlan_cm_source source,
349 enum wlan_reason_code reason_code,
350 struct qdf_mac_addr *bssid)
351 {
352 return QDF_STATUS_SUCCESS;
353 }
354
mlo_validate_mlo_cap(struct wlan_objmgr_vdev * vdev)355 static QDF_STATUS mlo_validate_mlo_cap(struct wlan_objmgr_vdev *vdev)
356 {
357 return QDF_STATUS_SUCCESS;
358 }
359
360 static inline
mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev * vdev)361 void mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
362 { }
363 #else
364 /**
365 * mlo_is_mld_connected - Check whether MLD is connected
366 *
367 * @vdev: pointer to vdev
368 *
369 * Return: true if mld is connected, false otherwise
370 */
371 static inline
mlo_is_mld_connected(struct wlan_objmgr_vdev * vdev)372 bool mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev)
373 {
374 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
375 uint8_t i = 0;
376
377 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
378 return true;
379
380 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
381 if (!mlo_dev_ctx->wlan_vdev_list[i])
382 continue;
383
384 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
385 if (!wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i]))
386 return false;
387 }
388 }
389 return true;
390 }
391
ucfg_mlo_is_mld_connected(struct wlan_objmgr_vdev * vdev)392 bool ucfg_mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev)
393 {
394 return mlo_is_mld_connected(vdev);
395 }
396
397 static inline
mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev * vdev)398 void mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
399 {
400 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
401 uint8_t i = 0;
402
403 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
404 return;
405
406 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
407 if (!mlo_dev_ctx->wlan_vdev_list[i])
408 continue;
409 wlan_vdev_mlme_clear_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]);
410 wlan_vdev_mlme_clear_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i]);
411 }
412 mlo_clear_bridge_sta_ctx(vdev);
413 }
414
ucfg_mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev * vdev)415 void ucfg_mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
416 {
417 mlo_mld_clear_mlo_cap(vdev);
418 }
419
420 static void
mlo_cm_handle_connect_in_disconnection_state(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req)421 mlo_cm_handle_connect_in_disconnection_state(struct wlan_objmgr_vdev *vdev,
422 struct wlan_cm_connect_req *req)
423 {
424 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
425 struct wlan_mlo_sta *sta_ctx;
426
427 if (!mlo_dev_ctx) {
428 mlo_err("ML dev ctx is NULL");
429 return;
430 }
431
432 sta_ctx = mlo_dev_ctx->sta_ctx;
433 if (!sta_ctx->connect_req)
434 sta_ctx->connect_req = qdf_mem_malloc(
435 sizeof(struct wlan_cm_connect_req));
436
437 if (sta_ctx->connect_req) {
438 qdf_mem_copy(sta_ctx->connect_req, req,
439 sizeof(struct wlan_cm_connect_req));
440 mlo_allocate_and_copy_ies(sta_ctx->connect_req, req);
441 } else {
442 mlo_err("Failed to allocate connect req");
443 }
444 }
445
446 static QDF_STATUS
mlo_validate_disconn_req(struct wlan_objmgr_vdev * vdev,enum wlan_cm_source source,enum wlan_reason_code reason_code,struct qdf_mac_addr * bssid)447 mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev,
448 enum wlan_cm_source source,
449 enum wlan_reason_code reason_code,
450 struct qdf_mac_addr *bssid)
451 {
452 struct wlan_mlo_dev_context *mlo_dev = vdev->mlo_dev_ctx;
453 struct wlan_mlo_sta *sta_ctx = mlo_dev->sta_ctx;
454 uint8_t i = 0;
455
456 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
457 if (!mlo_dev->wlan_vdev_list[i])
458 continue;
459
460 if (wlan_cm_is_vdev_connecting(mlo_dev->wlan_vdev_list[i])) {
461 if (!wlan_vdev_mlme_is_mlo_link_vdev(
462 mlo_dev->wlan_vdev_list[i]))
463 return QDF_STATUS_SUCCESS;
464
465 if (!sta_ctx->disconn_req)
466 sta_ctx->disconn_req =
467 qdf_mem_malloc(
468 sizeof(struct wlan_cm_disconnect_req));
469
470 if (!sta_ctx->disconn_req)
471 return QDF_STATUS_SUCCESS;
472
473 sta_ctx->disconn_req->vdev_id =
474 wlan_vdev_get_id(vdev);
475 sta_ctx->disconn_req->source = source;
476 sta_ctx->disconn_req->reason_code = reason_code;
477 if (bssid)
478 qdf_copy_macaddr(&sta_ctx->disconn_req->bssid,
479 bssid);
480 return QDF_STATUS_E_BUSY;
481 } else if (wlan_cm_is_vdev_connected(mlo_dev->wlan_vdev_list[i]) &&
482 !wlan_vdev_mlme_is_mlo_link_vdev(
483 mlo_dev->wlan_vdev_list[i]) &&
484 wlan_peer_is_mlo(wlan_vdev_get_bsspeer(
485 mlo_dev->wlan_vdev_list[i]))) {
486 /* If the vdev is moved to connected state but
487 * MLO mgr is not yet notified, defer disconnect
488 * as it can cause race between connect complete
489 * and disconnect initiation
490 */
491 if (!qdf_test_bit(i, sta_ctx->wlan_connected_links)) {
492 if (!sta_ctx->disconn_req)
493 sta_ctx->disconn_req =
494 qdf_mem_malloc(
495 sizeof(struct wlan_cm_disconnect_req));
496
497 if (!sta_ctx->disconn_req)
498 return QDF_STATUS_SUCCESS;
499
500 sta_ctx->disconn_req->vdev_id =
501 wlan_vdev_get_id(vdev);
502 sta_ctx->disconn_req->source = source;
503 sta_ctx->disconn_req->reason_code = reason_code;
504 if (bssid)
505 qdf_copy_macaddr(&sta_ctx->disconn_req->bssid,
506 bssid);
507
508 return QDF_STATUS_E_BUSY;
509 }
510 }
511 }
512 return QDF_STATUS_SUCCESS;
513 }
514
mlo_disconnect_no_lock(struct wlan_objmgr_vdev * vdev,enum wlan_cm_source source,enum wlan_reason_code reason_code,struct qdf_mac_addr * bssid)515 static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
516 enum wlan_cm_source source,
517 enum wlan_reason_code reason_code,
518 struct qdf_mac_addr *bssid)
519 {
520 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
521 struct wlan_mlo_sta *sta_ctx = NULL;
522 QDF_STATUS status = QDF_STATUS_SUCCESS;
523 struct wlan_objmgr_vdev *assoc_vdev = NULL;
524 uint8_t i = 0;
525
526 if (mlo_dev_ctx)
527 sta_ctx = mlo_dev_ctx->sta_ctx;
528 if (sta_ctx) {
529 mlo_free_copied_conn_req(sta_ctx);
530 } else {
531 return QDF_STATUS_E_FAILURE;
532 }
533
534 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
535 sta_ctx = mlo_dev_ctx->sta_ctx;
536 if (!sta_ctx)
537 return QDF_STATUS_E_FAILURE;
538
539 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
540
541 if (sta_ctx->connect_req) {
542 wlan_cm_free_connect_req(sta_ctx->connect_req);
543 sta_ctx->connect_req = NULL;
544 }
545
546 status = mlo_validate_disconn_req(vdev, source,
547 reason_code, bssid);
548 if (QDF_IS_STATUS_ERROR(status)) {
549 mlo_err("Connect in progress, deferring disconnect");
550 return status;
551 }
552
553 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
554 if (!mlo_dev_ctx->wlan_vdev_list[i])
555 continue;
556
557 if ((mlo_dev_ctx->wlan_vdev_list[i] != assoc_vdev) &&
558 (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links) ||
559 (wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i]) &&
560 !wlan_peer_is_mlo(wlan_vdev_get_bsspeer(mlo_dev_ctx->wlan_vdev_list[i])))))
561 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
562 source, reason_code,
563 NULL);
564 }
565
566 if (assoc_vdev)
567 wlan_cm_disconnect(assoc_vdev, source,
568 reason_code, NULL);
569 }
570
571 return status;
572 }
573
574 static void
mlo_cm_handle_connect_in_connection_state(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req)575 mlo_cm_handle_connect_in_connection_state(struct wlan_objmgr_vdev *vdev,
576 struct wlan_cm_connect_req *req)
577 {
578 mlo_disconnect_no_lock(vdev, CM_INTERNAL_DISCONNECT,
579 REASON_UNSPEC_FAILURE, NULL);
580 mlo_cm_handle_connect_in_disconnection_state(vdev, req);
581 }
582
583 static QDF_STATUS
mlo_validate_connect_req(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_dev_context * mlo_dev_ctx,struct wlan_cm_connect_req * req)584 mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev,
585 struct wlan_mlo_dev_context *mlo_dev_ctx,
586 struct wlan_cm_connect_req *req)
587 {
588 uint8_t i = 0;
589 QDF_STATUS status = QDF_STATUS_SUCCESS;
590
591 if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
592 return QDF_STATUS_SUCCESS;
593
594 // Handle connect in various states
595 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
596 if (!mlo_dev_ctx->wlan_vdev_list[i])
597 continue;
598
599 if ((wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) ||
600 (wlan_cm_is_vdev_connecting(mlo_dev_ctx->wlan_vdev_list[i])) ||
601 (wlan_cm_is_vdev_roaming(mlo_dev_ctx->wlan_vdev_list[i]))) {
602 mlo_cm_handle_connect_in_connection_state(mlo_dev_ctx->wlan_vdev_list[i], req);
603 return QDF_STATUS_E_BUSY;
604 } else if (wlan_cm_is_vdev_disconnecting(mlo_dev_ctx->wlan_vdev_list[i])) {
605 mlo_cm_handle_connect_in_disconnection_state(mlo_dev_ctx->wlan_vdev_list[i], req);
606 return QDF_STATUS_E_BUSY;
607 }
608
609 /*
610 * mlo_connect: update wlan_connect_req_links in
611 * wlan_cfg80211_conect on osif_cm_connect,
612 * Validate pre checks for connection
613 */
614 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connect_req_links)) {
615 status = mlo_mlme_validate_conn_req(
616 mlo_dev_ctx->wlan_vdev_list[i], NULL);
617 if (status != QDF_STATUS_SUCCESS)
618 return status;
619 /*
620 * clone security params in all partner sta vaps
621 */
622 mlo_mlme_clone_sta_security(
623 mlo_dev_ctx->wlan_vdev_list[i], req);
624 }
625 }
626 return status;
627 }
628
mlo_validate_mlo_cap(struct wlan_objmgr_vdev * vdev)629 static QDF_STATUS mlo_validate_mlo_cap(struct wlan_objmgr_vdev *vdev)
630 {
631 if (wlan_vdev_mlme_is_mlo_vdev(vdev))
632 return QDF_STATUS_SUCCESS;
633
634 return QDF_STATUS_E_FAILURE;
635 }
636 #endif
637
mlo_set_cu_bpcc(struct wlan_objmgr_vdev * vdev,uint8_t vdev_id,uint8_t bpcc)638 QDF_STATUS mlo_set_cu_bpcc(struct wlan_objmgr_vdev *vdev,
639 uint8_t vdev_id, uint8_t bpcc)
640 {
641 struct wlan_mlo_dev_context *mlo_dev_ctx;
642 struct mlo_sta_cu_params *cu_param;
643 uint8_t i;
644
645 mlo_dev_ctx = vdev->mlo_dev_ctx;
646 if (!mlo_dev_ctx) {
647 mlo_err("ML dev ctx is NULL");
648 return QDF_STATUS_E_INVAL;
649 }
650
651 cu_param = &mlo_dev_ctx->sta_ctx->mlo_cu_param[0];
652 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
653 if (cu_param[i].initialized && cu_param[i].vdev_id == vdev_id) {
654 cu_param[i].bpcc = bpcc;
655 return QDF_STATUS_SUCCESS;
656 }
657 }
658
659 return QDF_STATUS_E_INVAL;
660 }
661
mlo_get_cu_bpcc(struct wlan_objmgr_vdev * vdev,uint8_t vdev_id,uint8_t * bpcc)662 QDF_STATUS mlo_get_cu_bpcc(struct wlan_objmgr_vdev *vdev,
663 uint8_t vdev_id, uint8_t *bpcc)
664 {
665 struct wlan_mlo_dev_context *mlo_dev_ctx;
666 struct mlo_sta_cu_params *cu_param;
667 uint8_t i;
668
669 mlo_dev_ctx = vdev->mlo_dev_ctx;
670 if (!mlo_dev_ctx) {
671 mlo_err("ML dev ctx is NULL");
672 return QDF_STATUS_E_INVAL;
673 }
674
675 cu_param = &mlo_dev_ctx->sta_ctx->mlo_cu_param[0];
676 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
677 if (cu_param[i].initialized &&
678 cu_param[i].vdev_id == vdev_id) {
679 *bpcc = cu_param[i].bpcc;
680 return QDF_STATUS_SUCCESS;
681 }
682 }
683
684 return QDF_STATUS_E_INVAL;
685 }
686
mlo_init_cu_bpcc(struct wlan_mlo_dev_context * mlo_dev_ctx,uint8_t vdev_id)687 void mlo_init_cu_bpcc(struct wlan_mlo_dev_context *mlo_dev_ctx,
688 uint8_t vdev_id)
689 {
690 uint8_t i;
691 struct mlo_sta_cu_params *cu_param;
692 uint8_t empty_slot = 0xff;
693
694 cu_param = &mlo_dev_ctx->sta_ctx->mlo_cu_param[0];
695
696 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
697 if (cu_param[i].initialized &&
698 cu_param[i].vdev_id == vdev_id) {
699 cu_param[i].bpcc = 0;
700 return;
701 }
702
703 if (!cu_param[i].initialized && empty_slot == 0xff)
704 empty_slot = i;
705 }
706
707 if (empty_slot != 0xff) {
708 cu_param[empty_slot].bpcc = 0;
709 cu_param[empty_slot].vdev_id = vdev_id;
710 cu_param[empty_slot].initialized = true;
711 mlo_debug("init cu bpcc idx %d, vdev_id %d",
712 empty_slot, vdev_id);
713 } else {
714 mlo_debug("No bpcc idx for vdev_id %d", vdev_id);
715 }
716 }
717
mlo_clear_cu_bpcc(struct wlan_objmgr_vdev * vdev)718 void mlo_clear_cu_bpcc(struct wlan_objmgr_vdev *vdev)
719 {
720 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
721 struct wlan_mlo_sta *sta_ctx = NULL;
722 uint32_t size;
723
724 if (!vdev)
725 return;
726
727 mlo_dev_ctx = vdev->mlo_dev_ctx;
728 if (!mlo_dev_ctx)
729 return;
730
731 sta_ctx = mlo_dev_ctx->sta_ctx;
732 if (!sta_ctx)
733 return;
734
735 size = sizeof(sta_ctx->mlo_cu_param);
736 qdf_mem_zero(sta_ctx->mlo_cu_param, size);
737 }
738
739 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
mlo_clear_sta_key_mgmt(struct wlan_objmgr_vdev * vdev)740 static void mlo_clear_sta_key_mgmt(struct wlan_objmgr_vdev *vdev)
741 {
742 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
743 struct wlan_mlo_sta *sta_ctx = NULL;
744
745 if (!vdev)
746 return;
747
748 mlo_dev_ctx = vdev->mlo_dev_ctx;
749 if (!mlo_dev_ctx)
750 return;
751
752 sta_ctx = mlo_dev_ctx->sta_ctx;
753 if (!sta_ctx)
754 return;
755
756 qdf_mem_zero(sta_ctx->key_mgmt, sizeof(sta_ctx->key_mgmt));
757
758 mlo_debug("clear sta_key_mgmt");
759 }
760
761 #else
mlo_clear_sta_key_mgmt(struct wlan_objmgr_vdev * vdev)762 static void mlo_clear_sta_key_mgmt(struct wlan_objmgr_vdev *vdev)
763 {
764 }
765 #endif
766
mlo_connect(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req)767 QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev,
768 struct wlan_cm_connect_req *req)
769 {
770 struct wlan_mlo_dev_context *mlo_dev_ctx;
771 struct wlan_mlo_sta *sta_ctx = NULL;
772 QDF_STATUS status = QDF_STATUS_SUCCESS;
773
774 mlo_dev_ctx = vdev->mlo_dev_ctx;
775 if (mlo_dev_ctx)
776 sta_ctx = mlo_dev_ctx->sta_ctx;
777 if (sta_ctx) {
778 status = mlo_validate_mlo_cap(vdev);
779 if (QDF_IS_STATUS_ERROR(status))
780 return wlan_cm_start_connect(vdev, req);
781
782 mlo_dev_lock_acquire(mlo_dev_ctx);
783 status = mlo_validate_connect_req(vdev, mlo_dev_ctx, req);
784 copied_conn_req_lock_acquire(sta_ctx);
785 if (!sta_ctx->copied_conn_req)
786 sta_ctx->copied_conn_req = qdf_mem_malloc(
787 sizeof(struct wlan_cm_connect_req));
788 else
789 wlan_cm_free_connect_req_param(sta_ctx->copied_conn_req);
790
791 if (sta_ctx->copied_conn_req) {
792 qdf_mem_copy(sta_ctx->copied_conn_req, req,
793 sizeof(struct wlan_cm_connect_req));
794 mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req,
795 req);
796 copied_conn_req_lock_release(sta_ctx);
797 } else {
798 mlo_err("Failed to allocate orig connect req");
799 copied_conn_req_lock_release(sta_ctx);
800 mlo_dev_lock_release(mlo_dev_ctx);
801
802 return QDF_STATUS_E_NOMEM;
803 }
804
805 if (QDF_IS_STATUS_SUCCESS(status)) {
806 mlo_clear_cu_bpcc(vdev);
807 mlo_clear_connected_links_bmap(vdev);
808 mlo_clear_sta_key_mgmt(vdev);
809 mlo_dev_lock_release(mlo_dev_ctx);
810
811 status = wlan_cm_start_connect(vdev, req);
812 if (QDF_IS_STATUS_ERROR(status))
813 mlo_mld_clear_mlo_cap(vdev);
814 return status;
815 }
816
817 mlo_dev_lock_release(mlo_dev_ctx);
818
819 return status;
820 }
821
822 return wlan_cm_start_connect(vdev, req);
823 }
824
825 static inline void
mlo_update_connect_req_chan_info(struct wlan_cm_connect_req * req)826 mlo_update_connect_req_chan_info(struct wlan_cm_connect_req *req)
827 {
828 req->chan_freq = 0;
829 req->chan_freq_hint = 0;
830 }
831
832 /**
833 * mlo_prepare_and_send_connect- Prepare and send the connect req
834 *
835 * @vdev: vdev pointer
836 * @ml_parnter_info: ml partner link info
837 * @link_info: link info on which connect req will be sent
838 * @ssid: ssid to connect
839 * @mld_addr: MLD address for connect request.
840 *
841 * Return: none
842 */
843
844 static void
mlo_prepare_and_send_connect(struct wlan_objmgr_vdev * vdev,struct mlo_partner_info ml_parnter_info,struct mlo_link_info link_info,struct wlan_ssid ssid,struct qdf_mac_addr * mld_addr)845 mlo_prepare_and_send_connect(struct wlan_objmgr_vdev *vdev,
846 struct mlo_partner_info ml_parnter_info,
847 struct mlo_link_info link_info,
848 struct wlan_ssid ssid,
849 struct qdf_mac_addr *mld_addr)
850 {
851 struct wlan_cm_connect_req req = {0};
852 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
853 struct wlan_mlo_sta *sta_ctx;
854
855 if (!mlo_dev_ctx) {
856 mlo_err("ML dev ctx is NULL");
857 return;
858 }
859
860 sta_ctx = mlo_dev_ctx->sta_ctx;
861
862 mlo_debug("Partner link connect mac:" QDF_MAC_ADDR_FMT
863 " bssid:" QDF_MAC_ADDR_FMT " vdev_id:%d",
864 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
865 QDF_MAC_ADDR_REF(link_info.link_addr.bytes),
866 wlan_vdev_get_id(vdev));
867
868 if (sta_ctx->copied_conn_req)
869 qdf_mem_copy(&req, sta_ctx->copied_conn_req,
870 sizeof(struct wlan_cm_connect_req));
871 else
872 mlo_err("Invalid copied_conn_req");
873
874 mlo_update_connect_req_chan_info(&req);
875
876 qdf_mem_copy(req.bssid.bytes,
877 link_info.link_addr.bytes,
878 QDF_MAC_ADDR_SIZE);
879
880 qdf_mem_copy(&req.ml_parnter_info,
881 &ml_parnter_info,
882 sizeof(struct mlo_partner_info));
883
884 req.vdev_id = wlan_vdev_get_id(vdev);
885 req.ssid.length = ssid.length;
886 qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length);
887 if (mld_addr)
888 qdf_copy_macaddr(&req.mld_addr, mld_addr);
889
890 if (sta_ctx->copied_conn_req)
891 mlo_allocate_and_copy_ies(&req, sta_ctx->copied_conn_req);
892
893 if (!req.assoc_ie.ptr)
894 mlo_err("Failed to allocate assoc IEs");
895
896 if (!req.scan_ie.ptr)
897 mlo_err("Failed to allocate scan IEs");
898
899 /* Reset crypto auth type for partner link.
900 * It will be set based on partner scan cache entry
901 */
902 req.crypto.auth_type = 0;
903
904 wlan_cm_start_connect(vdev, &req);
905 wlan_cm_free_connect_req_param(&req);
906 }
907
908 /**
909 * mlo_send_link_connect- Create/Issue the connection on secondary link
910 *
911 * @vdev: vdev pointer
912 * @resp: Connection resp of assoc VDEV
913 *
914 * Return: none
915 */
916 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
mlo_send_link_connect(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * resp)917 static void mlo_send_link_connect(struct wlan_objmgr_vdev *vdev,
918 struct wlan_cm_connect_resp *resp)
919 {
920 /* Create the secondary interface, Send keys if the last link */
921 uint8_t i, partner_idx = 0;
922 struct wlan_ssid ssid = {0};
923 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
924 uint16_t vdev_count = 0;
925 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
926 struct mlo_partner_info *ml_parnter_info = &resp->ml_parnter_info;
927
928 mlo_debug("Sending link connect on partner interface");
929 wlan_vdev_mlme_get_ssid(
930 vdev, ssid.ssid,
931 &ssid.length);
932
933 if (!ml_parnter_info->num_partner_links) {
934 mlo_err("No partner info in connect resp");
935 return;
936 }
937
938 if(wlan_vdev_mlme_is_mlo_link_vdev(vdev))
939 return;
940
941 copied_conn_req_lock_acquire(mlo_dev_ctx->sta_ctx);
942 if (!mlo_dev_ctx->sta_ctx->copied_conn_req) {
943 mlo_dev_ctx->sta_ctx->copied_conn_req =
944 qdf_mem_malloc(sizeof(struct wlan_cm_connect_req));
945 if (mlo_dev_ctx->sta_ctx->copied_conn_req) {
946 wlan_cm_get_active_connect_req_param(vdev,
947 mlo_dev_ctx->sta_ctx->copied_conn_req);
948 }
949 }
950 copied_conn_req_lock_release(mlo_dev_ctx->sta_ctx);
951
952 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
953 for (i = 0; i < vdev_count; i++) {
954 if (wlan_vdev_list[i] == vdev) {
955 mlo_release_vdev_ref(wlan_vdev_list[i]);
956 continue;
957 }
958 wlan_vdev_mlme_set_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]);
959 wlan_vdev_mlme_set_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i]);
960 wlan_vdev_set_link_id(
961 wlan_vdev_list[i],
962 ml_parnter_info->partner_link_info[partner_idx].link_id);
963 ml_parnter_info->partner_link_info[partner_idx].vdev_id =
964 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
965 wlan_crypto_free_vdev_key(wlan_vdev_list[i]);
966 mlo_prepare_and_send_connect(
967 wlan_vdev_list[i],
968 *ml_parnter_info,
969 ml_parnter_info->partner_link_info[partner_idx],
970 ssid, &resp->mld_addr);
971 mlo_update_connected_links(wlan_vdev_list[i], 1);
972 partner_idx++;
973 mlo_release_vdev_ref(wlan_vdev_list[i]);
974 }
975 }
976 #else
mlo_send_link_connect(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * resp)977 static void mlo_send_link_connect(struct wlan_objmgr_vdev *vdev,
978 struct wlan_cm_connect_resp *resp)
979 {
980 struct wlan_ssid ssid = {0};
981 uint8_t i = 0;
982 uint8_t j = 0;
983 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
984 struct mlo_partner_info *ml_parnter_info = &resp->ml_parnter_info;
985
986 if (!ml_parnter_info->num_partner_links) {
987 mlo_err("No partner info in connect resp");
988 return;
989 }
990
991 mlo_dev_lock_acquire(mlo_dev_ctx);
992 if (!wlan_cm_is_vdev_connected(vdev)) {
993 mlo_dev_lock_release(mlo_dev_ctx);
994 return;
995 }
996
997 for (j = 0; j < ml_parnter_info->num_partner_links; j++) {
998 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
999 if (!mlo_dev_ctx->wlan_vdev_list[i])
1000 continue;
1001 /*
1002 * mlo_connect: update wlan_connected_links bitmap from
1003 * assoc resp parsing
1004 */
1005 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
1006 if (wlan_cm_is_vdev_disconnected(
1007 mlo_dev_ctx->wlan_vdev_list[i])) {
1008 if (mlo_dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id
1009 == ml_parnter_info->partner_link_info[j].link_id) {
1010 wlan_vdev_mlme_get_ssid(
1011 vdev, ssid.ssid,
1012 &ssid.length);
1013 mlo_prepare_and_send_connect(
1014 mlo_dev_ctx->wlan_vdev_list[i],
1015 *ml_parnter_info,
1016 ml_parnter_info->partner_link_info[j],
1017 ssid, NULL);
1018 mlo_dev_lock_release(mlo_dev_ctx);
1019 return;
1020 }
1021 }
1022 }
1023 }
1024 }
1025 mlo_dev_lock_release(mlo_dev_ctx);
1026 }
1027 #endif
1028
1029 void
mlo_update_connected_links_bmap(struct wlan_mlo_dev_context * mlo_dev_ctx,struct mlo_partner_info ml_parnter_info)1030 mlo_update_connected_links_bmap(struct wlan_mlo_dev_context *mlo_dev_ctx,
1031 struct mlo_partner_info ml_parnter_info)
1032 {
1033 uint8_t i = 0;
1034 uint8_t j = 0;
1035
1036 if (!mlo_dev_ctx) {
1037 mlo_err("ML dev ctx is NULL");
1038 return;
1039 }
1040
1041 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1042 if (!mlo_dev_ctx->wlan_vdev_list[i])
1043 continue;
1044
1045 for (j = 0; j < ml_parnter_info.num_partner_links; j++) {
1046 if (wlan_vdev_get_link_id(mlo_dev_ctx->wlan_vdev_list[i]) ==
1047 ml_parnter_info.partner_link_info[j].link_id)
1048 mlo_update_connected_links(
1049 mlo_dev_ctx->wlan_vdev_list[i], 1);
1050 }
1051 }
1052 }
1053
mlo_clear_connected_links_bmap(struct wlan_objmgr_vdev * vdev)1054 void mlo_clear_connected_links_bmap(struct wlan_objmgr_vdev *vdev)
1055 {
1056 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1057 struct wlan_mlo_sta *sta_ctx = NULL;
1058
1059 if (!vdev)
1060 return;
1061
1062 mlo_dev_ctx = vdev->mlo_dev_ctx;
1063 if (!mlo_dev_ctx)
1064 return;
1065
1066 sta_ctx = mlo_dev_ctx->sta_ctx;
1067 if (!sta_ctx)
1068 return;
1069
1070 qdf_mem_zero(sta_ctx->wlan_connected_links,
1071 sizeof(sta_ctx->wlan_connected_links));
1072 }
1073
ml_activate_disconnect_req_sched_cb(struct scheduler_msg * msg)1074 static QDF_STATUS ml_activate_disconnect_req_sched_cb(struct scheduler_msg *msg)
1075 {
1076 struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1077
1078 if (!vdev) {
1079 mlme_err("Null input vdev");
1080 return QDF_STATUS_E_INVAL;
1081 }
1082
1083 mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
1084 REASON_UNSPEC_FAILURE, NULL);
1085
1086 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1087 return QDF_STATUS_SUCCESS;
1088 }
1089
ml_activate_disconnect_req_flush_cb(struct scheduler_msg * msg)1090 static QDF_STATUS ml_activate_disconnect_req_flush_cb(struct scheduler_msg *msg)
1091 {
1092 struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1093
1094 if (!vdev) {
1095 mlme_err("Null input vdev");
1096 return QDF_STATUS_E_INVAL;
1097 }
1098
1099 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1100 return QDF_STATUS_SUCCESS;
1101 }
1102
ml_activate_pend_disconn_req_cb(struct scheduler_msg * msg)1103 static QDF_STATUS ml_activate_pend_disconn_req_cb(struct scheduler_msg *msg)
1104 {
1105 struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1106 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1107 struct wlan_mlo_sta *sta_ctx = NULL;
1108
1109 if (!vdev) {
1110 mlme_err("Null input vdev");
1111 return QDF_STATUS_E_INVAL;
1112 }
1113
1114 mlo_dev_ctx = vdev->mlo_dev_ctx;
1115 sta_ctx = mlo_dev_ctx->sta_ctx;
1116 if (!sta_ctx || !sta_ctx->disconn_req)
1117 goto release_ref;
1118
1119 mlo_disconnect_req(vdev, sta_ctx->disconn_req->source,
1120 sta_ctx->disconn_req->reason_code,
1121 &sta_ctx->disconn_req->bssid, false);
1122
1123 qdf_mem_free(sta_ctx->disconn_req);
1124 sta_ctx->disconn_req = NULL;
1125
1126 release_ref:
1127 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1128
1129 return QDF_STATUS_SUCCESS;
1130 }
1131
ml_activate_pend_disconn_req_flush_cb(struct scheduler_msg * msg)1132 static QDF_STATUS ml_activate_pend_disconn_req_flush_cb(
1133 struct scheduler_msg *msg)
1134 {
1135 struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1136
1137 if (!vdev) {
1138 mlme_err("Null input vdev");
1139 return QDF_STATUS_E_INVAL;
1140 }
1141
1142 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1143 return QDF_STATUS_SUCCESS;
1144 }
1145
1146 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1147 static inline
mlo_post_disconnect_msg(struct scheduler_msg * msg)1148 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
1149 {
1150 return scheduler_post_message(
1151 QDF_MODULE_ID_OS_IF,
1152 QDF_MODULE_ID_SCAN,
1153 QDF_MODULE_ID_OS_IF,
1154 msg);
1155 }
1156 #else
1157 static inline
mlo_post_disconnect_msg(struct scheduler_msg * msg)1158 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
1159 {
1160 return scheduler_post_message(
1161 QDF_MODULE_ID_MLME,
1162 QDF_MODULE_ID_MLME,
1163 QDF_MODULE_ID_MLME,
1164 msg);
1165 }
1166 #endif
1167
mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * rsp)1168 void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev,
1169 struct wlan_cm_connect_resp *rsp)
1170 {
1171 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1172 struct scheduler_msg msg = {0};
1173 QDF_STATUS ret;
1174 struct wlan_objmgr_vdev *assoc_vdev;
1175
1176 if (!mlo_dev_ctx) {
1177 mlo_err("ML dev ctx is NULL");
1178 return;
1179 }
1180
1181 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
1182 if (!assoc_vdev) {
1183 mlo_err("Assoc Vdev is NULL");
1184 return;
1185 }
1186
1187 if (vdev != assoc_vdev) {
1188 mlo_update_connected_links(vdev, 0);
1189 if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
1190 rsp->reason == CM_HW_MODE_FAILURE ||
1191 rsp->reason == CM_SER_FAILURE) {
1192 ret = wlan_objmgr_vdev_try_get_ref(
1193 assoc_vdev, WLAN_MLO_MGR_ID);
1194 if (QDF_IS_STATUS_ERROR(ret)) {
1195 mlo_err("Failed to get ref vdev_id %d",
1196 wlan_vdev_get_id(assoc_vdev));
1197 return;
1198 }
1199 /* Since these failures happen in same context. use
1200 * scheduler to avoid deadlock by deferring context
1201 */
1202 msg.bodyptr = assoc_vdev;
1203 msg.callback = ml_activate_disconnect_req_sched_cb;
1204 msg.flush_callback =
1205 ml_activate_disconnect_req_flush_cb;
1206 ret = mlo_post_disconnect_msg(&msg);
1207 if (QDF_IS_STATUS_ERROR(ret)) {
1208 wlan_objmgr_vdev_release_ref(
1209 assoc_vdev,
1210 WLAN_MLO_MGR_ID);
1211 return;
1212 }
1213 } else {
1214 mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
1215 REASON_UNSPEC_FAILURE, NULL);
1216 }
1217 }
1218 }
1219
mlo_handle_pending_disconnect(struct wlan_objmgr_vdev * vdev)1220 void mlo_handle_pending_disconnect(struct wlan_objmgr_vdev *vdev)
1221 {
1222 struct scheduler_msg msg = {0};
1223 QDF_STATUS ret;
1224
1225 ret = wlan_objmgr_vdev_try_get_ref(
1226 vdev, WLAN_MLO_MGR_ID);
1227 if (QDF_IS_STATUS_ERROR(ret)) {
1228 mlo_err("Failed to get ref vdev_id %d",
1229 wlan_vdev_get_id(vdev));
1230 return;
1231 }
1232
1233 msg.bodyptr = vdev;
1234 msg.callback = ml_activate_pend_disconn_req_cb;
1235 msg.flush_callback =
1236 ml_activate_pend_disconn_req_flush_cb;
1237 ret = mlo_post_disconnect_msg(&msg);
1238 if (QDF_IS_STATUS_ERROR(ret)) {
1239 mlo_err("Failed to post scheduler msg");
1240 wlan_objmgr_vdev_release_ref(
1241 vdev,
1242 WLAN_MLO_MGR_ID);
1243 QDF_BUG(0);
1244 return;
1245 }
1246 }
1247
1248 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1249 static bool
mlo_sta_ignore_link_connect_fail(struct wlan_objmgr_vdev * vdev)1250 mlo_sta_ignore_link_connect_fail(struct wlan_objmgr_vdev *vdev)
1251 {
1252 if (wlan_cm_is_vdev_disconnected(vdev)) {
1253 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
1254 return false;
1255 else
1256 return true;
1257 }
1258
1259 return false;
1260 }
1261 #else
1262 static inline bool
mlo_sta_ignore_link_connect_fail(struct wlan_objmgr_vdev * vdev)1263 mlo_sta_ignore_link_connect_fail(struct wlan_objmgr_vdev *vdev)
1264 {
1265 return false;
1266 }
1267 #endif
1268
mlo_sta_link_connect_notify(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * rsp)1269 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
1270 struct wlan_cm_connect_resp *rsp)
1271 {
1272 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1273 struct wlan_mlo_sta *sta_ctx = NULL;
1274
1275 if (mlo_dev_ctx) {
1276 sta_ctx = mlo_dev_ctx->sta_ctx;
1277 } else {
1278 mlo_debug_rl("mlo_dev_ctx is NULL");
1279 return;
1280 }
1281
1282 if (sta_ctx && sta_ctx->disconn_req) {
1283 mlo_debug("Handle pending disocnnect for vdev %d",
1284 wlan_vdev_get_id(vdev));
1285 mlo_handle_pending_disconnect(vdev);
1286 return;
1287 }
1288
1289 if (wlan_cm_is_link_switch_connect_resp(rsp)) {
1290 mlo_info("Skip for link switch connect request");
1291 return;
1292 }
1293
1294 if (mlo_sta_ignore_link_connect_fail(vdev))
1295 return;
1296
1297 if (wlan_cm_is_vdev_disconnected(vdev))
1298 mlo_free_copied_conn_req(sta_ctx);
1299
1300 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1301 mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev));
1302 if (wlan_cm_is_vdev_disconnected(vdev)) {
1303 mlo_handle_sta_link_connect_failure(vdev, rsp);
1304 return;
1305 } else if (!wlan_cm_is_vdev_connected(vdev)) {
1306 /* If vdev is not in disconnected or connected state,
1307 * then the event is received due to connect req being
1308 * flushed. Hence, ignore this event
1309 */
1310 return;
1311 }
1312
1313 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) && sta_ctx) {
1314 if (sta_ctx->assoc_rsp.ptr) {
1315 qdf_mem_free(sta_ctx->assoc_rsp.ptr);
1316 sta_ctx->assoc_rsp.ptr = NULL;
1317 }
1318 sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len;
1319 sta_ctx->assoc_rsp.ptr =
1320 qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len);
1321 if (!sta_ctx->assoc_rsp.ptr) {
1322 QDF_ASSERT(0);
1323 return;
1324 }
1325 if (rsp->connect_ies.assoc_rsp.ptr)
1326 qdf_mem_copy(sta_ctx->assoc_rsp.ptr,
1327 rsp->connect_ies.assoc_rsp.ptr,
1328 rsp->connect_ies.assoc_rsp.len);
1329 sta_ctx->ml_partner_info = rsp->ml_parnter_info;
1330 /* Update connected_links_bmap for all vdev taking
1331 * part in association
1332 */
1333 mlo_update_connected_links(vdev, 1);
1334 mlo_update_connected_links_bmap(mlo_dev_ctx,
1335 rsp->ml_parnter_info);
1336 }
1337 mlo_send_link_connect(vdev, rsp);
1338 }
1339 }
1340
1341 /**
1342 * mlo_send_link_disconnect_sync- Issue sync the disconnect request on MLD links
1343 *
1344 * @mlo_dev_ctx: pointer to mlo dev context
1345 * @source: disconnect source
1346 * @reason_code: disconnect reason
1347 * @bssid: bssid of AP to disconnect, can be null if not known
1348 *
1349 * Return: QDF_STATUS
1350 */
1351 static QDF_STATUS
mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context * mlo_dev_ctx,enum wlan_cm_source source,enum wlan_reason_code reason_code,struct qdf_mac_addr * bssid)1352 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
1353 enum wlan_cm_source source,
1354 enum wlan_reason_code reason_code,
1355 struct qdf_mac_addr *bssid)
1356 {
1357 uint8_t i;
1358 struct wlan_objmgr_vdev *sync_vdev =
1359 mlo_get_assoc_link_vdev(mlo_dev_ctx);
1360
1361 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1362 if (!mlo_dev_ctx->wlan_vdev_list[i] ||
1363 mlo_dev_ctx->wlan_vdev_list[i] == sync_vdev) {
1364 continue;
1365 }
1366
1367 /**
1368 * If the assoc vdev isn't present, use the first link dev as
1369 * sync candidate.
1370 */
1371 if (!sync_vdev) {
1372 sync_vdev = mlo_dev_ctx->wlan_vdev_list[i];
1373 continue;
1374 }
1375
1376 /**
1377 * To initiate disconnect on all links at once, no need to use
1378 * sync API for all link vdevs.
1379 */
1380 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
1381 source, reason_code, NULL);
1382 }
1383
1384 if (sync_vdev)
1385 wlan_cm_disconnect_sync(sync_vdev, source, reason_code);
1386
1387 return QDF_STATUS_SUCCESS;
1388 }
1389
mlo_disconnect_req(struct wlan_objmgr_vdev * vdev,enum wlan_cm_source source,enum wlan_reason_code reason_code,struct qdf_mac_addr * bssid,bool validate_req)1390 static QDF_STATUS mlo_disconnect_req(struct wlan_objmgr_vdev *vdev,
1391 enum wlan_cm_source source,
1392 enum wlan_reason_code reason_code,
1393 struct qdf_mac_addr *bssid,
1394 bool validate_req)
1395 {
1396 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1397 struct wlan_mlo_sta *sta_ctx = NULL;
1398 QDF_STATUS status = QDF_STATUS_SUCCESS;
1399
1400 if (!vdev)
1401 return QDF_STATUS_E_FAILURE;
1402
1403 mlo_dev_ctx = vdev->mlo_dev_ctx;
1404 if (mlo_dev_ctx)
1405 sta_ctx = mlo_dev_ctx->sta_ctx;
1406 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1407 mlo_dev_lock_acquire(mlo_dev_ctx);
1408 if (sta_ctx && sta_ctx->connect_req &&
1409 source != CM_INTERNAL_DISCONNECT) {
1410 wlan_cm_free_connect_req(sta_ctx->connect_req);
1411 sta_ctx->connect_req = NULL;
1412 }
1413
1414 if (validate_req) {
1415 status = mlo_validate_disconn_req(vdev, source,
1416 reason_code, bssid);
1417 if (QDF_IS_STATUS_ERROR(status)) {
1418 mlo_err("Connect in progress, deferring disconnect");
1419 mlo_dev_lock_release(mlo_dev_ctx);
1420 return status;
1421 }
1422 }
1423
1424 mlo_dev_lock_release(mlo_dev_ctx);
1425
1426 status = mlo_send_link_disconnect(vdev, source,
1427 reason_code, bssid);
1428 if (QDF_IS_STATUS_SUCCESS(status))
1429 mlo_free_copied_conn_req(sta_ctx);
1430
1431 return status;
1432 }
1433 status = wlan_cm_disconnect(vdev, source,
1434 reason_code, NULL);
1435 if (QDF_IS_STATUS_SUCCESS(status))
1436 mlo_free_copied_conn_req(sta_ctx);
1437
1438 return status;
1439 }
1440
mlo_disconnect(struct wlan_objmgr_vdev * vdev,enum wlan_cm_source source,enum wlan_reason_code reason_code,struct qdf_mac_addr * bssid)1441 QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
1442 enum wlan_cm_source source,
1443 enum wlan_reason_code reason_code,
1444 struct qdf_mac_addr *bssid)
1445 {
1446 return mlo_disconnect_req(vdev, source, reason_code, bssid, true);
1447 }
1448
1449 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1450 /**
1451 * mlo_wait_for_mld_disconnection - API to wait for sync mld disconnection
1452 * @vdev: pointer to vdev
1453 *
1454 * Return: none
1455 */
1456 static inline
mlo_wait_for_mld_disconnection(struct wlan_objmgr_vdev * vdev)1457 void mlo_wait_for_mld_disconnection(struct wlan_objmgr_vdev *vdev)
1458 { }
1459 #else
1460 #define ML_DISCONNECT_CMD_TIMEOUT 1000
1461 #define ML_DISCONNECT_CMD_TIMEOUT_CNT 30 /* 30*1000 ms */
1462
mlo_wait_for_mld_disconnection(struct wlan_objmgr_vdev * vdev)1463 static void mlo_wait_for_mld_disconnection(struct wlan_objmgr_vdev *vdev)
1464 {
1465 int waitcnt = 0;
1466 qdf_event_t wait_event;
1467
1468 qdf_mem_zero(&wait_event, sizeof(wait_event));
1469 qdf_event_create(&wait_event);
1470 qdf_event_reset(&wait_event);
1471
1472 while (!mlo_is_mld_disconnected(vdev) &&
1473 waitcnt < ML_DISCONNECT_CMD_TIMEOUT_CNT) {
1474 qdf_wait_single_event(&wait_event, ML_DISCONNECT_CMD_TIMEOUT);
1475 waitcnt++;
1476 }
1477 qdf_event_destroy(&wait_event);
1478 }
1479 #endif
mlo_sync_disconnect(struct wlan_objmgr_vdev * vdev,enum wlan_cm_source source,enum wlan_reason_code reason_code,struct qdf_mac_addr * bssid)1480 QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev,
1481 enum wlan_cm_source source,
1482 enum wlan_reason_code reason_code,
1483 struct qdf_mac_addr *bssid)
1484 {
1485 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1486 struct wlan_mlo_sta *sta_ctx = NULL;
1487 QDF_STATUS status = QDF_STATUS_SUCCESS;
1488
1489 if (!vdev)
1490 return QDF_STATUS_E_FAILURE;
1491
1492 mlo_dev_ctx = vdev->mlo_dev_ctx;
1493 if (mlo_dev_ctx)
1494 sta_ctx = mlo_dev_ctx->sta_ctx;
1495 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1496 if (sta_ctx && sta_ctx->connect_req) {
1497 wlan_cm_free_connect_req(sta_ctx->connect_req);
1498 sta_ctx->connect_req = NULL;
1499 }
1500
1501 status = mlo_validate_disconn_req(vdev, source,
1502 reason_code, bssid);
1503 if (QDF_IS_STATUS_ERROR(status)) {
1504 mlo_err("Connect in progress, deferring disconnect");
1505 return status;
1506 }
1507
1508 status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source,
1509 reason_code, bssid);
1510 if (QDF_IS_STATUS_SUCCESS(status)) {
1511 mlo_free_copied_conn_req(sta_ctx);
1512 mlo_wait_for_mld_disconnection(vdev);
1513 }
1514
1515 return status;
1516 }
1517 status = wlan_cm_disconnect_sync(vdev, source,
1518 reason_code);
1519 if (QDF_IS_STATUS_SUCCESS(status))
1520 mlo_free_copied_conn_req(sta_ctx);
1521
1522 return status;
1523 }
1524
1525 /**
1526 * mlo_handle_disconnect_resp- Issue desired actions on partner link vdev
1527 *
1528 * @vdev: pointer to vdev
1529 * @resp: disconnect resp
1530 *
1531 * Return: none
1532 */
1533 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1534 static
mlo_handle_disconnect_resp(struct wlan_objmgr_vdev * vdev,struct wlan_cm_discon_rsp * resp)1535 void mlo_handle_disconnect_resp(struct wlan_objmgr_vdev *vdev,
1536 struct wlan_cm_discon_rsp *resp)
1537 {
1538 /* If it is secondary link then delete vdev object from mlo device. */
1539 enum wlan_cm_source source;
1540 enum wlan_reason_code reason_code;
1541 uint8_t i = 0;
1542 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
1543 uint16_t vdev_count = 0;
1544
1545 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
1546 for (i = 0; i < vdev_count; i++) {
1547 if (wlan_cm_is_vdev_connected(wlan_vdev_list[i])) {
1548 if (wlan_vdev_mlme_is_mlo_link_vdev(
1549 wlan_vdev_list[i])) {
1550 source = resp->req.req.source;
1551 reason_code = resp->req.req.reason_code;
1552 wlan_cm_disconnect(
1553 wlan_vdev_list[i],
1554 source, reason_code, NULL);
1555 }
1556 }
1557 mlo_release_vdev_ref(wlan_vdev_list[i]);
1558 }
1559 }
1560 #else
1561 static
mlo_handle_disconnect_resp(struct wlan_objmgr_vdev * vdev,struct wlan_cm_discon_rsp * resp)1562 void mlo_handle_disconnect_resp(struct wlan_objmgr_vdev *vdev,
1563 struct wlan_cm_discon_rsp *resp)
1564 { }
1565
ml_activate_connect_req_sched_cb(struct scheduler_msg * msg)1566 static QDF_STATUS ml_activate_connect_req_sched_cb(struct scheduler_msg *msg)
1567 {
1568 struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1569 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
1570 struct wlan_mlo_sta *sta_ctx = NULL;
1571 uint8_t i = 0;
1572 struct mlo_partner_info partner_info;
1573 struct mlo_link_info partner_link_info;
1574 struct wlan_objmgr_vdev *tmp_vdev;
1575
1576 if (!vdev) {
1577 mlme_err("Null input vdev");
1578 return QDF_STATUS_E_INVAL;
1579 }
1580
1581 mlo_dev_ctx = vdev->mlo_dev_ctx;
1582 if (!mlo_dev_ctx) {
1583 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1584 return QDF_STATUS_E_INVAL;
1585 }
1586
1587 sta_ctx = mlo_dev_ctx->sta_ctx;
1588 if (!sta_ctx || !sta_ctx->connect_req) {
1589 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1590 return QDF_STATUS_E_INVAL;
1591 }
1592
1593 if (sta_ctx->connect_req->ml_parnter_info.num_partner_links) {
1594 partner_info = sta_ctx->connect_req->ml_parnter_info;
1595 wlan_vdev_mlme_set_mlo_vdev(vdev);
1596 wlan_vdev_mlme_clear_mlo_link_vdev(vdev);
1597 mlo_clear_connect_req_links_bmap(vdev);
1598 mlo_update_connect_req_links(vdev, 1);
1599 for (i = 0; i < partner_info.num_partner_links; i++) {
1600 partner_link_info = partner_info.partner_link_info[i];
1601 tmp_vdev = mlo_get_ml_vdev_by_mac(
1602 vdev,
1603 &partner_link_info.link_addr);
1604 if (tmp_vdev) {
1605 mlo_update_connect_req_links(tmp_vdev, 1);
1606 wlan_vdev_mlme_set_mlo_vdev(tmp_vdev);
1607 wlan_vdev_mlme_set_mlo_link_vdev(tmp_vdev);
1608 wlan_vdev_set_link_id(
1609 tmp_vdev,
1610 partner_link_info.link_id);
1611 }
1612 }
1613 }
1614
1615 mlo_connect(vdev, sta_ctx->connect_req);
1616 wlan_cm_free_connect_req(sta_ctx->connect_req);
1617 sta_ctx->connect_req = NULL;
1618
1619 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1620 return QDF_STATUS_SUCCESS;
1621 }
1622
ml_activate_connect_req_flush_cb(struct scheduler_msg * msg)1623 static QDF_STATUS ml_activate_connect_req_flush_cb(struct scheduler_msg *msg)
1624 {
1625 struct wlan_objmgr_vdev *vdev = msg->bodyptr;
1626
1627 if (!vdev) {
1628 mlme_err("Null input vdev");
1629 return QDF_STATUS_E_INVAL;
1630 }
1631
1632 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1633 return QDF_STATUS_SUCCESS;
1634 }
1635 #endif
1636
1637 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1638 static inline
mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev * vdev)1639 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
1640 { }
1641 #else
1642 static inline
mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev * vdev)1643 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
1644 {
1645 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1646 struct scheduler_msg msg = {0};
1647 QDF_STATUS ret;
1648 struct wlan_mlo_sta *sta_ctx = NULL;
1649
1650 if (!mlo_dev_ctx) {
1651 mlo_err("ML dev ctx is null");
1652 return;
1653 }
1654 sta_ctx = mlo_dev_ctx->sta_ctx;
1655 ret = wlan_objmgr_vdev_try_get_ref(
1656 vdev,
1657 WLAN_MLO_MGR_ID);
1658 if (QDF_IS_STATUS_ERROR(ret)) {
1659 wlan_cm_free_connect_req(sta_ctx->connect_req);
1660 sta_ctx->connect_req = NULL;
1661 return;
1662 }
1663 msg.bodyptr = vdev;
1664 msg.callback = ml_activate_connect_req_sched_cb;
1665 msg.flush_callback = ml_activate_connect_req_flush_cb;
1666
1667 ret = scheduler_post_message(QDF_MODULE_ID_MLME,
1668 QDF_MODULE_ID_MLME,
1669 QDF_MODULE_ID_MLME, &msg);
1670 if (QDF_IS_STATUS_ERROR(ret)) {
1671 wlan_cm_free_connect_req(sta_ctx->connect_req);
1672 sta_ctx->connect_req = NULL;
1673 wlan_objmgr_vdev_release_ref(vdev,
1674 WLAN_MLO_MGR_ID);
1675 return;
1676 }
1677 }
1678 #endif
1679
mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev * vdev,struct wlan_cm_discon_rsp * resp)1680 void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev,
1681 struct wlan_cm_discon_rsp *resp)
1682 {
1683 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1684 struct wlan_mlo_sta *sta_ctx = NULL;
1685 struct wlan_objmgr_vdev *assoc_vdev = NULL;
1686
1687 if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev)))
1688 return;
1689
1690 sta_ctx = mlo_dev_ctx->sta_ctx;
1691 if (!sta_ctx)
1692 return;
1693
1694 if (!wlan_cm_is_vdev_disconnected(vdev))
1695 return;
1696
1697 mlo_update_connected_links(vdev, 0);
1698 if (mlo_is_mld_disconnected(vdev)) {
1699 if (sta_ctx->connect_req) {
1700 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
1701 if (!assoc_vdev)
1702 return;
1703 mlo_sta_link_handle_pending_connect(assoc_vdev);
1704 }
1705 }
1706
1707 if (!wlan_cm_is_link_switch_disconnect_resp(resp))
1708 mlo_handle_disconnect_resp(vdev, resp);
1709 }
1710
mlo_is_mld_sta(struct wlan_objmgr_vdev * vdev)1711 bool mlo_is_mld_sta(struct wlan_objmgr_vdev *vdev)
1712 {
1713 if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) &&
1714 wlan_vdev_mlme_is_mlo_vdev(vdev))
1715 return true;
1716
1717 return false;
1718 }
1719
1720 qdf_export_symbol(mlo_is_mld_sta);
1721 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1722 struct wlan_objmgr_vdev *
mlo_get_ml_vdev_by_mac(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * macaddr)1723 mlo_get_ml_vdev_by_mac(struct wlan_objmgr_vdev *vdev,
1724 struct qdf_mac_addr *macaddr)
1725 {
1726 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1727 uint8_t i = 0;
1728
1729 if (!mlo_dev_ctx)
1730 return NULL;
1731
1732 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
1733 if (!mlo_dev_ctx->wlan_vdev_list[i])
1734 continue;
1735
1736 if(qdf_mem_cmp(macaddr,
1737 wlan_vdev_mlme_get_macaddr(mlo_dev_ctx->wlan_vdev_list[i]),
1738 QDF_MAC_ADDR_SIZE) == 0) {
1739 return mlo_dev_ctx->wlan_vdev_list[i];
1740 }
1741 }
1742 return NULL;
1743 }
1744 #endif
1745
1746 qdf_freq_t
mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev * pdev,struct qdf_mac_addr * bssid)1747 mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev *pdev,
1748 struct qdf_mac_addr *bssid)
1749 {
1750 struct scan_filter *scan_filter;
1751 int8_t ch_freq = 0;
1752 qdf_list_t *list = NULL;
1753 struct scan_cache_node *first_node = NULL;
1754 qdf_list_node_t *cur_node = NULL;
1755
1756 scan_filter = qdf_mem_malloc(sizeof(*scan_filter));
1757 if (!scan_filter)
1758 return ch_freq;
1759
1760 scan_filter->num_of_bssid = 1;
1761 qdf_mem_copy(scan_filter->bssid_list[0].bytes,
1762 bssid, sizeof(struct qdf_mac_addr));
1763 list = wlan_scan_get_result(pdev, scan_filter);
1764 qdf_mem_free(scan_filter);
1765
1766 if (!list || (list && !qdf_list_size(list))) {
1767 mlo_debug("scan list empty");
1768 goto error;
1769 }
1770
1771 qdf_list_peek_front(list, &cur_node);
1772 first_node = qdf_container_of(cur_node,
1773 struct scan_cache_node,
1774 node);
1775 if (first_node && first_node->entry)
1776 ch_freq = first_node->entry->channel.chan_freq;
1777 error:
1778 if (list)
1779 wlan_scan_purge_results(list);
1780
1781 return ch_freq;
1782 }
1783
1784 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
1785 /**
1786 * mlo_get_reassoc_rsp() - To get reassoc response
1787 * @vdev: objmgr vdev
1788 * @reassoc_rsp_frame: reassoc rsp
1789 *
1790 * Return: NA
1791 */
1792 static
mlo_get_reassoc_rsp(struct wlan_objmgr_vdev * vdev,struct element_info ** reassoc_rsp_frame)1793 void mlo_get_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
1794 struct element_info **reassoc_rsp_frame)
1795 {
1796 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1797 struct wlan_mlo_sta *sta_ctx = NULL;
1798
1799 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx)
1800 return;
1801
1802 sta_ctx = mlo_dev_ctx->sta_ctx;
1803 if (!sta_ctx->copied_reassoc_rsp) {
1804 mlo_err("Reassoc rsp not present for vdev_id %d",
1805 wlan_vdev_get_id(vdev));
1806 *reassoc_rsp_frame = NULL;
1807 return;
1808 }
1809
1810 if (!sta_ctx->copied_reassoc_rsp->connect_ies.assoc_rsp.len ||
1811 !sta_ctx->copied_reassoc_rsp->connect_ies.assoc_rsp.ptr) {
1812 mlo_err("Reassoc Resp info empty vdev_id %d assoc len %d",
1813 wlan_vdev_get_id(vdev),
1814 sta_ctx->copied_reassoc_rsp->connect_ies.assoc_rsp.len);
1815 *reassoc_rsp_frame = NULL;
1816 return;
1817 }
1818
1819 *reassoc_rsp_frame =
1820 &sta_ctx->copied_reassoc_rsp->connect_ies.assoc_rsp;
1821 }
1822 #else
1823 static inline
mlo_get_reassoc_rsp(struct wlan_objmgr_vdev * vdev,struct element_info ** reassoc_rsp_frame)1824 void mlo_get_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
1825 struct element_info **reassoc_rsp_frame)
1826 {
1827 *reassoc_rsp_frame = NULL;
1828 }
1829 #endif
1830
mlo_get_assoc_rsp(struct wlan_objmgr_vdev * vdev,struct element_info * assoc_rsp_frame)1831 void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev,
1832 struct element_info *assoc_rsp_frame)
1833 {
1834 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
1835 struct wlan_mlo_sta *sta_ctx = NULL;
1836 struct element_info *mlo_reassoc_rsp = NULL;
1837
1838 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx)
1839 return;
1840
1841 sta_ctx = mlo_dev_ctx->sta_ctx;
1842 if (sta_ctx->assoc_rsp.len && sta_ctx->assoc_rsp.ptr) {
1843 *assoc_rsp_frame = sta_ctx->assoc_rsp;
1844 return;
1845 }
1846 mlo_get_reassoc_rsp(vdev, &mlo_reassoc_rsp);
1847 if (mlo_reassoc_rsp)
1848 *assoc_rsp_frame = *mlo_reassoc_rsp;
1849 }
1850
mlo_sta_save_quiet_status(struct wlan_mlo_dev_context * mlo_dev_ctx,uint8_t link_id,bool quiet_status)1851 QDF_STATUS mlo_sta_save_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
1852 uint8_t link_id,
1853 bool quiet_status)
1854 {
1855 struct wlan_mlo_sta *sta_ctx;
1856 int i;
1857 bool find_free_buffer = false;
1858 int free_idx;
1859
1860 if (!mlo_dev_ctx) {
1861 mlo_err("invalid mlo_dev_ctx");
1862 return QDF_STATUS_E_INVAL;
1863 }
1864
1865 mlo_dev_lock_acquire(mlo_dev_ctx);
1866 sta_ctx = mlo_dev_ctx->sta_ctx;
1867 if (!sta_ctx) {
1868 mlo_err("invalid sta_ctx");
1869 mlo_dev_lock_release(mlo_dev_ctx);
1870 return QDF_STATUS_E_INVAL;
1871 }
1872 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) {
1873 if (!sta_ctx->mlo_quiet_status[i].valid_status) {
1874 if (!find_free_buffer) {
1875 free_idx = i;
1876 find_free_buffer = true;
1877 }
1878 } else if (link_id == sta_ctx->mlo_quiet_status[i].link_id) {
1879 sta_ctx->mlo_quiet_status[i].quiet_status =
1880 quiet_status;
1881 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d quiet status update %d",
1882 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
1883 link_id, quiet_status);
1884 mlo_dev_lock_release(mlo_dev_ctx);
1885 return QDF_STATUS_SUCCESS;
1886 }
1887 }
1888 if (!find_free_buffer) {
1889 mlo_err("no free buffer for link id %d to save quiet_status",
1890 link_id);
1891 mlo_dev_lock_release(mlo_dev_ctx);
1892 return QDF_STATUS_E_INVAL;
1893 }
1894 sta_ctx->mlo_quiet_status[free_idx].quiet_status = quiet_status;
1895 sta_ctx->mlo_quiet_status[free_idx].link_id = link_id;
1896 sta_ctx->mlo_quiet_status[free_idx].valid_status = true;
1897
1898 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d in quiet status %d",
1899 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
1900 link_id, quiet_status);
1901 mlo_dev_lock_release(mlo_dev_ctx);
1902
1903 return QDF_STATUS_SUCCESS;
1904 }
1905
mlo_is_sta_in_quiet_status(struct wlan_mlo_dev_context * mlo_dev_ctx,uint8_t link_id)1906 bool mlo_is_sta_in_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
1907 uint8_t link_id)
1908 {
1909 struct wlan_mlo_sta *sta_ctx;
1910 int i;
1911 bool quiet_status = false;
1912
1913 if (!mlo_dev_ctx) {
1914 mlo_err("invalid mlo_dev_ctx");
1915 return quiet_status;
1916 }
1917
1918 mlo_dev_lock_acquire(mlo_dev_ctx);
1919 sta_ctx = mlo_dev_ctx->sta_ctx;
1920 if (!sta_ctx) {
1921 mlo_err("invalid sta_ctx");
1922 mlo_dev_lock_release(mlo_dev_ctx);
1923 return quiet_status;
1924 }
1925 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) {
1926 if (sta_ctx->mlo_quiet_status[i].valid_status &&
1927 link_id == sta_ctx->mlo_quiet_status[i].link_id) {
1928 quiet_status =
1929 sta_ctx->mlo_quiet_status[i].quiet_status;
1930 break;
1931 }
1932 }
1933 mlo_dev_lock_release(mlo_dev_ctx);
1934
1935 return quiet_status;
1936 }
1937
mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc * psoc,uint8_t * vdev_id_list,uint8_t num_mlo,uint8_t * mlo_idx,uint8_t affected_links,uint8_t * affected_list)1938 bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc,
1939 uint8_t *vdev_id_list,
1940 uint8_t num_mlo, uint8_t *mlo_idx,
1941 uint8_t affected_links,
1942 uint8_t *affected_list)
1943 {
1944 uint8_t i, j;
1945 struct wlan_objmgr_vdev *vdev;
1946 bool allowed = false;
1947
1948 for (i = 0; i < num_mlo; i++) {
1949 for (j = 0; j < affected_links; j++) {
1950 if (vdev_id_list[mlo_idx[i]] == affected_list[j])
1951 break;
1952 }
1953 if (j != affected_links)
1954 continue;
1955 /* find vdev not in affected_list */
1956 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
1957 psoc, vdev_id_list[mlo_idx[i]],
1958 WLAN_IF_MGR_ID);
1959 if (!vdev) {
1960 mlo_err("invalid vdev for id %d",
1961 vdev_id_list[mlo_idx[i]]);
1962 continue;
1963 }
1964
1965 /* for not affected vdev, check the vdev is in quiet or not*/
1966 allowed = !mlo_is_sta_in_quiet_status(
1967 vdev->mlo_dev_ctx, wlan_vdev_get_link_id(vdev));
1968 wlan_objmgr_vdev_release_ref(vdev, WLAN_IF_MGR_ID);
1969 if (allowed) {
1970 mlo_debug("vdev id %d link id %d is not in quiet, allow partner link to trigger inactivity",
1971 wlan_vdev_get_id(vdev),
1972 wlan_vdev_get_link_id(vdev));
1973 break;
1974 }
1975 }
1976
1977 return allowed;
1978 }
1979
mlo_is_sta_csa_synced(struct wlan_mlo_dev_context * mlo_dev_ctx,uint8_t link_id)1980 bool mlo_is_sta_csa_synced(struct wlan_mlo_dev_context *mlo_dev_ctx,
1981 uint8_t link_id)
1982 {
1983 struct wlan_mlo_sta *sta_ctx;
1984 int i;
1985 bool sta_csa_synced = false;
1986
1987 if (!mlo_dev_ctx) {
1988 mlo_err("invalid mlo_dev_ctx");
1989 return sta_csa_synced;
1990 }
1991
1992 mlo_dev_lock_acquire(mlo_dev_ctx);
1993 sta_ctx = mlo_dev_ctx->sta_ctx;
1994 if (!sta_ctx) {
1995 mlo_err("invalid sta_ctx");
1996 mlo_dev_lock_release(mlo_dev_ctx);
1997 return sta_csa_synced;
1998 }
1999 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
2000 if (link_id == sta_ctx->mlo_csa_param[i].link_id &&
2001 (sta_ctx->mlo_csa_param[i].valid_csa_param ||
2002 sta_ctx->mlo_csa_param[i].mlo_csa_synced)) {
2003 sta_csa_synced =
2004 sta_ctx->mlo_csa_param[i].mlo_csa_synced;
2005 break;
2006 }
2007 }
2008 mlo_dev_lock_release(mlo_dev_ctx);
2009
2010 return sta_csa_synced;
2011 }
2012
2013 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
mlo_sta_handle_csa_standby_link(struct wlan_mlo_dev_context * mlo_dev_ctx,uint8_t link_id,struct csa_offload_params * csa_param,struct wlan_objmgr_vdev * vdev)2014 QDF_STATUS mlo_sta_handle_csa_standby_link(
2015 struct wlan_mlo_dev_context *mlo_dev_ctx,
2016 uint8_t link_id,
2017 struct csa_offload_params *csa_param,
2018 struct wlan_objmgr_vdev *vdev)
2019 {
2020 QDF_STATUS status = QDF_STATUS_SUCCESS;
2021 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
2022 struct mlo_link_info *link_info;
2023 struct mlo_link_bss_params params = {0};
2024 struct wlan_objmgr_psoc *psoc;
2025 struct wlan_objmgr_pdev *pdev;
2026
2027 if (!mlo_dev_ctx) {
2028 mlo_err("invalid mlo_dev_ctx");
2029 return QDF_STATUS_E_NULL_VALUE;
2030 }
2031
2032 pdev = wlan_vdev_get_pdev(vdev);
2033 if (!pdev) {
2034 mlo_err("null pdev");
2035 return QDF_STATUS_E_NULL_VALUE;
2036 }
2037
2038 psoc = wlan_vdev_get_psoc(vdev);
2039 if (!psoc) {
2040 mlo_err("null psoc");
2041 return QDF_STATUS_E_NULL_VALUE;
2042 }
2043
2044 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
2045
2046 link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx, link_id);
2047 if (!link_info) {
2048 mlo_err("link info null");
2049 return QDF_STATUS_E_NULL_VALUE;
2050 }
2051
2052 if (link_info->vdev_id != WLAN_INVALID_VDEV_ID) {
2053 mlo_debug("vdev id %d link id %d ", link_info->vdev_id,
2054 link_id);
2055 return QDF_STATUS_E_NULL_VALUE;
2056 }
2057
2058 mlo_mgr_update_csa_link_info(pdev, mlo_dev_ctx, csa_param, link_id);
2059
2060 params.link_id = link_info->link_id;
2061 params.chan = qdf_mem_malloc(sizeof(struct wlan_channel));
2062 if (!params.chan) {
2063 mlo_err("no mem allocated");
2064 return QDF_STATUS_E_NOMEM;
2065 }
2066
2067 wlan_vdev_get_bss_peer_mld_mac(
2068 vdev,
2069 (struct qdf_mac_addr *)¶ms.ap_mld_mac[0]);
2070
2071 params.chan->ch_freq = link_info->link_chan_info->ch_freq;
2072 params.chan->ch_cfreq1 = link_info->link_chan_info->ch_cfreq1;
2073 params.chan->ch_cfreq2 = link_info->link_chan_info->ch_cfreq2;
2074 params.chan->ch_phymode = link_info->link_chan_info->ch_phymode;
2075
2076 mlo_debug("link id %d chan freq %d cfreq1 %d cfreq2 %d host phymode %d ap mld mac " QDF_MAC_ADDR_FMT,
2077 link_info->link_id, link_info->link_chan_info->ch_freq,
2078 link_info->link_chan_info->ch_cfreq1,
2079 link_info->link_chan_info->ch_cfreq2,
2080 link_info->link_chan_info->ch_phymode,
2081 QDF_MAC_ADDR_REF(¶ms.ap_mld_mac[0]));
2082
2083 if (!mlo_tx_ops->send_link_set_bss_params_cmd) {
2084 mlo_err("handler is not registered");
2085 qdf_mem_free(params.chan);
2086 return QDF_STATUS_E_NULL_VALUE;
2087 }
2088
2089 status = mlo_tx_ops->send_link_set_bss_params_cmd(psoc, ¶ms);
2090
2091 if (QDF_IS_STATUS_ERROR(status)) {
2092 mlo_err("failed to send link set bss request command to FW");
2093 qdf_mem_free(params.chan);
2094 return QDF_STATUS_E_NULL_VALUE;
2095 }
2096 qdf_mem_free(params.chan);
2097 return status;
2098 }
2099
mlo_sta_handle_link_reconfig_standby_link(struct wlan_objmgr_vdev * vdev,struct ml_rv_info * reconfig_info)2100 static void mlo_sta_handle_link_reconfig_standby_link(
2101 struct wlan_objmgr_vdev *vdev,
2102 struct ml_rv_info *reconfig_info)
2103 {
2104 struct vdev_mlme_obj *vdev_mlme;
2105
2106 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
2107 if (!vdev_mlme)
2108 return;
2109 if (vdev_mlme->ops &&
2110 vdev_mlme->ops->mlme_vdev_reconfig_notify_standby) {
2111 vdev_mlme->ops->mlme_vdev_reconfig_notify_standby(
2112 vdev_mlme,
2113 reconfig_info);
2114 }
2115 }
2116 #else
mlo_sta_handle_link_reconfig_standby_link(struct wlan_objmgr_vdev * vdev,struct ml_rv_info * reconfig_info)2117 static void mlo_sta_handle_link_reconfig_standby_link(
2118 struct wlan_objmgr_vdev *vdev,
2119 struct ml_rv_info *reconfig_info)
2120 {
2121 }
2122 #endif
2123
mlo_sta_csa_save_params(struct wlan_mlo_dev_context * mlo_dev_ctx,uint8_t link_id,struct csa_offload_params * csa_param)2124 QDF_STATUS mlo_sta_csa_save_params(struct wlan_mlo_dev_context *mlo_dev_ctx,
2125 uint8_t link_id,
2126 struct csa_offload_params *csa_param)
2127 {
2128 struct wlan_mlo_sta *sta_ctx;
2129 int i;
2130 bool find_free_buffer = false;
2131 int free_idx;
2132 QDF_STATUS status = QDF_STATUS_SUCCESS;
2133
2134 if (!mlo_dev_ctx) {
2135 mlo_err("invalid mlo_dev_ctx");
2136 status = QDF_STATUS_E_INVAL;
2137 goto done;
2138 }
2139
2140 mlo_dev_lock_acquire(mlo_dev_ctx);
2141 sta_ctx = mlo_dev_ctx->sta_ctx;
2142 if (!sta_ctx) {
2143 mlo_err("invalid sta_ctx");
2144 status = QDF_STATUS_E_INVAL;
2145 goto rel_lock;
2146 }
2147 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
2148 if (!sta_ctx->mlo_csa_param[i].valid_csa_param &&
2149 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
2150 if (!find_free_buffer) {
2151 free_idx = i;
2152 find_free_buffer = true;
2153 }
2154 } else if (link_id == sta_ctx->mlo_csa_param[i].link_id) {
2155 qdf_mem_copy(&sta_ctx->mlo_csa_param[i].csa_param,
2156 csa_param, sizeof(*csa_param));
2157 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d update csa",
2158 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
2159 link_id);
2160 goto rel_lock;
2161 }
2162 }
2163 if (!find_free_buffer) {
2164 mlo_err("no free buffer of csa param for link %d in sta_ctx",
2165 link_id);
2166 status = QDF_STATUS_E_INVAL;
2167 goto rel_lock;
2168 }
2169 qdf_mem_copy(&sta_ctx->mlo_csa_param[free_idx].csa_param,
2170 csa_param, sizeof(*csa_param));
2171 sta_ctx->mlo_csa_param[free_idx].link_id = link_id;
2172 sta_ctx->mlo_csa_param[free_idx].valid_csa_param = true;
2173 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d RX csa",
2174 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
2175 link_id);
2176
2177 rel_lock:
2178 mlo_dev_lock_release(mlo_dev_ctx);
2179
2180 done:
2181
2182 return status;
2183 }
2184
mlo_sta_up_active_notify(struct wlan_objmgr_vdev * vdev)2185 QDF_STATUS mlo_sta_up_active_notify(struct wlan_objmgr_vdev *vdev)
2186 {
2187 struct wlan_mlo_sta *sta_ctx;
2188 struct wlan_mlo_dev_context *mlo_dev_ctx;
2189 uint8_t link_id;
2190 int i;
2191 bool find_free_buffer = false;
2192 int free_idx;
2193 struct csa_offload_params csa_param;
2194 struct wlan_channel *chan;
2195 QDF_STATUS status = QDF_STATUS_SUCCESS;
2196
2197 if (!vdev) {
2198 mlo_err("invalid vdev");
2199 status = QDF_STATUS_E_INVAL;
2200 goto done;
2201 }
2202 link_id = wlan_vdev_get_link_id(vdev);
2203 mlo_dev_ctx = vdev->mlo_dev_ctx;
2204 if (!mlo_dev_ctx) {
2205 mlo_err("invalid mlo_dev_ctx");
2206 status = QDF_STATUS_E_INVAL;
2207 goto done;
2208 }
2209 mlo_dev_lock_acquire(mlo_dev_ctx);
2210 sta_ctx = mlo_dev_ctx->sta_ctx;
2211 if (!sta_ctx) {
2212 mlo_err("invalid sta_ctx");
2213 status = QDF_STATUS_E_INVAL;
2214 goto rel_lock;
2215 }
2216
2217 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
2218 if (!sta_ctx->mlo_csa_param[i].valid_csa_param &&
2219 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
2220 if (!find_free_buffer) {
2221 free_idx = i;
2222 find_free_buffer = true;
2223 }
2224 } else if (link_id == sta_ctx->mlo_csa_param[i].link_id) {
2225 if (sta_ctx->mlo_csa_param[i].valid_csa_param &&
2226 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
2227 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " vdev id %d link id %d handle csa",
2228 QDF_MAC_ADDR_REF(
2229 mlo_dev_ctx->mld_addr.bytes),
2230 wlan_vdev_get_id(vdev), link_id);
2231 csa_param = sta_ctx->mlo_csa_param[i].csa_param;
2232 sta_ctx->mlo_csa_param[i].mlo_csa_synced = true;
2233 mlo_dev_lock_release(mlo_dev_ctx);
2234 chan = wlan_vdev_mlme_get_bss_chan(vdev);
2235 if (csa_param.csa_chan_freq && chan &&
2236 csa_param.csa_chan_freq != chan->ch_freq)
2237 mlo_mlme_handle_sta_csa_param(
2238 vdev, &csa_param);
2239 goto done;
2240 }
2241 sta_ctx->mlo_csa_param[i].mlo_csa_synced = true;
2242 goto rel_lock;
2243 }
2244 }
2245 if (!find_free_buffer) {
2246 mlo_err("no free buffer of csa param for link %d in sta_ctx",
2247 link_id);
2248 goto rel_lock;
2249 }
2250 sta_ctx->mlo_csa_param[free_idx].mlo_csa_synced = true;
2251 sta_ctx->mlo_csa_param[free_idx].link_id = link_id;
2252 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d UP Active",
2253 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
2254 link_id);
2255
2256 rel_lock:
2257 mlo_dev_lock_release(mlo_dev_ctx);
2258
2259 done:
2260
2261 return status;
2262 }
2263
mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev * vdev,struct csa_offload_params * csa_param)2264 bool mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev *vdev,
2265 struct csa_offload_params *csa_param)
2266 {
2267 struct wlan_mlo_sta *sta_ctx;
2268 struct wlan_mlo_dev_context *mlo_dev_ctx;
2269 uint8_t link_id;
2270 int i;
2271 bool handled = false;
2272
2273 if (!vdev) {
2274 mlo_err("invalid vdev");
2275 goto done;
2276 }
2277 link_id = wlan_vdev_get_link_id(vdev);
2278 mlo_dev_ctx = vdev->mlo_dev_ctx;
2279 if (!mlo_dev_ctx) {
2280 mlo_err("invalid mlo_dev_ctx");
2281 goto done;
2282 }
2283 mlo_dev_lock_acquire(mlo_dev_ctx);
2284 sta_ctx = mlo_dev_ctx->sta_ctx;
2285 if (!sta_ctx) {
2286 mlo_err("invalid sta_ctx");
2287 goto rel_lock;
2288 }
2289
2290 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
2291 if (link_id == sta_ctx->mlo_csa_param[i].link_id &&
2292 (sta_ctx->mlo_csa_param[i].valid_csa_param ||
2293 sta_ctx->mlo_csa_param[i].mlo_csa_synced))
2294 break;
2295 }
2296
2297 if (i >= QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param)) {
2298 mlo_debug("mlo csa synced does not happen before csa FW event");
2299 goto rel_lock;
2300 }
2301 if (!sta_ctx->mlo_csa_param[i].csa_offload_event_recvd) {
2302 sta_ctx->mlo_csa_param[i].csa_offload_event_recvd = true;
2303 if (sta_ctx->mlo_csa_param[i].valid_csa_param &&
2304 !qdf_mem_cmp(&sta_ctx->mlo_csa_param[i].csa_param,
2305 csa_param, sizeof(*csa_param)))
2306 handled = true;
2307 }
2308
2309 rel_lock:
2310 mlo_dev_lock_release(mlo_dev_ctx);
2311
2312 done:
2313
2314 return handled;
2315 }
2316
2317 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
mlo_internal_disconnect_links(struct wlan_objmgr_vdev * vdev)2318 void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev)
2319 {
2320 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
2321 struct wlan_mlo_sta *sta_ctx = NULL;
2322 uint8_t i;
2323 struct wlan_objmgr_vdev *assoc_vdev;
2324 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
2325 uint16_t vdev_count = 0;
2326
2327 if (!vdev)
2328 return;
2329
2330 if (!wlan_vdev_mlme_is_assoc_sta_vdev(vdev) &&
2331 !wlan_mlo_mgr_is_link_switch_on_assoc_vdev(vdev)) {
2332 mlo_debug("Not an assoc vdev, so ignore disconnect req");
2333 return;
2334 }
2335
2336 mlo_dev_ctx = vdev->mlo_dev_ctx;
2337 if (mlo_dev_ctx) {
2338 sta_ctx = mlo_dev_ctx->sta_ctx;
2339 } else {
2340 mlo_err("Invalid mlo_dev_ctx");
2341 return;
2342 }
2343
2344 if (sta_ctx) {
2345 mlo_free_copied_conn_req(sta_ctx);
2346 } else {
2347 mlo_err("Invalid sta_ctx");
2348 return;
2349 }
2350
2351 if (sta_ctx->connect_req) {
2352 wlan_cm_free_connect_req(sta_ctx->connect_req);
2353 sta_ctx->connect_req = NULL;
2354 }
2355
2356 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
2357 if (!assoc_vdev) {
2358 assoc_vdev = wlan_mlo_mgr_link_switch_get_assoc_vdev(vdev);
2359 if (!assoc_vdev) {
2360 mlo_debug("Couldn't get assoc vdev");
2361 return;
2362 }
2363 mlo_release_vdev_ref(assoc_vdev);
2364 }
2365
2366 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
2367 for (i = 0; i < vdev_count; i++) {
2368 if (wlan_vdev_list[i] != assoc_vdev &&
2369 (wlan_cm_is_vdev_connected(wlan_vdev_list[i]) ||
2370 wlan_cm_is_vdev_connecting(wlan_vdev_list[i]) ||
2371 wlan_cm_is_vdev_idle_due_to_link_switch(wlan_vdev_list[i])))
2372 wlan_cm_disconnect(wlan_vdev_list[i],
2373 CM_MLO_LINK_VDEV_DISCONNECT,
2374 REASON_UNSPEC_FAILURE,
2375 NULL);
2376 mlo_release_vdev_ref(wlan_vdev_list[i]);
2377 }
2378 }
2379 #else
mlo_internal_disconnect_links(struct wlan_objmgr_vdev * vdev)2380 void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev)
2381 {
2382 }
2383 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
2384
mlo_sta_get_vdev_list(struct wlan_objmgr_vdev * vdev,uint16_t * vdev_count,struct wlan_objmgr_vdev ** wlan_vdev_list)2385 void mlo_sta_get_vdev_list(struct wlan_objmgr_vdev *vdev, uint16_t *vdev_count,
2386 struct wlan_objmgr_vdev **wlan_vdev_list)
2387 {
2388 struct wlan_mlo_dev_context *dev_ctx;
2389 int i;
2390 QDF_STATUS status;
2391
2392 *vdev_count = 0;
2393
2394 if (!vdev || !vdev->mlo_dev_ctx) {
2395 mlo_err("Invalid input");
2396 return;
2397 }
2398
2399 dev_ctx = vdev->mlo_dev_ctx;
2400
2401 mlo_dev_lock_acquire(dev_ctx);
2402 *vdev_count = 0;
2403 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
2404 if (dev_ctx->wlan_vdev_list[i]) {
2405 status =
2406 wlan_objmgr_vdev_try_get_ref(dev_ctx->wlan_vdev_list[i],
2407 WLAN_MLO_MGR_ID);
2408 if (QDF_IS_STATUS_ERROR(status))
2409 break;
2410 wlan_vdev_list[*vdev_count] =
2411 dev_ctx->wlan_vdev_list[i];
2412 (*vdev_count) += 1;
2413 }
2414 }
2415 mlo_dev_lock_release(dev_ctx);
2416 }
2417
mlo_sta_vdev_get_reconfig_timer_state(struct wlan_objmgr_vdev * vdev)2418 bool mlo_sta_vdev_get_reconfig_timer_state(struct wlan_objmgr_vdev *vdev)
2419 {
2420 struct vdev_mlme_obj *vdev_mlme;
2421
2422 if (!vdev || !mlo_is_mld_sta(vdev))
2423 return false;
2424
2425 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
2426 if (!vdev_mlme) {
2427 mlo_err("vdev mlme is null");
2428 return false;
2429 }
2430
2431 return vdev_mlme->ml_reconfig_started;
2432 }
2433
mlo_sta_stop_reconfig_timer_by_vdev(struct wlan_objmgr_vdev * vdev)2434 void mlo_sta_stop_reconfig_timer_by_vdev(struct wlan_objmgr_vdev *vdev)
2435 {
2436 struct vdev_mlme_obj *vdev_mlme;
2437
2438 if (!vdev || !mlo_is_mld_sta(vdev))
2439 return;
2440
2441 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
2442 if (!vdev_mlme) {
2443 mlo_err("vdev mlme is null");
2444 return;
2445 }
2446
2447 if (!vdev_mlme->ml_reconfig_started)
2448 return;
2449
2450 qdf_timer_stop(&vdev_mlme->ml_reconfig_timer);
2451
2452 mlo_debug("vdev %d reconfig timer active to stop",
2453 wlan_vdev_get_id(vdev));
2454 vdev_mlme->ml_reconfig_started = false;
2455 }
2456
mlo_sta_stop_reconfig_timer(struct wlan_objmgr_vdev * vdev)2457 void mlo_sta_stop_reconfig_timer(struct wlan_objmgr_vdev *vdev)
2458 {
2459 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0};
2460 uint16_t vdev_count = 0;
2461 uint8_t i;
2462
2463 if (!vdev || !mlo_is_mld_sta(vdev))
2464 return;
2465
2466 mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
2467 if (!vdev_count) {
2468 mlo_err("vdev num 0 in mld dev");
2469 return;
2470 }
2471
2472 for (i = 0; i < vdev_count; i++) {
2473 if (!wlan_vdev_list[i]) {
2474 mlo_err("vdev is null in mld");
2475 goto release_ref;
2476 }
2477 mlo_sta_stop_reconfig_timer_by_vdev(wlan_vdev_list[i]);
2478 }
2479
2480 release_ref:
2481 for (i = 0; i < vdev_count; i++)
2482 mlo_release_vdev_ref(wlan_vdev_list[i]);
2483 }
2484
2485 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
mlo_defer_set_keys(struct wlan_objmgr_vdev * vdev,uint8_t link_id,bool value)2486 void mlo_defer_set_keys(struct wlan_objmgr_vdev *vdev,
2487 uint8_t link_id, bool value)
2488 {
2489 struct wlan_mlo_sta *sta_ctx;
2490 uint8_t link_iter;
2491
2492 if (!vdev || !vdev->mlo_dev_ctx)
2493 return;
2494
2495 sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
2496 if (!sta_ctx)
2497 return;
2498 if (value) {
2499 for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS;
2500 link_iter++) {
2501 if (sta_ctx->key_mgmt[link_iter].keys_saved &&
2502 sta_ctx->key_mgmt[link_iter].link_id == link_id)
2503 return;
2504 }
2505
2506 for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS;
2507 link_iter++) {
2508 if (!sta_ctx->key_mgmt[link_iter].keys_saved) {
2509 sta_ctx->key_mgmt[link_iter].link_id = link_id;
2510 sta_ctx->key_mgmt[link_iter].keys_saved = true;
2511 mlo_debug("set key link id %d value %d iter %d",
2512 link_id, value, link_iter);
2513 return;
2514 }
2515 }
2516 } else {
2517 for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS;
2518 link_iter++) {
2519 if (sta_ctx->key_mgmt[link_iter].link_id == link_id) {
2520 sta_ctx->key_mgmt[link_iter].keys_saved = false;
2521 mlo_debug("set key link id %d value %d iter %d",
2522 link_id, value, link_iter);
2523 return;
2524 }
2525 }
2526 }
2527 }
2528
mlo_is_set_key_defered(struct wlan_objmgr_vdev * vdev,uint8_t link_id)2529 bool mlo_is_set_key_defered(struct wlan_objmgr_vdev *vdev,
2530 uint8_t link_id)
2531 {
2532 struct wlan_mlo_sta *sta_ctx;
2533 uint8_t link_iter;
2534
2535 if (!vdev || !vdev->mlo_dev_ctx)
2536 return false;
2537
2538 sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
2539 if (!sta_ctx)
2540 return false;
2541
2542 for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS;
2543 link_iter++) {
2544 if (sta_ctx->key_mgmt[link_iter].link_id == link_id)
2545 return sta_ctx->key_mgmt[link_iter].keys_saved;
2546 }
2547 return false;
2548 }
2549 #endif
2550
2551 static uint16_t
mlo_get_bcn_interval_by_bssid(struct wlan_objmgr_pdev * pdev,uint8_t * bssid)2552 mlo_get_bcn_interval_by_bssid(struct wlan_objmgr_pdev *pdev,
2553 uint8_t *bssid)
2554 {
2555 struct scan_filter *scan_filter;
2556 uint16_t bcn_int = 0;
2557 qdf_list_t *list = NULL;
2558 struct scan_cache_node *first_node = NULL;
2559 qdf_list_node_t *cur_node = NULL;
2560
2561 scan_filter = qdf_mem_malloc(sizeof(*scan_filter));
2562 if (!scan_filter)
2563 return bcn_int;
2564
2565 scan_filter->num_of_bssid = 1;
2566 qdf_mem_copy(scan_filter->bssid_list[0].bytes,
2567 bssid, sizeof(struct qdf_mac_addr));
2568 list = wlan_scan_get_result(pdev, scan_filter);
2569 qdf_mem_free(scan_filter);
2570
2571 if (!list || (list && !qdf_list_size(list))) {
2572 mlo_debug("scan list empty");
2573 goto error;
2574 }
2575
2576 qdf_list_peek_front(list, &cur_node);
2577 first_node = qdf_container_of(cur_node,
2578 struct scan_cache_node,
2579 node);
2580 if (first_node && first_node->entry)
2581 bcn_int = first_node->entry->bcn_int;
2582 error:
2583 if (list)
2584 wlan_scan_purge_results(list);
2585
2586 return bcn_int;
2587 }
2588
2589 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE
2590 static QDF_STATUS
mlo_sta_handle_ptqm_migration(struct wlan_objmgr_vdev * removal_vdev)2591 mlo_sta_handle_ptqm_migration(struct wlan_objmgr_vdev *removal_vdev)
2592 {
2593 struct wlan_objmgr_peer *bss_peer;
2594
2595 if (!wlan_cm_is_vdev_connected(removal_vdev))
2596 return QDF_STATUS_E_INVAL;
2597
2598 bss_peer = wlan_vdev_get_bsspeer(removal_vdev);
2599 if (!bss_peer)
2600 return QDF_STATUS_E_INVAL;
2601
2602 /* Invoke migration only if the link being removed is the primary */
2603 if (wlan_mlo_peer_get_primary_peer_link_id(bss_peer)
2604 != wlan_vdev_get_link_id(removal_vdev))
2605 return QDF_STATUS_SUCCESS;
2606
2607 return wlan_mlo_set_ptqm_migration(removal_vdev, bss_peer->mlo_peer_ctx,
2608 false, WLAN_LINK_ID_INVALID, true);
2609 }
2610 #else
2611 static QDF_STATUS
mlo_sta_handle_ptqm_migration(struct wlan_objmgr_vdev * removal_vdev)2612 mlo_sta_handle_ptqm_migration(struct wlan_objmgr_vdev *removal_vdev)
2613 {
2614 return QDF_STATUS_SUCCESS;
2615 }
2616 #endif
2617
mlo_process_link_remove(struct wlan_objmgr_vdev * vdev,struct ml_rv_partner_link_info * link_info)2618 static void mlo_process_link_remove(struct wlan_objmgr_vdev *vdev,
2619 struct ml_rv_partner_link_info *link_info)
2620 {
2621 struct vdev_mlme_obj *vdev_mlme = NULL;
2622 struct wlan_objmgr_peer *bss_peer = NULL;
2623 uint16_t bcn_int = 0;
2624 uint16_t tbtt_count = 0;
2625 QDF_STATUS status;
2626
2627 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
2628 if (!vdev_mlme)
2629 return;
2630
2631 bss_peer = wlan_vdev_get_bsspeer(vdev);
2632 if (!bss_peer)
2633 return;
2634
2635 /* Link delete triggered from AP,
2636 * start timer with tbtt count * beacon interval
2637 */
2638 tbtt_count = link_info->ap_removal_timer;
2639 bcn_int = mlo_get_bcn_interval_by_bssid(
2640 wlan_vdev_get_pdev(vdev),
2641 wlan_peer_get_macaddr(bss_peer));
2642 if (!bcn_int)
2643 return;
2644
2645 if (vdev_mlme->ops &&
2646 vdev_mlme->ops->mlme_vdev_reconfig_notify) {
2647 status = vdev_mlme->ops->mlme_vdev_reconfig_notify(
2648 vdev_mlme, &tbtt_count, bcn_int);
2649 if (QDF_IS_STATUS_ERROR(status))
2650 return;
2651 }
2652
2653 /* Handle PTQM migration upon seeing AP removal for the first time */
2654 if (!vdev_mlme->ml_reconfig_started)
2655 mlo_sta_handle_ptqm_migration(vdev);
2656
2657 vdev_mlme->ml_reconfig_started = true;
2658 qdf_timer_mod(&vdev_mlme->ml_reconfig_timer,
2659 qdf_time_uint_to_ms(tbtt_count * bcn_int));
2660 }
2661
2662 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
2663 static inline
mlo_process_link_add(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct mlo_partner_info * cache_partner_info,struct mlo_partner_info * partner_info,uint16_t vdev_count)2664 QDF_STATUS mlo_process_link_add(struct wlan_objmgr_psoc *psoc,
2665 struct wlan_objmgr_vdev *vdev,
2666 struct mlo_partner_info *cache_partner_info,
2667 struct mlo_partner_info *partner_info,
2668 uint16_t vdev_count)
2669 {
2670 return QDF_STATUS_E_INVAL;
2671 }
2672 #else
2673 static
mlo_process_link_add(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct mlo_partner_info * cache_partner_info,struct mlo_partner_info * partner_info,uint16_t vdev_count)2674 QDF_STATUS mlo_process_link_add(struct wlan_objmgr_psoc *psoc,
2675 struct wlan_objmgr_vdev *vdev,
2676 struct mlo_partner_info *cache_partner_info,
2677 struct mlo_partner_info *partner_info,
2678 uint16_t vdev_count)
2679 {
2680 struct wlan_mlo_dev_context *ml_ctx = vdev->mlo_dev_ctx;
2681
2682 /* Check if ini to support dynamic link add is enable
2683 * or not
2684 */
2685 if (!mlme_mlo_is_reconfig_reassoc_enable(psoc)) {
2686 mlo_debug("ML Reconfig link add support disabled");
2687 return QDF_STATUS_E_INVAL;
2688 }
2689
2690 if (vdev_count == ml_ctx->wlan_vdev_count) {
2691 /* All links are participating in current ML connection */
2692 return QDF_STATUS_E_INVAL;
2693 }
2694
2695 /* check if any new link in scan entry */
2696 if (partner_info->num_partner_links ==
2697 cache_partner_info->num_partner_links) {
2698 if (!qdf_mem_cmp(cache_partner_info, partner_info,
2699 sizeof(struct mlo_partner_info))) {
2700 mlo_debug("No new link found");
2701 return QDF_STATUS_E_INVAL;
2702 }
2703 }
2704
2705 /* mlo connected on all links already */
2706 if (partner_info->num_partner_links <= (vdev_count - 1))
2707 return QDF_STATUS_E_INVAL;
2708
2709 /* Partner info changed compared to the cached scan entry.
2710 * Process link add
2711 */
2712 mlo_err("Link addition detected, issue disconnect");
2713 mlo_disconnect(vdev, CM_SB_DISCONNECT,
2714 REASON_UNSPEC_FAILURE, NULL);
2715 return QDF_STATUS_SUCCESS;
2716 }
2717 #endif
2718
mlo_process_ml_reconfig_ie(struct wlan_objmgr_vdev * vdev,struct scan_cache_entry * scan_entry,uint8_t * ml_ie,qdf_size_t ml_ie_len,struct mlo_partner_info * partner_info)2719 void mlo_process_ml_reconfig_ie(struct wlan_objmgr_vdev *vdev,
2720 struct scan_cache_entry *scan_entry,
2721 uint8_t *ml_ie, qdf_size_t ml_ie_len,
2722 struct mlo_partner_info *partner_info)
2723 {
2724 struct wlan_objmgr_psoc *psoc = NULL;
2725 struct wlan_objmgr_pdev *pdev = NULL;
2726 struct wlan_objmgr_vdev *co_mld_vdev = NULL;
2727 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
2728 uint16_t vdev_count = 0;
2729 uint8_t idx = 0;
2730 uint8_t i = 0;
2731 uint8_t link_ix = 0;
2732 struct ml_rv_info reconfig_info = {0};
2733 struct mlo_partner_info ml_partner_info = {0};
2734 uint8_t *ml_rv_ie = NULL;
2735 qdf_size_t ml_rv_ie_len = 0;
2736 QDF_STATUS status = QDF_STATUS_SUCCESS;
2737
2738 if (!vdev || !mlo_is_mld_sta(vdev))
2739 return;
2740
2741 pdev = wlan_vdev_get_pdev(vdev);
2742 if (!pdev)
2743 return;
2744
2745 psoc = wlan_pdev_get_psoc(pdev);
2746 if (!psoc)
2747 return;
2748
2749 mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
2750 if (!vdev_count) {
2751 mlo_debug("Number of VDEVs under MLD is reported as 0");
2752 return;
2753 }
2754
2755 if (!scan_entry ||
2756 QDF_IS_STATUS_ERROR(util_scan_get_ml_partner_info(scan_entry,
2757 &ml_partner_info))) {
2758 mlo_debug("Unable to fetch the partner info in scan db");
2759 goto check_ml_rv;
2760 }
2761
2762 /* Processing for link add */
2763 if (QDF_IS_STATUS_SUCCESS(mlo_process_link_add(psoc, vdev,
2764 partner_info,
2765 &ml_partner_info,
2766 vdev_count))) {
2767 mlo_err("Issued MLD disconnect for link add");
2768 goto err_release_refs;
2769 }
2770
2771 check_ml_rv:
2772 /* Processing for ML Reconfig IE */
2773 if (vdev_count == 1) {
2774 /* Single link MLO, no need to process link delete */
2775 goto err_release_refs;
2776 }
2777
2778 status = util_find_mlie_by_variant(ml_ie,
2779 ml_ie_len,
2780 &ml_rv_ie,
2781 &ml_rv_ie_len,
2782 WLAN_ML_VARIANT_RECONFIG);
2783 if (QDF_IS_STATUS_ERROR(status) || !ml_rv_ie) {
2784 mlo_debug("ML IE for reconfig variant not found");
2785 goto err_release_refs;
2786 }
2787
2788 status = util_get_rvmlie_persta_link_info(ml_rv_ie, ml_rv_ie_len,
2789 &reconfig_info);
2790 if (QDF_IS_STATUS_ERROR(status)) {
2791 mlo_err("Unable to get persta link info from ML RV IE");
2792 goto err_release_refs;
2793 }
2794
2795 if (!reconfig_info.num_links) {
2796 mlo_err("No. of links is 0 in ML reconfig IE");
2797 goto err_release_refs;
2798 }
2799
2800 for (idx = 0; idx < vdev_count; idx++) {
2801 co_mld_vdev = wlan_vdev_list[idx];
2802 if (!co_mld_vdev) {
2803 mlo_debug("VDEV in MLD VDEV list is NULL");
2804 goto err_release_refs;
2805 }
2806
2807 link_ix = wlan_vdev_get_link_id(co_mld_vdev);
2808 for (i = 0; i < reconfig_info.num_links; i++) {
2809 if (link_ix == reconfig_info.link_info[i].link_id)
2810 mlo_process_link_remove(co_mld_vdev,
2811 &reconfig_info.link_info[i]);
2812 }
2813 }
2814
2815 mlo_sta_handle_link_reconfig_standby_link(vdev, &reconfig_info);
2816
2817 err_release_refs:
2818
2819 for (i = 0; i < vdev_count; i++)
2820 mlo_release_vdev_ref(wlan_vdev_list[i]);
2821 }
2822
2823 QDF_STATUS
mlo_get_link_state_context(struct wlan_objmgr_psoc * psoc,get_ml_link_state_cb * resp_cb,void ** context,uint8_t vdev_id)2824 mlo_get_link_state_context(struct wlan_objmgr_psoc *psoc,
2825 get_ml_link_state_cb *resp_cb,
2826 void **context, uint8_t vdev_id)
2827 {
2828 struct wlan_mlo_dev_context *mlo_ctx;
2829 struct wlan_mlo_sta *sta_ctx = NULL;
2830 struct wlan_objmgr_vdev *vdev;
2831
2832 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
2833 WLAN_MLO_MGR_ID);
2834 if (!vdev)
2835 return QDF_STATUS_E_NULL_VALUE;
2836
2837 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
2838 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
2839 return QDF_STATUS_E_NULL_VALUE;
2840 }
2841
2842 mlo_ctx = vdev->mlo_dev_ctx;
2843
2844 if (!mlo_ctx) {
2845 mlo_err("null mlo_dev_ctx");
2846 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
2847 return QDF_STATUS_E_NULL_VALUE;
2848 }
2849
2850 sta_ctx = mlo_ctx->sta_ctx;
2851
2852 if (!sta_ctx) {
2853 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
2854 return QDF_STATUS_E_INVAL;
2855 }
2856
2857 mlo_dev_lock_acquire(mlo_ctx);
2858 *resp_cb = sta_ctx->ml_link_state.ml_link_state_resp_cb;
2859 *context = sta_ctx->ml_link_state.ml_link_state_req_context;
2860
2861 mlo_dev_lock_release(mlo_ctx);
2862 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
2863 return QDF_STATUS_SUCCESS;
2864 }
2865
2866 void
wlan_mlo_send_vdev_pause(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,uint16_t session_id,uint16_t vdev_pause_dur)2867 wlan_mlo_send_vdev_pause(struct wlan_objmgr_psoc *psoc,
2868 struct wlan_objmgr_vdev *vdev,
2869 uint16_t session_id,
2870 uint16_t vdev_pause_dur)
2871 {
2872 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
2873 struct mlo_vdev_pause vdev_pause_info;
2874 QDF_STATUS status = QDF_STATUS_E_FAILURE;
2875
2876 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
2877 if (!mlo_tx_ops) {
2878 mlo_err("tx_ops is null!");
2879 return;
2880 }
2881
2882 if (!mlo_tx_ops->send_vdev_pause) {
2883 mlo_err("send_vdev_pause is null");
2884 return;
2885 }
2886
2887 vdev_pause_info.vdev_id = session_id;
2888 vdev_pause_info.vdev_pause_duration = vdev_pause_dur;
2889 status = mlo_tx_ops->send_vdev_pause(psoc, &vdev_pause_info);
2890 if (QDF_IS_STATUS_ERROR(status))
2891 mlo_err("Failed to send vdev pause to FW");
2892 }
2893
2894 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
mlo_is_any_link_disconnecting(struct wlan_objmgr_vdev * vdev)2895 bool mlo_is_any_link_disconnecting(struct wlan_objmgr_vdev *vdev)
2896 {
2897 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
2898 uint16_t vdev_count = 0, i;
2899 bool status = false;
2900
2901 if (!vdev)
2902 return status;
2903
2904 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list);
2905 for (i = 0; i < vdev_count; i++) {
2906 if (!status && wlan_cm_is_vdev_disconnecting(wlan_vdev_list[i]))
2907 status = true;
2908 mlo_release_vdev_ref(wlan_vdev_list[i]);
2909 }
2910
2911 return status;
2912 }
2913
2914 QDF_STATUS
mlo_set_chan_switch_in_progress(struct wlan_objmgr_vdev * vdev,bool val)2915 mlo_set_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev, bool val)
2916 {
2917 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
2918
2919 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx)
2920 return QDF_STATUS_E_INVAL;
2921
2922 mlo_dev_ctx->sta_ctx->ml_chan_switch_in_progress = val;
2923 mlo_debug("Set ml_chan_switch_in_progress: %d vdev %d",
2924 val, wlan_vdev_get_id(vdev));
2925
2926 return QDF_STATUS_SUCCESS;
2927 }
2928
mlo_is_chan_switch_in_progress(struct wlan_objmgr_vdev * vdev)2929 bool mlo_is_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev)
2930 {
2931 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
2932
2933 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx)
2934 return false;
2935
2936 return mlo_dev_ctx->sta_ctx->ml_chan_switch_in_progress;
2937 }
2938 #endif
2939 #endif
2940