1 /*
2 * Copyright (c) 2012-2015, 2020-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: Implements connect specific APIs of connection manager
20 */
21
22 #include "wlan_cm_main_api.h"
23 #include "wlan_scan_api.h"
24 #include "wlan_cm_roam.h"
25 #include "wlan_cm_sm.h"
26 #ifdef WLAN_POLICY_MGR_ENABLE
27 #include "wlan_policy_mgr_api.h"
28 #endif
29 #include <wlan_serialization_api.h>
30 #ifdef CONN_MGR_ADV_FEATURE
31 #include "wlan_dlm_api.h"
32 #include "wlan_cm_roam_api.h"
33 #include "wlan_tdls_api.h"
34 #include "wlan_mlo_t2lm.h"
35 #include "wlan_t2lm_api.h"
36 #endif
37 #include <wlan_utility.h>
38 #ifdef WLAN_FEATURE_11BE_MLO
39 #include <wlan_mlo_mgr_peer.h>
40 #endif
41 #include <wlan_mlo_mgr_link_switch.h>
42 #include <wlan_mlo_mgr_sta.h>
43 #include "wlan_mlo_mgr_op.h"
44 #include <wlan_objmgr_vdev_obj.h>
45 #include "wlan_psoc_mlme_api.h"
46 #include "wlan_scan_public_structs.h"
47 #ifdef WLAN_FEATURE_LL_LT_SAP
48 #include "wlan_ll_sap_api.h"
49 #endif
50 #ifdef CONNECTIVITY_DIAG_EVENT
51 #include "wlan_connectivity_logging.h"
52 #endif
53 #include "wlan_mlme_api.h"
54
55 void
cm_fill_failure_resp_from_cm_id(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp,wlan_cm_id cm_id,enum wlan_cm_connect_fail_reason reason)56 cm_fill_failure_resp_from_cm_id(struct cnx_mgr *cm_ctx,
57 struct wlan_cm_connect_resp *resp,
58 wlan_cm_id cm_id,
59 enum wlan_cm_connect_fail_reason reason)
60 {
61 resp->connect_status = QDF_STATUS_E_FAILURE;
62 resp->cm_id = cm_id;
63 resp->vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
64 resp->reason = reason;
65 /* Get bssid and ssid and freq for the cm id from the req list */
66 cm_fill_bss_info_in_connect_rsp_by_cm_id(cm_ctx, cm_id, resp);
67 }
68
cm_connect_cmd_timeout(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id)69 static QDF_STATUS cm_connect_cmd_timeout(struct cnx_mgr *cm_ctx,
70 wlan_cm_id cm_id)
71 {
72 struct wlan_cm_connect_resp *resp;
73 QDF_STATUS status;
74
75 resp = qdf_mem_malloc(sizeof(*resp));
76 if (!resp)
77 return QDF_STATUS_E_NOMEM;
78
79 cm_fill_failure_resp_from_cm_id(cm_ctx, resp, cm_id, CM_SER_TIMEOUT);
80 status = cm_sm_deliver_event(cm_ctx->vdev,
81 WLAN_CM_SM_EV_CONNECT_FAILURE,
82 sizeof(*resp), resp);
83 qdf_mem_free(resp);
84
85 if (QDF_IS_STATUS_ERROR(status))
86 cm_connect_handle_event_post_fail(cm_ctx, cm_id);
87
88 return status;
89 }
90
91 #ifdef WLAN_CM_USE_SPINLOCK
cm_activate_connect_req_sched_cb(struct scheduler_msg * msg)92 static QDF_STATUS cm_activate_connect_req_sched_cb(struct scheduler_msg *msg)
93 {
94 struct wlan_serialization_command *cmd = msg->bodyptr;
95 struct wlan_objmgr_vdev *vdev;
96 struct cnx_mgr *cm_ctx;
97 QDF_STATUS ret = QDF_STATUS_E_FAILURE;
98
99 if (!cmd) {
100 mlme_err("cmd is null");
101 return QDF_STATUS_E_INVAL;
102 }
103
104 vdev = cmd->vdev;
105 if (!vdev) {
106 mlme_err("vdev is null");
107 return QDF_STATUS_E_INVAL;
108 }
109
110 cm_ctx = cm_get_cm_ctx(vdev);
111 if (!cm_ctx)
112 return QDF_STATUS_E_INVAL;
113
114 ret = cm_sm_deliver_event(vdev,
115 WLAN_CM_SM_EV_CONNECT_ACTIVE,
116 sizeof(wlan_cm_id),
117 &cmd->cmd_id);
118
119 /*
120 * Called from scheduler context hence posting failure
121 */
122 if (QDF_IS_STATUS_ERROR(ret)) {
123 mlme_err(CM_PREFIX_FMT "Activation failed for cmd:%d",
124 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id),
125 cmd->cmd_type);
126 cm_connect_handle_event_post_fail(cm_ctx, cmd->cmd_id);
127 }
128
129 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
130 return ret;
131 }
132
133 static QDF_STATUS
cm_activate_connect_req(struct wlan_serialization_command * cmd)134 cm_activate_connect_req(struct wlan_serialization_command *cmd)
135 {
136 struct wlan_objmgr_vdev *vdev = cmd->vdev;
137 struct scheduler_msg msg = {0};
138 QDF_STATUS ret;
139
140 msg.bodyptr = cmd;
141 msg.callback = cm_activate_connect_req_sched_cb;
142 msg.flush_callback = cm_activate_cmd_req_flush_cb;
143
144 ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_MLME_CM_ID);
145 if (QDF_IS_STATUS_ERROR(ret))
146 return ret;
147
148 ret = scheduler_post_message(QDF_MODULE_ID_MLME,
149 QDF_MODULE_ID_MLME,
150 QDF_MODULE_ID_MLME, &msg);
151
152 if (QDF_IS_STATUS_ERROR(ret)) {
153 mlme_err(CM_PREFIX_FMT "Failed to post scheduler_msg",
154 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id));
155 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
156 return ret;
157 }
158 mlme_debug(CM_PREFIX_FMT "Cmd act in sched cmd type:%d",
159 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id),
160 cmd->cmd_type);
161
162 return ret;
163 }
164 #else
165 static QDF_STATUS
cm_activate_connect_req(struct wlan_serialization_command * cmd)166 cm_activate_connect_req(struct wlan_serialization_command *cmd)
167 {
168 return cm_sm_deliver_event(cmd->vdev,
169 WLAN_CM_SM_EV_CONNECT_ACTIVE,
170 sizeof(wlan_cm_id),
171 &cmd->cmd_id);
172 }
173 #endif
174
175 static QDF_STATUS
cm_ser_connect_cb(struct wlan_serialization_command * cmd,enum wlan_serialization_cb_reason reason)176 cm_ser_connect_cb(struct wlan_serialization_command *cmd,
177 enum wlan_serialization_cb_reason reason)
178 {
179 QDF_STATUS status = QDF_STATUS_SUCCESS;
180 struct wlan_objmgr_vdev *vdev;
181 struct cnx_mgr *cm_ctx;
182 enum qdf_hang_reason hang_reason = QDF_VDEV_ACTIVE_SER_CONNECT_TIMEOUT;
183
184 if (!cmd) {
185 mlme_err("cmd is NULL, reason: %d", reason);
186 QDF_ASSERT(0);
187 return QDF_STATUS_E_NULL_VALUE;
188 }
189
190 vdev = cmd->vdev;
191
192 cm_ctx = cm_get_cm_ctx(vdev);
193 if (!cm_ctx)
194 return QDF_STATUS_E_NULL_VALUE;
195
196 switch (reason) {
197 case WLAN_SER_CB_ACTIVATE_CMD:
198 /*
199 * For pending to active reason, use async api to take lock.
200 * For direct activation use sync api to avoid taking lock
201 * as lock is already acquired by the requester.
202 */
203 if (cmd->activation_reason == SER_PENDING_TO_ACTIVE)
204 status = cm_activate_connect_req(cmd);
205 else
206 status = cm_sm_deliver_event_sync(cm_ctx,
207 WLAN_CM_SM_EV_CONNECT_ACTIVE,
208 sizeof(wlan_cm_id),
209 &cmd->cmd_id);
210 if (QDF_IS_STATUS_SUCCESS(status))
211 break;
212 /*
213 * Handle failure if posting fails, i.e. the SM state has
214 * changed or head cm_id doesn't match the active cm_id.
215 * connect active should be handled only in JOIN_PENDING. If
216 * new command has been received connect activation should be
217 * aborted from here with connect req cleanup.
218 */
219 cm_connect_handle_event_post_fail(cm_ctx, cmd->cmd_id);
220 break;
221 case WLAN_SER_CB_CANCEL_CMD:
222 /* command removed from pending list. */
223 break;
224 case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
225 mlme_err(CM_PREFIX_FMT "Active command timeout",
226 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id));
227 cm_trigger_panic_on_cmd_timeout(cm_ctx->vdev, hang_reason);
228 cm_connect_cmd_timeout(cm_ctx, cmd->cmd_id);
229 break;
230 case WLAN_SER_CB_RELEASE_MEM_CMD:
231 cm_reset_active_cm_id(vdev, cmd->cmd_id);
232 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
233 break;
234 default:
235 QDF_ASSERT(0);
236 status = QDF_STATUS_E_INVAL;
237 break;
238 }
239
240 return status;
241 }
242
cm_ser_connect_req(struct wlan_objmgr_pdev * pdev,struct cnx_mgr * cm_ctx,struct cm_connect_req * cm_req)243 static QDF_STATUS cm_ser_connect_req(struct wlan_objmgr_pdev *pdev,
244 struct cnx_mgr *cm_ctx,
245 struct cm_connect_req *cm_req)
246 {
247 struct wlan_serialization_command cmd = {0, };
248 enum wlan_serialization_status ser_cmd_status;
249 QDF_STATUS status;
250 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
251
252 if (cm_is_link_switch_connect_req(cm_req)) {
253 /*
254 * For link switch, connect serialization is not required as
255 * link switch is already serialized.
256 */
257 return cm_sm_deliver_event_sync(cm_ctx,
258 WLAN_CM_SM_EV_CONNECT_ACTIVE,
259 sizeof(wlan_cm_id),
260 &cm_req->cm_id);
261 }
262
263 status = wlan_objmgr_vdev_try_get_ref(cm_ctx->vdev, WLAN_MLME_CM_ID);
264 if (QDF_IS_STATUS_ERROR(status)) {
265 mlme_err(CM_PREFIX_FMT "unable to get reference",
266 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
267 return status;
268 }
269
270 cmd.cmd_type = WLAN_SER_CMD_VDEV_CONNECT;
271 cmd.cmd_id = cm_req->cm_id;
272 cmd.cmd_cb = cm_ser_connect_cb;
273 cmd.source = WLAN_UMAC_COMP_MLME;
274 cmd.is_high_priority = false;
275 cmd.cmd_timeout_duration = cm_ctx->connect_timeout;
276 cmd.vdev = cm_ctx->vdev;
277 cmd.is_blocking = true;
278
279 ser_cmd_status = wlan_serialization_request(&cmd);
280 switch (ser_cmd_status) {
281 case WLAN_SER_CMD_PENDING:
282 /* command moved to pending list.Do nothing */
283 break;
284 case WLAN_SER_CMD_ACTIVE:
285 /* command moved to active list. Do nothing */
286 break;
287 default:
288 mlme_err(CM_PREFIX_FMT "ser cmd status %d",
289 CM_PREFIX_REF(vdev_id, cm_req->cm_id), ser_cmd_status);
290 wlan_objmgr_vdev_release_ref(cm_ctx->vdev, WLAN_MLME_CM_ID);
291
292 return QDF_STATUS_E_FAILURE;
293 }
294
295 return QDF_STATUS_SUCCESS;
296 }
297
298 void
cm_connect_handle_event_post_fail(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id)299 cm_connect_handle_event_post_fail(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
300 {
301 struct wlan_cm_connect_resp *resp;
302
303 resp = qdf_mem_malloc(sizeof(*resp));
304 if (!resp)
305 return;
306
307 cm_fill_failure_resp_from_cm_id(cm_ctx, resp, cm_id,
308 CM_ABORT_DUE_TO_NEW_REQ_RECVD);
309 cm_connect_complete(cm_ctx, resp);
310 qdf_mem_free(resp);
311 }
312
313 #ifdef CONNECTIVITY_DIAG_EVENT
314 static void
cm_connectivity_connecting_event(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req)315 cm_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev,
316 struct wlan_cm_connect_req *req)
317 {
318 wlan_connectivity_connecting_event(vdev, req);
319 }
320 #else
321 static void
cm_connectivity_connecting_event(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req)322 cm_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev,
323 struct wlan_cm_connect_req *req)
324 {
325 }
326 #endif
327
328 QDF_STATUS
cm_send_connect_start_fail(struct cnx_mgr * cm_ctx,struct cm_connect_req * req,enum wlan_cm_connect_fail_reason reason)329 cm_send_connect_start_fail(struct cnx_mgr *cm_ctx,
330 struct cm_connect_req *req,
331 enum wlan_cm_connect_fail_reason reason)
332 {
333 struct wlan_cm_connect_resp *resp;
334 QDF_STATUS status;
335
336 resp = qdf_mem_malloc(sizeof(*resp));
337 if (!resp)
338 return QDF_STATUS_E_NOMEM;
339
340 cm_connectivity_connecting_event(cm_ctx->vdev, &req->req);
341
342 cm_fill_failure_resp_from_cm_id(cm_ctx, resp, req->cm_id, reason);
343
344 status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_CONNECT_FAILURE,
345 sizeof(*resp), resp);
346 qdf_mem_free(resp);
347 return status;
348 }
349
350 #ifdef WLAN_POLICY_MGR_ENABLE
351 static void
cm_cont_connect_for_event(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,wlan_cm_id cm_id,enum wlan_cm_sm_evt event)352 cm_cont_connect_for_event(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
353 wlan_cm_id cm_id, enum wlan_cm_sm_evt event)
354 {
355 struct wlan_objmgr_vdev *vdev;
356 QDF_STATUS status;
357 struct cnx_mgr *cm_ctx;
358
359 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
360 WLAN_MLME_CM_ID);
361 if (!vdev)
362 return;
363
364 cm_ctx = cm_get_cm_ctx(vdev);
365 if (!cm_ctx) {
366 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
367 return;
368 }
369
370 status = cm_sm_deliver_event(vdev, event, sizeof(wlan_cm_id), &cm_id);
371
372 /*
373 * Handle failure if posting fails, i.e. the SM state has
374 * changed or head cm_id doesn't match the active cm_id. If
375 * new command has been received connect should be
376 * aborted from here with req cleanup.
377 */
378 if (QDF_IS_STATUS_ERROR(status))
379 cm_connect_handle_event_post_fail(cm_ctx, cm_id);
380 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
381 }
382
383 QDF_STATUS
cm_ser_connect_after_mode_change_resp(struct cnx_mgr * cm_ctx,wlan_cm_id * cm_id,enum wlan_cm_sm_evt event)384 cm_ser_connect_after_mode_change_resp(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id,
385 enum wlan_cm_sm_evt event)
386 {
387 struct cm_req *cm_req;
388 enum wlan_cm_connect_fail_reason reason = CM_GENERIC_FAILURE;
389 struct wlan_objmgr_pdev *pdev;
390 QDF_STATUS status;
391
392 if (!cm_id)
393 return QDF_STATUS_E_FAILURE;
394
395 cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
396 if (!cm_req)
397 return QDF_STATUS_E_INVAL;
398
399 pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
400 if (!pdev) {
401 mlme_err(CM_PREFIX_FMT "Failed to find pdev",
402 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
403 cm_req->cm_id));
404 goto send_failure;
405 }
406
407 switch (event) {
408 case WLAN_CM_SM_EV_HW_MODE_SUCCESS:
409 case WLAN_CM_SM_EV_BEARER_SWITCH_COMPLETE:
410 status = cm_ser_connect_req(pdev, cm_ctx, &cm_req->connect_req);
411 if (QDF_IS_STATUS_ERROR(status)) {
412 reason = CM_SER_FAILURE;
413 break;
414 }
415 return status;
416 case WLAN_CM_SM_EV_HW_MODE_FAILURE:
417 reason = CM_HW_MODE_FAILURE;
418 break;
419 default:
420 break;
421 }
422
423 send_failure:
424 return cm_send_connect_start_fail(cm_ctx, &cm_req->connect_req, reason);
425 }
426
cm_hw_mode_change_resp(struct wlan_objmgr_pdev * pdev,uint8_t vdev_id,wlan_cm_id cm_id,QDF_STATUS status)427 void cm_hw_mode_change_resp(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
428 wlan_cm_id cm_id, QDF_STATUS status)
429 {
430 enum wlan_cm_sm_evt event = WLAN_CM_SM_EV_HW_MODE_SUCCESS;
431
432 mlme_debug(CM_PREFIX_FMT "Continue connect after HW mode change, status %d",
433 CM_PREFIX_REF(vdev_id, cm_id), status);
434
435 if (QDF_IS_STATUS_ERROR(status))
436 event = WLAN_CM_SM_EV_HW_MODE_FAILURE;
437
438 cm_cont_connect_for_event(wlan_pdev_get_psoc(pdev), vdev_id, cm_id,
439 event);
440 }
441
cm_check_for_hw_mode_change(struct wlan_objmgr_psoc * psoc,qdf_list_t * scan_list,uint8_t vdev_id,wlan_cm_id connect_id)442 static QDF_STATUS cm_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
443 qdf_list_t *scan_list,
444 uint8_t vdev_id,
445 wlan_cm_id connect_id)
446 {
447 return policy_mgr_change_hw_mode_sta_connect(psoc, scan_list, vdev_id,
448 connect_id);
449 }
450 #else
451 static inline
cm_check_for_hw_mode_change(struct wlan_objmgr_psoc * psoc,qdf_list_t * scan_list,uint8_t vdev_id,uint8_t connect_id)452 QDF_STATUS cm_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
453 qdf_list_t *scan_list, uint8_t vdev_id,
454 uint8_t connect_id)
455 {
456 return QDF_STATUS_E_ALREADY;
457 }
458 #endif /* WLAN_POLICY_MGR_ENABLE */
459
460 #ifdef WLAN_FEATURE_LL_LT_SAP
cm_bearer_switch_resp(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,wlan_cm_id cm_id,QDF_STATUS status)461 void cm_bearer_switch_resp(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
462 wlan_cm_id cm_id, QDF_STATUS status)
463 {
464 mlme_debug(CM_PREFIX_FMT "Continue connect after bearer switch %d",
465 CM_PREFIX_REF(vdev_id, cm_id), status);
466
467 cm_cont_connect_for_event(psoc, vdev_id, cm_id,
468 WLAN_CM_SM_EV_BEARER_SWITCH_COMPLETE);
469 }
470
471 static QDF_STATUS
cm_check_for_bearer_switch(struct wlan_objmgr_psoc * psoc,qdf_list_t * scan_list,uint8_t vdev_id,wlan_cm_id cm_id)472 cm_check_for_bearer_switch(struct wlan_objmgr_psoc *psoc, qdf_list_t *scan_list,
473 uint8_t vdev_id, wlan_cm_id cm_id)
474 {
475 return wlan_ll_sap_switch_bearer_on_sta_connect_start(psoc, scan_list,
476 vdev_id, cm_id);
477 }
478 #else
479 static inline QDF_STATUS
cm_check_for_bearer_switch(struct wlan_objmgr_psoc * psoc,qdf_list_t * scan_list,uint8_t vdev_id,wlan_cm_id cm_id)480 cm_check_for_bearer_switch(struct wlan_objmgr_psoc *psoc, qdf_list_t *scan_list,
481 uint8_t vdev_id, wlan_cm_id cm_id)
482 {
483 return QDF_STATUS_E_ALREADY;
484 }
485 #endif /* WLAN_FEATURE_LL_LT_SAP */
486
cm_delete_pmksa_for_bssid(struct cnx_mgr * cm_ctx,struct qdf_mac_addr * bssid)487 static inline void cm_delete_pmksa_for_bssid(struct cnx_mgr *cm_ctx,
488 struct qdf_mac_addr *bssid)
489 {
490 struct wlan_crypto_pmksa pmksa;
491
492 qdf_mem_zero(&pmksa, sizeof(pmksa));
493 qdf_copy_macaddr(&pmksa.bssid, bssid);
494 wlan_crypto_set_del_pmksa(cm_ctx->vdev, &pmksa, false);
495 }
496
497 #if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
498 static inline
cm_delete_pmksa_for_single_pmk_bssid(struct cnx_mgr * cm_ctx,struct qdf_mac_addr * bssid)499 void cm_delete_pmksa_for_single_pmk_bssid(struct cnx_mgr *cm_ctx,
500 struct qdf_mac_addr *bssid)
501 {
502 cm_delete_pmksa_for_bssid(cm_ctx, bssid);
503 }
504 #else
505 static inline
cm_delete_pmksa_for_single_pmk_bssid(struct cnx_mgr * cm_ctx,struct qdf_mac_addr * bssid)506 void cm_delete_pmksa_for_single_pmk_bssid(struct cnx_mgr *cm_ctx,
507 struct qdf_mac_addr *bssid)
508 {
509 }
510 #endif /* WLAN_SAE_SINGLE_PMK && WLAN_FEATURE_ROAM_OFFLOAD */
511
512 static inline void
cm_set_pmf_caps(struct wlan_cm_connect_req * req,struct scan_filter * filter)513 cm_set_pmf_caps(struct wlan_cm_connect_req *req, struct scan_filter *filter)
514 {
515 if (req->crypto.rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED)
516 filter->pmf_cap = WLAN_PMF_REQUIRED;
517 else if (req->crypto.rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)
518 filter->pmf_cap = WLAN_PMF_CAPABLE;
519 else
520 filter->pmf_cap = WLAN_PMF_DISABLED;
521 }
522
523 #ifdef WLAN_FEATURE_11BE_MLO
524 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
525 static inline
cm_set_vdev_link_id(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)526 void cm_set_vdev_link_id(struct cnx_mgr *cm_ctx,
527 struct cm_connect_req *req)
528 {
529 uint8_t link_id;
530
531 link_id = req->cur_candidate->entry->ml_info.self_link_id;
532 mlme_debug(CM_PREFIX_FMT "setting link ID to %d",
533 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), req->cm_id),
534 link_id);
535 wlan_vdev_set_link_id(cm_ctx->vdev, link_id);
536 }
537
538 static inline
cm_is_ml_connection(struct wlan_objmgr_vdev * vdev,struct cm_connect_req * req)539 bool cm_is_ml_connection(struct wlan_objmgr_vdev *vdev,
540 struct cm_connect_req *req)
541 {
542 struct qdf_mac_addr *mld_mac;
543 bool eht_capab;
544
545 wlan_psoc_mlme_get_11be_capab(wlan_vdev_get_psoc(vdev), &eht_capab);
546 mld_mac = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
547
548 if (eht_capab && !qdf_is_macaddr_zero(mld_mac) &&
549 req->cur_candidate->entry->ie_list.multi_link_bv &&
550 wlan_cm_is_eht_allowed_for_current_security(wlan_vdev_get_psoc(vdev),
551 req->cur_candidate->entry,
552 true))
553 return true;
554
555 return false;
556 }
557
cm_update_vdev_mlme_macaddr(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)558 static QDF_STATUS cm_update_vdev_mlme_macaddr(struct cnx_mgr *cm_ctx,
559 struct cm_connect_req *req)
560 {
561 struct qdf_mac_addr *mac;
562 struct wlan_objmgr_vdev *vdev = cm_ctx->vdev;
563 uint8_t vdev_id = wlan_vdev_get_id(vdev);
564
565 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
566 return QDF_STATUS_SUCCESS;
567
568 mac = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
569
570 if (cm_is_ml_connection(vdev, req)) {
571 wlan_vdev_obj_lock(vdev);
572 /* Use link address for ML connection */
573 wlan_vdev_mlme_set_macaddr(vdev, vdev->vdev_mlme.linkaddr);
574 wlan_vdev_obj_unlock(vdev);
575 wlan_vdev_mlme_set_mlo_vdev(vdev);
576 mlme_debug(CM_PREFIX_FMT "setting ML link address " QDF_MAC_ADDR_FMT,
577 CM_PREFIX_REF(vdev_id, req->cm_id),
578 QDF_MAC_ADDR_REF(mac->bytes));
579 } else {
580 if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) {
581 mlme_debug(CM_PREFIX_FMT "MLIE is not present for partner" QDF_MAC_ADDR_FMT,
582 CM_PREFIX_REF(vdev_id, req->cm_id),
583 QDF_MAC_ADDR_REF(mac->bytes));
584 return QDF_STATUS_E_INVAL;
585 }
586
587 /* Use net_dev address for non-ML connection */
588 if (!qdf_is_macaddr_zero(mac)) {
589 wlan_vdev_obj_lock(vdev);
590 wlan_vdev_mlme_set_macaddr(vdev, mac->bytes);
591 wlan_vdev_obj_unlock(vdev);
592 mlme_debug(CM_PREFIX_FMT "setting non-ML address " QDF_MAC_ADDR_FMT,
593 CM_PREFIX_REF(vdev_id, req->cm_id),
594 QDF_MAC_ADDR_REF(mac->bytes));
595 }
596 wlan_vdev_mlme_clear_mlo_vdev(vdev);
597 }
598
599 return QDF_STATUS_SUCCESS;
600 }
601 #else
602 static inline
cm_set_vdev_link_id(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)603 void cm_set_vdev_link_id(struct cnx_mgr *cm_ctx,
604 struct cm_connect_req *req)
605 { }
606
cm_update_vdev_mlme_macaddr(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)607 static QDF_STATUS cm_update_vdev_mlme_macaddr(struct cnx_mgr *cm_ctx,
608 struct cm_connect_req *req)
609 {
610 return QDF_STATUS_SUCCESS;
611 }
612 #endif
613 /**
614 * cm_get_bss_peer_mld_addr() - get bss peer mld mac address
615 * @req: pointer to cm_connect_req
616 *
617 * Return: mld mac address
618 */
cm_get_bss_peer_mld_addr(struct cm_connect_req * req)619 static struct qdf_mac_addr *cm_get_bss_peer_mld_addr(struct cm_connect_req *req)
620 {
621 if (req && req->cur_candidate && req->cur_candidate->entry)
622 return &req->cur_candidate->entry->ml_info.mld_mac_addr;
623 else
624 return NULL;
625 }
626
627 /**
628 * cm_bss_peer_is_assoc_peer() - is the bss peer to be created assoc peer or not
629 * @req: pointer to cm_connect_req
630 *
631 * Return: true if the bss peer to be created is assoc peer
632 */
cm_bss_peer_is_assoc_peer(struct cm_connect_req * req)633 static bool cm_bss_peer_is_assoc_peer(struct cm_connect_req *req)
634 {
635 if (req)
636 return !req->req.is_non_assoc_link;
637
638 return false;
639 }
640
641 /**
642 * cm_candidate_mlo_update() - handle mlo scenario for candidate validating
643 * @scan_entry: scan result of the candidate
644 * @validate_bss_info: candidate info to be updated
645 *
646 * Return: None
647 */
648 static void
cm_candidate_mlo_update(struct scan_cache_entry * scan_entry,struct validate_bss_data * validate_bss_info)649 cm_candidate_mlo_update(struct scan_cache_entry *scan_entry,
650 struct validate_bss_data *validate_bss_info)
651 {
652 validate_bss_info->is_mlo = !!scan_entry->ie_list.multi_link_bv;
653 validate_bss_info->scan_entry = scan_entry;
654 }
655
656 #else
657 static inline
cm_set_vdev_link_id(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)658 void cm_set_vdev_link_id(struct cnx_mgr *cm_ctx,
659 struct cm_connect_req *req)
660 { }
661
cm_update_vdev_mlme_macaddr(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)662 static QDF_STATUS cm_update_vdev_mlme_macaddr(struct cnx_mgr *cm_ctx,
663 struct cm_connect_req *req)
664 {
665 return QDF_STATUS_SUCCESS;
666 }
667
cm_get_bss_peer_mld_addr(struct cm_connect_req * req)668 static struct qdf_mac_addr *cm_get_bss_peer_mld_addr(struct cm_connect_req *req)
669 {
670 return NULL;
671 }
672
cm_bss_peer_is_assoc_peer(struct cm_connect_req * req)673 static bool cm_bss_peer_is_assoc_peer(struct cm_connect_req *req)
674 {
675 return false;
676 }
677
678 static inline void
cm_candidate_mlo_update(struct scan_cache_entry * scan_entry,struct validate_bss_data * validate_bss_info)679 cm_candidate_mlo_update(struct scan_cache_entry *scan_entry,
680 struct validate_bss_data *validate_bss_info)
681 {
682 }
683 #endif
684
cm_create_bss_peer(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)685 static void cm_create_bss_peer(struct cnx_mgr *cm_ctx,
686 struct cm_connect_req *req)
687 {
688 QDF_STATUS status;
689 struct qdf_mac_addr *bssid;
690 struct qdf_mac_addr *mld_mac = NULL;
691 bool is_assoc_link = false;
692 bool eht_capab;
693 struct wlan_objmgr_vdev *vdev;
694
695 if (!cm_ctx) {
696 mlme_err("invalid cm_ctx");
697 return;
698 }
699
700 vdev = cm_ctx->vdev;
701 if (mlo_is_sta_bridge_vdev(vdev) && req) {
702 /* Acquire lock as required by wlan_vdev_mlme_get_mldaddr() */
703 wlan_vdev_obj_lock(vdev);
704 bssid = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
705 wlan_vdev_obj_unlock(vdev);
706 mld_mac = mlo_get_sta_ctx_bss_mld_addr(vdev);
707 status = mlme_cm_bss_peer_create_req(vdev, bssid,
708 mld_mac, is_assoc_link);
709 goto peer_create_fail;
710 }
711
712 if (!req || !req->cur_candidate || !req->cur_candidate->entry) {
713 mlme_err("invalid req");
714 return;
715 }
716
717 wlan_psoc_mlme_get_11be_capab(wlan_vdev_get_psoc(vdev), &eht_capab);
718 if (eht_capab && wlan_vdev_mlme_is_mlo_vdev(vdev) &&
719 wlan_cm_is_eht_allowed_for_current_security(wlan_vdev_get_psoc(vdev),
720 req->cur_candidate->entry,
721 true)) {
722 cm_set_vdev_link_id(cm_ctx, req);
723 wlan_mlo_init_cu_bpcc(vdev);
724 mld_mac = cm_get_bss_peer_mld_addr(req);
725 mlo_set_sta_ctx_bss_mld_addr(vdev, mld_mac);
726 is_assoc_link = cm_bss_peer_is_assoc_peer(req);
727 }
728
729 bssid = &req->cur_candidate->entry->bssid;
730 status = mlme_cm_bss_peer_create_req(vdev, bssid,
731 mld_mac, is_assoc_link);
732 peer_create_fail:
733 if (QDF_IS_STATUS_ERROR(status)) {
734 struct wlan_cm_connect_resp *resp;
735 uint8_t vdev_id = wlan_vdev_get_id(vdev);
736
737 /* In case of failure try with next candidate */
738 mlme_err(CM_PREFIX_FMT "peer create request failed %d",
739 CM_PREFIX_REF(vdev_id, req->cm_id), status);
740
741 resp = qdf_mem_malloc(sizeof(*resp));
742 if (!resp)
743 return;
744
745 cm_fill_failure_resp_from_cm_id(cm_ctx, resp, req->cm_id,
746 CM_PEER_CREATE_FAILED);
747 cm_sm_deliver_event_sync(cm_ctx,
748 WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE,
749 sizeof(*resp), resp);
750 qdf_mem_free(resp);
751 }
752 }
753
754 #if defined(CONN_MGR_ADV_FEATURE) && defined(WLAN_FEATURE_11BE_MLO)
755 static QDF_STATUS
cm_t2lm_validate_candidate(struct cnx_mgr * cm_ctx,struct scan_cache_entry * scan_entry)756 cm_t2lm_validate_candidate(struct cnx_mgr *cm_ctx,
757 struct scan_cache_entry *scan_entry)
758 {
759 return wlan_t2lm_validate_candidate(cm_ctx, scan_entry);
760 }
761 #else
762 static inline QDF_STATUS
cm_t2lm_validate_candidate(struct cnx_mgr * cm_ctx,struct scan_cache_entry * scan_entry)763 cm_t2lm_validate_candidate(struct cnx_mgr *cm_ctx,
764 struct scan_cache_entry *scan_entry)
765 {
766 return QDF_STATUS_SUCCESS;
767 }
768 #endif
769
770 static
cm_if_mgr_validate_candidate(struct cnx_mgr * cm_ctx,struct scan_cache_entry * scan_entry)771 QDF_STATUS cm_if_mgr_validate_candidate(struct cnx_mgr *cm_ctx,
772 struct scan_cache_entry *scan_entry)
773 {
774 struct if_mgr_event_data event_data = {0};
775 QDF_STATUS status = QDF_STATUS_SUCCESS;
776
777 event_data.validate_bss_info.chan_freq = scan_entry->channel.chan_freq;
778 event_data.validate_bss_info.beacon_interval = scan_entry->bcn_int;
779 qdf_copy_macaddr(&event_data.validate_bss_info.peer_addr,
780 &scan_entry->bssid);
781 cm_candidate_mlo_update(scan_entry, &event_data.validate_bss_info);
782
783 status = cm_t2lm_validate_candidate(cm_ctx, scan_entry);
784 if (QDF_IS_STATUS_ERROR(status))
785 return status;
786
787 return if_mgr_deliver_event(cm_ctx->vdev,
788 WLAN_IF_MGR_EV_VALIDATE_CANDIDATE,
789 &event_data);
790 }
791
792 #ifdef CONN_MGR_ADV_FEATURE
793 #ifdef WLAN_FEATURE_FILS_SK
794 /*
795 * cm_create_fils_realm_hash: API to create hash using realm
796 * @fils_info: fils connection info obtained from supplicant
797 * @tmp_hash: pointer to new hash
798 *
799 * Return: QDF_STATUS
800 */
801 static QDF_STATUS
cm_create_fils_realm_hash(struct wlan_fils_con_info * fils_info,uint8_t * tmp_hash)802 cm_create_fils_realm_hash(struct wlan_fils_con_info *fils_info,
803 uint8_t *tmp_hash)
804 {
805 uint8_t *hash;
806 uint8_t *data;
807
808 if (!fils_info->realm_len)
809 return QDF_STATUS_E_NOSUPPORT;
810
811 hash = qdf_mem_malloc(SHA256_DIGEST_SIZE);
812 if (!hash)
813 return QDF_STATUS_E_NOMEM;
814
815 data = fils_info->realm;
816 qdf_get_hash(SHA256_CRYPTO_TYPE, 1, &data, &fils_info->realm_len, hash);
817 qdf_mem_copy(tmp_hash, hash, REALM_HASH_LEN);
818 qdf_mem_free(hash);
819
820 return QDF_STATUS_SUCCESS;
821 }
822
cm_update_fils_scan_filter(struct scan_filter * filter,struct cm_connect_req * cm_req)823 static void cm_update_fils_scan_filter(struct scan_filter *filter,
824 struct cm_connect_req *cm_req)
825
826 {
827 uint8_t realm_hash[REALM_HASH_LEN];
828 QDF_STATUS status;
829
830 if (!cm_req->req.fils_info.is_fils_connection)
831 return;
832
833 status = cm_create_fils_realm_hash(&cm_req->req.fils_info, realm_hash);
834 if (QDF_IS_STATUS_ERROR(status))
835 return;
836
837 filter->fils_scan_filter.realm_check = true;
838 mlme_debug(CM_PREFIX_FMT "creating realm based on fils info",
839 CM_PREFIX_REF(cm_req->req.vdev_id, cm_req->cm_id));
840 qdf_mem_copy(filter->fils_scan_filter.fils_realm, realm_hash,
841 REALM_HASH_LEN);
842 }
843
cm_is_fils_connection(struct wlan_cm_connect_resp * resp)844 static inline bool cm_is_fils_connection(struct wlan_cm_connect_resp *resp)
845 {
846 return resp->is_fils_connection;
847 }
848
cm_set_fils_key(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)849 static QDF_STATUS cm_set_fils_key(struct cnx_mgr *cm_ctx,
850 struct wlan_cm_connect_resp *resp)
851 {
852 struct fils_connect_rsp_params *fils_ie;
853
854 fils_ie = resp->connect_ies.fils_ie;
855
856 if (!fils_ie)
857 return QDF_STATUS_E_INVAL;
858
859 cm_store_fils_key(cm_ctx, true, 0, fils_ie->tk_len, fils_ie->tk,
860 &resp->bssid, resp->cm_id);
861 cm_store_fils_key(cm_ctx, false, 2, fils_ie->gtk_len, fils_ie->gtk,
862 &resp->bssid, resp->cm_id);
863 cm_set_key(cm_ctx, true, 0, &resp->bssid);
864 cm_set_key(cm_ctx, false, 2, &resp->bssid);
865
866 return QDF_STATUS_SUCCESS;
867 }
868
869 #else
cm_update_fils_scan_filter(struct scan_filter * filter,struct cm_connect_req * cm_req)870 static inline void cm_update_fils_scan_filter(struct scan_filter *filter,
871 struct cm_connect_req *cm_req)
872 { }
873
cm_is_fils_connection(struct wlan_cm_connect_resp * resp)874 static inline bool cm_is_fils_connection(struct wlan_cm_connect_resp *resp)
875 {
876 return false;
877 }
878
cm_set_fils_key(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)879 static inline QDF_STATUS cm_set_fils_key(struct cnx_mgr *cm_ctx,
880 struct wlan_cm_connect_resp *resp)
881 {
882 return QDF_STATUS_SUCCESS;
883 }
884 #endif /* WLAN_FEATURE_FILS_SK */
885
886 /**
887 * cm_get_vdev_id_with_active_vdev_op() - Get vdev id from serialization
888 * pending queue for which disconnect or connect is ongoing
889 * @pdev: pdev common object
890 * @object: vdev object
891 * @arg: vdev operation search arg
892 *
893 * Return: None
894 */
cm_get_vdev_id_with_active_vdev_op(struct wlan_objmgr_pdev * pdev,void * object,void * arg)895 static void cm_get_vdev_id_with_active_vdev_op(struct wlan_objmgr_pdev *pdev,
896 void *object, void *arg)
897 {
898 struct vdev_op_search_arg *vdev_arg = arg;
899 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
900 uint8_t vdev_id = wlan_vdev_get_id(vdev);
901 enum QDF_OPMODE opmode = wlan_vdev_mlme_get_opmode(vdev);
902
903 if (!vdev_arg)
904 return;
905
906 /* Avoid same vdev id check */
907 if (vdev_arg->current_vdev_id == vdev_id)
908 return;
909
910 if (opmode == QDF_STA_MODE || opmode == QDF_P2P_CLIENT_MODE) {
911 if (cm_is_vdev_disconnecting(vdev))
912 vdev_arg->sta_cli_vdev_id = vdev_id;
913 return;
914 }
915
916 if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE ||
917 opmode == QDF_NDI_MODE) {
918 /* Check if START/STOP AP OP is in progress */
919 if (wlan_ser_is_non_scan_cmd_type_in_vdev_queue(vdev,
920 WLAN_SER_CMD_VDEV_START_BSS) ||
921 wlan_ser_is_non_scan_cmd_type_in_vdev_queue(vdev,
922 WLAN_SER_CMD_VDEV_STOP_BSS))
923 vdev_arg->sap_go_vdev_id = vdev_id;
924 return;
925 }
926 }
927
928 /**
929 * cm_is_any_other_vdev_connecting_disconnecting() - check whether any other
930 * vdev is in waiting for vdev operations (connect/disconnect or start/stop AP)
931 * @cm_ctx: connection manager context
932 * @cm_req: Connect request.
933 *
934 * As Connect is a blocking call this API will make sure the vdev operations on
935 * other vdev doesn't starve
936 *
937 * Return : true if any other vdev has pending operation
938 */
939 static bool
cm_is_any_other_vdev_connecting_disconnecting(struct cnx_mgr * cm_ctx,struct cm_req * cm_req)940 cm_is_any_other_vdev_connecting_disconnecting(struct cnx_mgr *cm_ctx,
941 struct cm_req *cm_req)
942 {
943 struct wlan_objmgr_pdev *pdev;
944 uint8_t cur_vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
945 struct vdev_op_search_arg vdev_arg;
946
947 pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
948 if (!pdev) {
949 mlme_err(CM_PREFIX_FMT "Failed to find pdev",
950 CM_PREFIX_REF(cur_vdev_id, cm_req->cm_id));
951 return false;
952 }
953
954 vdev_arg.current_vdev_id = cur_vdev_id;
955 vdev_arg.sap_go_vdev_id = WLAN_INVALID_VDEV_ID;
956 vdev_arg.sta_cli_vdev_id = WLAN_INVALID_VDEV_ID;
957 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
958 cm_get_vdev_id_with_active_vdev_op,
959 &vdev_arg, 0,
960 WLAN_MLME_CM_ID);
961
962 /* For STA/CLI avoid the fist candidate itself if possible */
963 if (vdev_arg.sta_cli_vdev_id != WLAN_INVALID_VDEV_ID) {
964 mlme_info(CM_PREFIX_FMT "Abort connection as sta/cli vdev %d is disconnecting",
965 CM_PREFIX_REF(cur_vdev_id, cm_req->cm_id),
966 vdev_arg.sta_cli_vdev_id);
967 return true;
968 }
969
970 /*
971 * For SAP/GO ops pending avoid the next candidate, this is to support
972 * wifi sharing etc use case where we need to connect to AP in parallel
973 * to SAP operation, so try atleast one candidate.
974 */
975 if (cm_req->connect_req.cur_candidate &&
976 vdev_arg.sap_go_vdev_id != WLAN_INVALID_VDEV_ID) {
977 mlme_info(CM_PREFIX_FMT "Avoid next candidate as SAP/GO/NDI vdev %d has pending vdev op",
978 CM_PREFIX_REF(cur_vdev_id, cm_req->cm_id),
979 vdev_arg.sap_go_vdev_id);
980 return true;
981 }
982
983 return false;
984 }
985
986 QDF_STATUS
cm_inform_dlm_connect_complete(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * resp)987 cm_inform_dlm_connect_complete(struct wlan_objmgr_vdev *vdev,
988 struct wlan_cm_connect_resp *resp)
989 {
990 struct wlan_objmgr_pdev *pdev;
991
992 pdev = wlan_vdev_get_pdev(vdev);
993 if (!pdev) {
994 mlme_err(CM_PREFIX_FMT "Failed to find pdev",
995 CM_PREFIX_REF(wlan_vdev_get_id(vdev), resp->cm_id));
996 return QDF_STATUS_E_FAILURE;
997 }
998
999 if (QDF_IS_STATUS_SUCCESS(resp->connect_status))
1000 wlan_dlm_update_bssid_connect_params(pdev, resp->bssid,
1001 DLM_AP_CONNECTED);
1002
1003 return QDF_STATUS_SUCCESS;
1004 }
1005
1006 /**
1007 * cm_is_retry_with_same_candidate() - This API check if reconnect attempt is
1008 * required with the same candidate again
1009 * @cm_ctx: connection manager context
1010 * @req: Connect request.
1011 * @resp: connect resp from previous connection attempt
1012 *
1013 * This function return true if same candidate needs to be tried again
1014 *
1015 * Return: bool
1016 */
cm_is_retry_with_same_candidate(struct cnx_mgr * cm_ctx,struct cm_connect_req * req,struct wlan_cm_connect_resp * resp)1017 static bool cm_is_retry_with_same_candidate(struct cnx_mgr *cm_ctx,
1018 struct cm_connect_req *req,
1019 struct wlan_cm_connect_resp *resp)
1020 {
1021 uint8_t max_retry_count = CM_MAX_CANDIDATE_RETRIES;
1022 uint32_t key_mgmt;
1023 struct wlan_objmgr_psoc *psoc;
1024 bool sae_connection;
1025 bool is_mlo_vdev = false;
1026 QDF_STATUS status;
1027 uint8_t mlo_link_num;
1028 qdf_freq_t freq;
1029
1030 psoc = wlan_pdev_get_psoc(wlan_vdev_get_pdev(cm_ctx->vdev));
1031
1032 key_mgmt = req->cur_candidate->entry->neg_sec_info.key_mgmt;
1033 freq = req->cur_candidate->entry->channel.chan_freq;
1034
1035 is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(cm_ctx->vdev);
1036 mlo_link_num = wlan_mlme_get_sta_mlo_conn_max_num(psoc);
1037
1038 /* Try once again for the invalid PMKID case without PMKID or
1039 * Association request rejected temporarily; try again later
1040 */
1041 if (resp->status_code == STATUS_INVALID_PMKID ||
1042 resp->status_code == STATUS_ASSOC_REJECTED_TEMPORARILY)
1043 goto use_same_candidate;
1044
1045 sae_connection = key_mgmt & (1 << WLAN_CRYPTO_KEY_MGMT_SAE |
1046 1 << WLAN_CRYPTO_KEY_MGMT_FT_SAE |
1047 1 << WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY |
1048 1 << WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY);
1049
1050 /* For SAE use max retry count from INI */
1051 if (sae_connection)
1052 wlan_mlme_get_sae_assoc_retry_count(psoc, &max_retry_count);
1053
1054 /* Try again for the JOIN timeout if only one candidate */
1055 if (resp->reason == CM_JOIN_TIMEOUT &&
1056 qdf_list_size(req->candidate_list) == 1) {
1057 /*
1058 * If there is a interface connected which can lead to MCC,
1059 * do not retry as it can lead to beacon miss on that interface.
1060 * Coz as part of vdev start mac remain on candidate freq for 3
1061 * sec.
1062 */
1063 if (policy_mgr_will_freq_lead_to_mcc(psoc, freq))
1064 return false;
1065
1066 goto use_same_candidate;
1067 }
1068
1069 /*
1070 * Try again for the ASSOC timeout in SAE connection or
1071 * AP has reconnect on assoc timeout OUI.
1072 */
1073 if (resp->reason == CM_ASSOC_TIMEOUT && (sae_connection ||
1074 (mlme_get_reconn_after_assoc_timeout_flag(psoc, resp->vdev_id)))) {
1075
1076 goto use_same_candidate;
1077 }
1078
1079 return false;
1080
1081 use_same_candidate:
1082 if (req->cur_candidate_retries >= max_retry_count)
1083 return false;
1084
1085 status = cm_if_mgr_validate_candidate(cm_ctx,
1086 req->cur_candidate->entry);
1087 if (QDF_IS_STATUS_ERROR(status))
1088 return false;
1089
1090 mlme_info(CM_PREFIX_FMT "Retry again with " QDF_MAC_ADDR_FMT ", status code %d reason %d key_mgmt 0x%x retry count %d max retry %d",
1091 CM_PREFIX_REF(resp->vdev_id, resp->cm_id),
1092 QDF_MAC_ADDR_REF(resp->bssid.bytes), resp->status_code,
1093 resp->reason, key_mgmt, req->cur_candidate_retries,
1094 max_retry_count);
1095
1096 req->cur_candidate_retries++;
1097
1098 return true;
1099 }
1100
1101 /*
1102 * Do not allow last connect attempt after 25 sec, assuming last attempt will
1103 * complete in max 10 sec, total connect time will not be more than 35 sec.
1104 * Do not confuse this with active command timeout, that is taken care by
1105 * CM_MAX_PER_CANDIDATE_CONNECT_TIMEOUT
1106 */
1107 #define CM_CONNECT_MAX_ACTIVE_TIME 25000
1108
1109 /**
1110 * cm_is_time_allowed_for_connect_attempt() - This API check if next connect
1111 * attempt can be tried within allocated time.
1112 * @cm_ctx: connection manager context
1113 * @req: Connect request.
1114 *
1115 * This function return true if connect attempt can be tried so that total time
1116 * taken by connect req do not exceed 30-35 seconds.
1117 *
1118 * Return: bool
1119 */
cm_is_time_allowed_for_connect_attempt(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)1120 static bool cm_is_time_allowed_for_connect_attempt(struct cnx_mgr *cm_ctx,
1121 struct cm_connect_req *req)
1122 {
1123 qdf_time_t time_since_connect_active;
1124 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
1125
1126 time_since_connect_active = qdf_mc_timer_get_system_time() -
1127 req->connect_active_time;
1128 if (time_since_connect_active >= CM_CONNECT_MAX_ACTIVE_TIME) {
1129 mlme_info(CM_PREFIX_FMT "Max time allocated (%d ms) for connect completed, cur time %lu, active time %lu and diff %lu",
1130 CM_PREFIX_REF(vdev_id, req->cm_id),
1131 CM_CONNECT_MAX_ACTIVE_TIME,
1132 qdf_mc_timer_get_system_time(),
1133 req->connect_active_time,
1134 time_since_connect_active);
1135 return false;
1136 }
1137
1138 return true;
1139 }
1140
cm_update_advance_filter(struct wlan_objmgr_pdev * pdev,struct cnx_mgr * cm_ctx,struct scan_filter * filter,struct cm_connect_req * cm_req)1141 static inline void cm_update_advance_filter(struct wlan_objmgr_pdev *pdev,
1142 struct cnx_mgr *cm_ctx,
1143 struct scan_filter *filter,
1144 struct cm_connect_req *cm_req)
1145 {
1146 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
1147
1148 /* Select only ESS type */
1149 filter->bss_type = WLAN_TYPE_BSS;
1150 filter->enable_adaptive_11r =
1151 wlan_mlme_adaptive_11r_enabled(psoc);
1152 if (wlan_vdev_mlme_get_opmode(cm_ctx->vdev) != QDF_STA_MODE)
1153 return;
1154 /* For link vdev, we don't filter any channels.
1155 * Dual STA mode, one link can be disabled in post connection
1156 * if needed.
1157 */
1158 if (!cm_req->req.is_non_assoc_link)
1159 wlan_cm_dual_sta_roam_update_connect_channels(psoc, filter);
1160 filter->dot11mode = cm_req->req.dot11mode_filter;
1161 cm_update_fils_scan_filter(filter, cm_req);
1162 }
1163
cm_update_security_filter(struct scan_filter * filter,struct wlan_cm_connect_req * req)1164 static void cm_update_security_filter(struct scan_filter *filter,
1165 struct wlan_cm_connect_req *req)
1166 {
1167 /* Ignore security match for rsn override, OSEN and WPS connection */
1168 if (req->force_rsne_override || req->is_wps_connection ||
1169 req->is_osen_connection) {
1170 filter->ignore_auth_enc_type = 1;
1171 return;
1172 }
1173
1174 filter->authmodeset = req->crypto.auth_type;
1175 filter->ucastcipherset = req->crypto.ciphers_pairwise;
1176 filter->key_mgmt = req->crypto.akm_suites;
1177 filter->mcastcipherset = req->crypto.group_cipher;
1178 filter->mgmtcipherset = req->crypto.mgmt_ciphers;
1179 cm_set_pmf_caps(req, filter);
1180 }
1181
1182 /**
1183 * cm_set_fils_wep_key() - check and set wep or fils keys if required
1184 * @cm_ctx: connection manager context
1185 * @resp: connect resp
1186 *
1187 * Context: Can be called from any context and to be used only after posting a
1188 * msg to SM (ie holding the SM lock) i.e. on successful connection.
1189 */
cm_set_fils_wep_key(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)1190 static void cm_set_fils_wep_key(struct cnx_mgr *cm_ctx,
1191 struct wlan_cm_connect_resp *resp)
1192 {
1193 int32_t cipher;
1194 struct qdf_mac_addr broadcast_mac = QDF_MAC_ADDR_BCAST_INIT;
1195
1196 /* Check and set FILS keys */
1197 if (cm_is_fils_connection(resp)) {
1198 cm_set_fils_key(cm_ctx, resp);
1199 return;
1200 }
1201 /* Check and set WEP keys */
1202 cipher = wlan_crypto_get_param(cm_ctx->vdev,
1203 WLAN_CRYPTO_PARAM_UCAST_CIPHER);
1204 if (cipher < 0)
1205 return;
1206
1207 if (!(cipher & (1 << WLAN_CRYPTO_CIPHER_WEP_40 |
1208 1 << WLAN_CRYPTO_CIPHER_WEP_104)))
1209 return;
1210
1211 cm_set_key(cm_ctx, true, 0, &resp->bssid);
1212 cm_set_key(cm_ctx, false, 0, &broadcast_mac);
1213 }
1214
cm_teardown_tdls(struct wlan_objmgr_vdev * vdev)1215 static void cm_teardown_tdls(struct wlan_objmgr_vdev *vdev)
1216 {
1217 struct wlan_objmgr_psoc *psoc;
1218
1219 psoc = wlan_vdev_get_psoc(vdev);
1220 if (!psoc)
1221 return;
1222
1223 wlan_tdls_check_and_teardown_links_sync(psoc, vdev);
1224 }
1225
cm_handle_connect_start_req(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req)1226 static void cm_handle_connect_start_req(struct wlan_objmgr_vdev *vdev,
1227 struct wlan_cm_connect_req *req)
1228 {
1229 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
1230 cm_teardown_tdls(vdev);
1231
1232 wlan_cm_set_force_20mhz_in_24ghz(vdev,
1233 req->ht_caps & WLAN_HTCAP_C_CHWIDTH40);
1234 }
1235
1236 #else
1237 static inline bool
cm_is_any_other_vdev_connecting_disconnecting(struct cnx_mgr * cm_ctx,struct cm_req * cm_req)1238 cm_is_any_other_vdev_connecting_disconnecting(struct cnx_mgr *cm_ctx,
1239 struct cm_req *cm_req)
1240 {
1241 return false;
1242 }
1243
1244 static inline
cm_is_retry_with_same_candidate(struct cnx_mgr * cm_ctx,struct cm_connect_req * req,struct wlan_cm_connect_resp * resp)1245 bool cm_is_retry_with_same_candidate(struct cnx_mgr *cm_ctx,
1246 struct cm_connect_req *req,
1247 struct wlan_cm_connect_resp *resp)
1248 {
1249 return false;
1250 }
1251
1252 static inline
cm_is_time_allowed_for_connect_attempt(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)1253 bool cm_is_time_allowed_for_connect_attempt(struct cnx_mgr *cm_ctx,
1254 struct cm_connect_req *req)
1255 {
1256 return true;
1257 }
1258
cm_update_advance_filter(struct wlan_objmgr_pdev * pdev,struct cnx_mgr * cm_ctx,struct scan_filter * filter,struct cm_connect_req * cm_req)1259 static inline void cm_update_advance_filter(struct wlan_objmgr_pdev *pdev,
1260 struct cnx_mgr *cm_ctx,
1261 struct scan_filter *filter,
1262 struct cm_connect_req *cm_req)
1263 {
1264 struct wlan_objmgr_vdev *vdev = cm_ctx->vdev;
1265
1266 if (cm_ctx->cm_candidate_advance_filter)
1267 cm_ctx->cm_candidate_advance_filter(vdev, filter);
1268 }
1269
cm_update_security_filter(struct scan_filter * filter,struct wlan_cm_connect_req * req)1270 static void cm_update_security_filter(struct scan_filter *filter,
1271 struct wlan_cm_connect_req *req)
1272 {
1273 if (!QDF_HAS_PARAM(req->crypto.auth_type, WLAN_CRYPTO_AUTH_WAPI) &&
1274 !QDF_HAS_PARAM(req->crypto.auth_type, WLAN_CRYPTO_AUTH_RSNA) &&
1275 !QDF_HAS_PARAM(req->crypto.auth_type, WLAN_CRYPTO_AUTH_WPA)) {
1276 filter->ignore_auth_enc_type = 1;
1277 return;
1278 }
1279
1280 filter->authmodeset = req->crypto.auth_type;
1281 filter->ucastcipherset = req->crypto.ciphers_pairwise;
1282 filter->key_mgmt = req->crypto.akm_suites;
1283 filter->mcastcipherset = req->crypto.group_cipher;
1284 filter->mgmtcipherset = req->crypto.mgmt_ciphers;
1285 cm_set_pmf_caps(req, filter);
1286 }
1287
cm_set_fils_wep_key(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)1288 static inline void cm_set_fils_wep_key(struct cnx_mgr *cm_ctx,
1289 struct wlan_cm_connect_resp *resp)
1290 {}
1291
1292 QDF_STATUS
cm_peer_create_on_bss_select_ind_resp(struct cnx_mgr * cm_ctx,wlan_cm_id * cm_id)1293 cm_peer_create_on_bss_select_ind_resp(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
1294 {
1295 struct cm_req *cm_req;
1296
1297 cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
1298 if (!cm_req)
1299 return QDF_STATUS_E_FAILURE;
1300
1301 /* Update vdev mlme mac address based on connection type */
1302 cm_update_vdev_mlme_macaddr(cm_ctx, &cm_req->connect_req);
1303
1304 cm_create_bss_peer(cm_ctx, &cm_req->connect_req);
1305
1306 return QDF_STATUS_SUCCESS;
1307 }
1308
cm_bss_select_ind_rsp(struct wlan_objmgr_vdev * vdev,QDF_STATUS status)1309 QDF_STATUS cm_bss_select_ind_rsp(struct wlan_objmgr_vdev *vdev,
1310 QDF_STATUS status)
1311 {
1312 struct cnx_mgr *cm_ctx;
1313 QDF_STATUS qdf_status;
1314 wlan_cm_id cm_id;
1315 uint32_t prefix;
1316 struct wlan_cm_connect_resp *resp;
1317
1318 cm_ctx = cm_get_cm_ctx(vdev);
1319 if (!cm_ctx)
1320 return QDF_STATUS_E_INVAL;
1321
1322 cm_id = cm_ctx->active_cm_id;
1323 prefix = CM_ID_GET_PREFIX(cm_id);
1324
1325 if (prefix != CONNECT_REQ_PREFIX) {
1326 mlme_err(CM_PREFIX_FMT "active req is not connect req",
1327 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
1328 return QDF_STATUS_E_INVAL;
1329 }
1330
1331 if (QDF_IS_STATUS_SUCCESS(status)) {
1332 qdf_status =
1333 cm_sm_deliver_event(vdev,
1334 WLAN_CM_SM_EV_BSS_SELECT_IND_SUCCESS,
1335 sizeof(wlan_cm_id), &cm_id);
1336 if (QDF_IS_STATUS_SUCCESS(qdf_status))
1337 return qdf_status;
1338
1339 goto post_err;
1340 }
1341
1342 /* In case of failure try with next candidate */
1343 resp = qdf_mem_malloc(sizeof(*resp));
1344 if (!resp) {
1345 qdf_status = QDF_STATUS_E_NOMEM;
1346 goto post_err;
1347 }
1348
1349 cm_fill_failure_resp_from_cm_id(cm_ctx, resp, cm_id,
1350 CM_BSS_SELECT_IND_FAILED);
1351 qdf_status =
1352 cm_sm_deliver_event(vdev,
1353 WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE,
1354 sizeof(*resp), resp);
1355 qdf_mem_free(resp);
1356 if (QDF_IS_STATUS_SUCCESS(qdf_status))
1357 return qdf_status;
1358
1359 post_err:
1360 /*
1361 * If there is a event posting error it means the SM state is not in
1362 * JOIN ACTIVE (some new cmd has changed the state of SM), so just
1363 * complete the connect command.
1364 */
1365 cm_connect_handle_event_post_fail(cm_ctx, cm_id);
1366 return qdf_status;
1367 }
1368
cm_teardown_tdls(struct wlan_objmgr_vdev * vdev)1369 static inline void cm_teardown_tdls(struct wlan_objmgr_vdev *vdev) {}
1370
cm_handle_connect_start_req(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req)1371 static inline void cm_handle_connect_start_req(struct wlan_objmgr_vdev *vdev,
1372 struct wlan_cm_connect_req *req)
1373 {
1374 }
1375
1376 #endif /* CONN_MGR_ADV_FEATURE */
1377
cm_connect_prepare_scan_filter(struct wlan_objmgr_pdev * pdev,struct cnx_mgr * cm_ctx,struct cm_connect_req * cm_req,struct scan_filter * filter,bool security_valid_for_6ghz)1378 static void cm_connect_prepare_scan_filter(struct wlan_objmgr_pdev *pdev,
1379 struct cnx_mgr *cm_ctx,
1380 struct cm_connect_req *cm_req,
1381 struct scan_filter *filter,
1382 bool security_valid_for_6ghz)
1383 {
1384 if (!qdf_is_macaddr_zero(&cm_req->req.bssid)) {
1385 filter->num_of_bssid = 1;
1386 qdf_copy_macaddr(&filter->bssid_list[0], &cm_req->req.bssid);
1387 }
1388
1389 qdf_copy_macaddr(&filter->bssid_hint, &cm_req->req.bssid_hint);
1390 filter->num_of_ssid = 1;
1391 qdf_mem_copy(&filter->ssid_list[0], &cm_req->req.ssid,
1392 sizeof(struct wlan_ssid));
1393
1394 if (cm_req->req.chan_freq) {
1395 filter->num_of_channels = 1;
1396 filter->chan_freq_list[0] = cm_req->req.chan_freq;
1397 }
1398
1399 /* Security is not valid for 6Ghz so ignore 6Ghz APs */
1400 if (!security_valid_for_6ghz)
1401 filter->ignore_6ghz_channel = true;
1402
1403 if (cm_req->req.is_non_assoc_link)
1404 filter->ignore_6ghz_channel = false;
1405
1406 cm_update_security_filter(filter, &cm_req->req);
1407 cm_update_advance_filter(pdev, cm_ctx, filter, cm_req);
1408 }
1409
1410 #ifdef WLAN_FEATURE_11BE_MLO
1411 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
cm_is_scan_support(struct cm_connect_req * cm_req)1412 static QDF_STATUS cm_is_scan_support(struct cm_connect_req *cm_req)
1413 {
1414 if (cm_req->req.is_non_assoc_link)
1415 return QDF_STATUS_E_FAILURE;
1416
1417 return QDF_STATUS_SUCCESS;
1418 }
1419 #else
cm_is_scan_support(struct cm_connect_req * cm_req)1420 static QDF_STATUS cm_is_scan_support(struct cm_connect_req *cm_req)
1421 {
1422 if (cm_req->req.ml_parnter_info.num_partner_links)
1423 return QDF_STATUS_E_FAILURE;
1424
1425 return QDF_STATUS_SUCCESS;
1426 }
1427 #endif
1428 #else
cm_is_scan_support(struct cm_connect_req * cm_req)1429 static QDF_STATUS cm_is_scan_support(struct cm_connect_req *cm_req)
1430 {
1431 return QDF_STATUS_SUCCESS;
1432 }
1433 #endif
1434
1435 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE)
1436 #define CFG_MLO_ASSOC_LINK_BAND_MAX 0x70
1437
cm_update_mlo_filter(struct wlan_objmgr_pdev * pdev,struct cm_connect_req * cm_req,struct scan_filter * filter)1438 static QDF_STATUS cm_update_mlo_filter(struct wlan_objmgr_pdev *pdev,
1439 struct cm_connect_req *cm_req,
1440 struct scan_filter *filter)
1441 {
1442 struct wlan_objmgr_psoc *psoc;
1443
1444 psoc = wlan_pdev_get_psoc(pdev);
1445 filter->band_bitmap = wlan_mlme_get_sta_mlo_conn_band_bmp(psoc);
1446 /* Apply assoc band filter only for assoc link */
1447 if (cm_req->req.is_non_assoc_link) {
1448 filter->band_bitmap =
1449 filter->band_bitmap | CFG_MLO_ASSOC_LINK_BAND_MAX;
1450 /* Only select entry which matches MLD address filter for
1451 * link VDEV connect, to avoid assoc/link VDEV selecting
1452 * candidates with different MLD address.
1453 */
1454 filter->match_mld_addr = true;
1455 qdf_copy_macaddr(&filter->mld_addr, &cm_req->req.mld_addr);
1456 }
1457
1458 mlme_debug(CM_PREFIX_FMT "band bitmap: 0x%x",
1459 CM_PREFIX_REF(cm_req->req.vdev_id, cm_req->cm_id),
1460 filter->band_bitmap);
1461
1462 return QDF_STATUS_SUCCESS;
1463 }
1464
cm_remove_mbssid_links_without_scan_entry(qdf_list_t * candidate_list)1465 static QDF_STATUS cm_remove_mbssid_links_without_scan_entry(
1466 qdf_list_t *candidate_list)
1467 {
1468 struct scan_cache_node *scan_node = NULL;
1469 struct scan_cache_entry *partner_entry = NULL, *scan_entry = NULL;
1470 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1471 struct partner_link_info *partner_info;
1472 struct qdf_mac_addr *mld_addr;
1473 uint8_t i = 0;
1474
1475 if (qdf_list_peek_front(candidate_list,
1476 &cur_node) != QDF_STATUS_SUCCESS) {
1477 mlme_err("Failed to dequeue");
1478 return QDF_STATUS_E_FAILURE;
1479 }
1480
1481 while (cur_node) {
1482 qdf_list_peek_next(candidate_list, cur_node, &next_node);
1483 scan_node = qdf_container_of(cur_node, struct scan_cache_node,
1484 node);
1485 scan_entry = scan_node->entry;
1486 mld_addr = util_scan_entry_mldaddr(scan_entry);
1487
1488 if (!scan_entry->mbssid_info.profile_num || !mld_addr)
1489 goto next_entry;
1490
1491 /*
1492 * Mark the links of an MBSSID partner as invalid if there
1493 * is no scan entry for the link at the time of the candidate
1494 * selection.
1495 *
1496 * For MBSSID candidates, ML-probe request would not be sent,
1497 * during join phase, therefore the scan entry would not be
1498 * created anytime before the association.
1499 *
1500 */
1501 for (i = 0; i < scan_entry->ml_info.num_links; i++) {
1502 if (!scan_entry->ml_info.link_info[i].is_valid_link)
1503 continue;
1504
1505 partner_info = &scan_entry->ml_info.link_info[i];
1506 partner_entry = cm_get_entry(candidate_list,
1507 &partner_info->link_addr);
1508
1509 if (!partner_entry ||
1510 !qdf_is_macaddr_equal(mld_addr,
1511 &partner_entry->ml_info.mld_mac_addr)) {
1512 scan_entry->ml_info.link_info[i].is_valid_link = false;
1513 mlme_debug("Scan entry is not present for link idx %d, drop the link",
1514 scan_entry->ml_info.link_info[i].link_id);
1515 }
1516 }
1517 next_entry:
1518 cur_node = next_node;
1519 next_node = NULL;
1520 }
1521
1522 return QDF_STATUS_SUCCESS;
1523 }
1524
1525 #else
cm_update_mlo_filter(struct wlan_objmgr_pdev * pdev,struct cm_connect_req * cm_req,struct scan_filter * filter)1526 static QDF_STATUS cm_update_mlo_filter(struct wlan_objmgr_pdev *pdev,
1527 struct cm_connect_req *cm_req,
1528 struct scan_filter *filter)
1529 {
1530 return QDF_STATUS_SUCCESS;
1531 }
1532
cm_remove_mbssid_links_without_scan_entry(qdf_list_t * candidate_list)1533 static QDF_STATUS cm_remove_mbssid_links_without_scan_entry(
1534 qdf_list_t *candidate_list)
1535 {
1536 return QDF_STATUS_SUCCESS;
1537 }
1538 #endif
1539
1540 static QDF_STATUS
cm_connect_fetch_candidates(struct wlan_objmgr_pdev * pdev,struct cnx_mgr * cm_ctx,struct cm_connect_req * cm_req,qdf_list_t ** fetched_candidate_list,uint32_t * num_bss_found)1541 cm_connect_fetch_candidates(struct wlan_objmgr_pdev *pdev,
1542 struct cnx_mgr *cm_ctx,
1543 struct cm_connect_req *cm_req,
1544 qdf_list_t **fetched_candidate_list,
1545 uint32_t *num_bss_found)
1546 {
1547 struct scan_filter *filter;
1548 uint32_t num_bss = 0;
1549 enum QDF_OPMODE op_mode;
1550 qdf_list_t *candidate_list;
1551 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
1552 bool security_valid_for_6ghz;
1553 const uint8_t *rsnxe;
1554
1555 rsnxe = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE,
1556 cm_req->req.assoc_ie.ptr,
1557 cm_req->req.assoc_ie.len);
1558 security_valid_for_6ghz =
1559 wlan_cm_6ghz_allowed_for_akm(wlan_pdev_get_psoc(pdev),
1560 cm_req->req.crypto.akm_suites,
1561 cm_req->req.crypto.rsn_caps,
1562 rsnxe, cm_req->req.sae_pwe,
1563 cm_req->req.is_wps_connection);
1564
1565 /*
1566 * Ignore connect req if the freq is provided and its 6Ghz and
1567 * security is not valid for 6Ghz
1568 */
1569 if (cm_req->req.chan_freq && !security_valid_for_6ghz &&
1570 WLAN_REG_IS_6GHZ_CHAN_FREQ(cm_req->req.chan_freq)) {
1571 mlme_info(CM_PREFIX_FMT "6ghz freq (%d) given and 6Ghz not allowed for the security in connect req",
1572 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
1573 cm_req->req.chan_freq);
1574 return QDF_STATUS_E_INVAL;
1575 }
1576 filter = qdf_mem_malloc(sizeof(*filter));
1577 if (!filter)
1578 return QDF_STATUS_E_NOMEM;
1579
1580 cm_connect_prepare_scan_filter(pdev, cm_ctx, cm_req, filter,
1581 security_valid_for_6ghz);
1582
1583 cm_update_mlo_filter(pdev, cm_req, filter);
1584
1585 candidate_list = wlan_scan_get_result(pdev, filter);
1586 if (candidate_list) {
1587 num_bss = qdf_list_size(candidate_list);
1588 mlme_debug(CM_PREFIX_FMT "num_entries found %d",
1589 CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss);
1590 }
1591 *num_bss_found = num_bss;
1592
1593 if (num_bss && !wlan_vdev_mlme_is_mlo_link_vdev(cm_ctx->vdev))
1594 cm_remove_mbssid_links_without_scan_entry(candidate_list);
1595
1596 op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev);
1597 if (num_bss && op_mode == QDF_STA_MODE &&
1598 !cm_req->req.is_non_assoc_link)
1599 cm_calculate_scores(cm_ctx, pdev, filter, candidate_list);
1600 qdf_mem_free(filter);
1601
1602 if (!candidate_list || !qdf_list_size(candidate_list)) {
1603 if (candidate_list)
1604 wlan_scan_purge_results(candidate_list);
1605 return QDF_STATUS_E_EMPTY;
1606 }
1607 *fetched_candidate_list = candidate_list;
1608
1609 return QDF_STATUS_SUCCESS;
1610 }
1611
cm_connect_get_candidates(struct wlan_objmgr_pdev * pdev,struct cnx_mgr * cm_ctx,struct cm_connect_req * cm_req)1612 static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev,
1613 struct cnx_mgr *cm_ctx,
1614 struct cm_connect_req *cm_req)
1615 {
1616 uint32_t num_bss = 0;
1617 qdf_list_t *candidate_list = NULL;
1618 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
1619 QDF_STATUS status;
1620
1621 status = cm_connect_fetch_candidates(pdev, cm_ctx, cm_req,
1622 &candidate_list, &num_bss);
1623 if (QDF_IS_STATUS_ERROR(status)) {
1624 if (candidate_list)
1625 wlan_scan_purge_results(candidate_list);
1626 mlme_info(CM_PREFIX_FMT "no valid candidate found, num_bss %d scan_id %d",
1627 CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss,
1628 cm_req->scan_id);
1629
1630 /*
1631 * If connect scan was already done OR candidate were found
1632 * but none of them were valid OR if ML link connection
1633 * return QDF_STATUS_E_EMPTY.
1634 */
1635 if (cm_req->scan_id || num_bss ||
1636 QDF_IS_STATUS_ERROR(cm_is_scan_support(cm_req)))
1637 return QDF_STATUS_E_EMPTY;
1638
1639 /* Try connect scan to search for any valid candidate */
1640 status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_SCAN,
1641 sizeof(*cm_req), cm_req);
1642 /*
1643 * If connect scan is initiated, return pending, so that
1644 * connect start after scan complete
1645 */
1646 if (QDF_IS_STATUS_SUCCESS(status))
1647 status = QDF_STATUS_E_PENDING;
1648
1649 return status;
1650 }
1651 cm_req->candidate_list = candidate_list;
1652
1653 return status;
1654 }
1655
1656 #ifdef CONN_MGR_ADV_FEATURE
cm_update_candidate_list(struct cnx_mgr * cm_ctx,struct cm_connect_req * cm_req,struct scan_cache_node * prev_candidate)1657 static void cm_update_candidate_list(struct cnx_mgr *cm_ctx,
1658 struct cm_connect_req *cm_req,
1659 struct scan_cache_node *prev_candidate)
1660 {
1661 struct wlan_objmgr_pdev *pdev;
1662 uint32_t num_bss = 0;
1663 qdf_list_t *candidate_list = NULL;
1664 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
1665 QDF_STATUS status;
1666 struct scan_cache_node *scan_entry;
1667 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1668 struct qdf_mac_addr *bssid;
1669 bool found;
1670
1671 pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
1672 if (!pdev) {
1673 mlme_err(CM_PREFIX_FMT "Failed to find pdev",
1674 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
1675 return;
1676 }
1677
1678 status = cm_connect_fetch_candidates(pdev, cm_ctx, cm_req,
1679 &candidate_list, &num_bss);
1680 if (QDF_IS_STATUS_ERROR(status)) {
1681 mlme_debug(CM_PREFIX_FMT "failed to fetch bss: %d",
1682 CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss);
1683 goto free_list;
1684 }
1685
1686 if (qdf_list_peek_front(candidate_list, &cur_node) !=
1687 QDF_STATUS_SUCCESS) {
1688 mlme_err(CM_PREFIX_FMT "failed to peer front of candidate_list",
1689 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
1690 goto free_list;
1691 }
1692
1693 while (cur_node) {
1694 qdf_list_peek_next(candidate_list, cur_node, &next_node);
1695
1696 scan_entry = qdf_container_of(cur_node, struct scan_cache_node,
1697 node);
1698 bssid = &scan_entry->entry->bssid;
1699 if (qdf_is_macaddr_zero(bssid) ||
1700 qdf_is_macaddr_broadcast(bssid))
1701 goto next;
1702 found = cm_find_bss_from_candidate_list(cm_req->candidate_list,
1703 bssid, NULL);
1704 if (found)
1705 goto next;
1706 status = qdf_list_remove_node(candidate_list, cur_node);
1707 if (QDF_IS_STATUS_ERROR(status)) {
1708 mlme_err(CM_PREFIX_FMT "failed to remove node for " QDF_MAC_ADDR_FMT " from candidate list",
1709 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
1710 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes));
1711 goto free_list;
1712 }
1713
1714 status = qdf_list_insert_after(cm_req->candidate_list,
1715 &scan_entry->node,
1716 &prev_candidate->node);
1717 if (QDF_IS_STATUS_ERROR(status)) {
1718 mlme_err(CM_PREFIX_FMT "failed to insert node for " QDF_MAC_ADDR_FMT " to candidate list",
1719 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
1720 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes));
1721 util_scan_free_cache_entry(scan_entry->entry);
1722 qdf_mem_free(scan_entry);
1723 goto free_list;
1724 }
1725 prev_candidate = scan_entry;
1726 mlme_debug(CM_PREFIX_FMT "insert new node " QDF_MAC_ADDR_FMT " to candidate list",
1727 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
1728 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes));
1729 next:
1730 cur_node = next_node;
1731 next_node = NULL;
1732 }
1733 /* print updated candidate list */
1734 mlme_debug(CM_PREFIX_FMT "updated candidate list",
1735 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
1736 cm_print_candidate_list(cm_req->candidate_list);
1737 free_list:
1738 if (candidate_list)
1739 wlan_scan_purge_results(candidate_list);
1740 }
1741 #else
1742 static inline void
cm_update_candidate_list(struct cnx_mgr * cm_ctx,struct cm_connect_req * cm_req,struct scan_cache_node * prev_candidate)1743 cm_update_candidate_list(struct cnx_mgr *cm_ctx,
1744 struct cm_connect_req *cm_req,
1745 struct scan_cache_node *prev_candidate)
1746 {
1747 }
1748 #endif
1749
cm_if_mgr_inform_connect_complete(struct wlan_objmgr_vdev * vdev,QDF_STATUS connect_status)1750 QDF_STATUS cm_if_mgr_inform_connect_complete(struct wlan_objmgr_vdev *vdev,
1751 QDF_STATUS connect_status)
1752 {
1753 struct if_mgr_event_data *connect_complete;
1754
1755 connect_complete = qdf_mem_malloc(sizeof(*connect_complete));
1756 if (!connect_complete)
1757 return QDF_STATUS_E_NOMEM;
1758
1759 connect_complete->status = connect_status;
1760 if_mgr_deliver_event(vdev, WLAN_IF_MGR_EV_CONNECT_COMPLETE,
1761 connect_complete);
1762 qdf_mem_free(connect_complete);
1763
1764 return QDF_STATUS_SUCCESS;
1765 }
1766
1767 static QDF_STATUS
cm_if_mgr_inform_connect_start(struct wlan_objmgr_vdev * vdev)1768 cm_if_mgr_inform_connect_start(struct wlan_objmgr_vdev *vdev)
1769 {
1770 return if_mgr_deliver_event(vdev, WLAN_IF_MGR_EV_CONNECT_START, NULL);
1771 }
1772
1773 QDF_STATUS
cm_handle_connect_req_in_non_init_state(struct cnx_mgr * cm_ctx,struct cm_connect_req * cm_req,enum wlan_cm_sm_state cm_state_substate)1774 cm_handle_connect_req_in_non_init_state(struct cnx_mgr *cm_ctx,
1775 struct cm_connect_req *cm_req,
1776 enum wlan_cm_sm_state cm_state_substate)
1777 {
1778 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
1779
1780 /*
1781 * Connect re-assoc req should have been received in one of the
1782 * following states:
1783 * a) SB disconnect in progress
1784 * b) Roam start/Roam sync in progress
1785 * c) Reassoc
1786 * d) Connected state with LFR3 disabled
1787 * e) Invalid Roam request
1788 *
1789 * In this case, set reassoc_in_non_init flag, so that disconnect can
1790 * be notified to the upper layers if connect request fails. This is
1791 * required by upper layers to clear the connection state of the
1792 * previous connection.
1793 */
1794 if (cm_is_connect_req_reassoc(&cm_req->req)) {
1795 cm_req->req.reassoc_in_non_init = true;
1796 mlme_debug(CM_PREFIX_FMT "Reassoc received in %d state",
1797 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
1798 cm_state_substate);
1799 }
1800
1801 /* Reject any link switch connect request while in non-init state */
1802 if (cm_is_link_switch_connect_req(cm_req)) {
1803 mlme_info(CM_PREFIX_FMT "Ignore connect req from source %d state %d",
1804 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
1805 cm_req->req.source, cm_state_substate);
1806 return QDF_STATUS_E_INVAL;
1807 }
1808
1809 switch (cm_state_substate) {
1810 case WLAN_CM_S_ROAMING:
1811 /* for FW roam/LFR3 remove the req from the list */
1812 if (cm_roam_offload_enabled(wlan_vdev_get_psoc(cm_ctx->vdev)))
1813 cm_flush_pending_request(cm_ctx, ROAM_REQ_PREFIX,
1814 false);
1815 fallthrough;
1816 case WLAN_CM_S_CONNECTED:
1817 case WLAN_CM_SS_JOIN_ACTIVE:
1818 /*
1819 * In roaming state, there would be no
1820 * pending command, so for new connect request, queue internal
1821 * disconnect. The preauth and reassoc process will be aborted
1822 * as the state machine will be moved to connecting state and
1823 * preauth/reassoc/roam start event posting will fail.
1824 *
1825 * In connected state, there would be no pending command, so
1826 * for new connect request, queue internal disconnect
1827 *
1828 * In join active state there would be only one active connect
1829 * request in the cm req list, so to abort at certain stages and
1830 * to cleanup after its completion, queue internal disconnect.
1831 */
1832 cm_initiate_internal_disconnect(cm_ctx);
1833 break;
1834 case WLAN_CM_SS_SCAN:
1835 /* In the scan state abort the ongoing scan */
1836 cm_vdev_scan_cancel(wlan_vdev_get_pdev(cm_ctx->vdev),
1837 cm_ctx->vdev);
1838 fallthrough;
1839 case WLAN_CM_SS_JOIN_PENDING:
1840 /*
1841 * In case of scan or join pending there could be 2 scenarios:-
1842 *
1843 * 1. There is a connect request pending, so just remove
1844 * the pending connect req. As we will queue a new connect
1845 * req, all resp for pending connect req will be dropped.
1846 * 2. There is a connect request in active and
1847 * and a internal disconnect followed by a connect req in
1848 * pending. In this case the disconnect will take care of
1849 * cleaning up the active connect request and thus only
1850 * remove the pending connect.
1851 */
1852 cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX, false);
1853 break;
1854 case WLAN_CM_S_DISCONNECTING:
1855 /*
1856 * Flush failed pending connect req as new req is received
1857 * and its no longer the latest one.
1858 */
1859 if (cm_ctx->connect_count)
1860 cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX,
1861 true);
1862 /*
1863 * In case of disconnecting state, there could be 2 scenarios:-
1864 * In both case no state specific action is required.
1865 * 1. There is disconnect request in the cm_req list, no action
1866 * required to cleanup.
1867 * so just add the connect request to the list.
1868 * 2. There is a connect request activated, followed by
1869 * disconnect in pending queue. So keep the disconnect
1870 * to cleanup the active connect and no action required to
1871 * cleanup.
1872 */
1873 break;
1874 default:
1875 mlme_err(CM_PREFIX_FMT "Connect req in invalid state %d",
1876 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
1877 cm_state_substate);
1878 return QDF_STATUS_E_FAILURE;
1879 };
1880
1881 /* Queue the new connect request after state specific actions */
1882 return cm_add_connect_req_to_list(cm_ctx, cm_req);
1883 }
1884
cm_connect_start(struct cnx_mgr * cm_ctx,struct cm_connect_req * cm_req)1885 QDF_STATUS cm_connect_start(struct cnx_mgr *cm_ctx,
1886 struct cm_connect_req *cm_req)
1887 {
1888 struct wlan_objmgr_pdev *pdev;
1889 struct wlan_objmgr_psoc *psoc;
1890 enum wlan_cm_connect_fail_reason reason = CM_GENERIC_FAILURE;
1891 QDF_STATUS status;
1892 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
1893
1894 /* Interface event */
1895 pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
1896 if (!pdev) {
1897 mlme_err(CM_PREFIX_FMT "Failed to find pdev",
1898 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
1899 goto connect_err;
1900 }
1901
1902 psoc = wlan_pdev_get_psoc(pdev);
1903 if (!psoc) {
1904 mlme_err(CM_PREFIX_FMT "Failed to find psoc",
1905 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
1906 goto connect_err;
1907 }
1908
1909 /*
1910 * Do not initiate the duplicate ifmanager and connect start ind if
1911 * this is called from Scan for ssid
1912 */
1913 if (!cm_req->scan_id) {
1914 cm_if_mgr_inform_connect_start(cm_ctx->vdev);
1915 status = mlme_cm_connect_start_ind(cm_ctx->vdev, &cm_req->req);
1916 if (QDF_IS_STATUS_ERROR(status)) {
1917 reason = CM_NO_CANDIDATE_FOUND;
1918 goto connect_err;
1919 }
1920 }
1921
1922 if (mlo_is_sta_bridge_vdev(cm_ctx->vdev)) {
1923 status = cm_ser_connect_req(pdev, cm_ctx, cm_req);
1924 if (QDF_IS_STATUS_ERROR(status)) {
1925 reason = CM_SER_FAILURE;
1926 goto connect_err;
1927 }
1928
1929 return QDF_STATUS_SUCCESS;
1930 }
1931 status = cm_connect_get_candidates(pdev, cm_ctx, cm_req);
1932
1933 /* In case of status pending connect will continue after scan */
1934 if (status == QDF_STATUS_E_PENDING)
1935 return QDF_STATUS_SUCCESS;
1936 if (QDF_IS_STATUS_ERROR(status)) {
1937 reason = CM_NO_CANDIDATE_FOUND;
1938 goto connect_err;
1939 }
1940
1941 status = cm_check_for_bearer_switch(psoc, cm_req->candidate_list,
1942 vdev_id, cm_req->cm_id);
1943 if (QDF_IS_STATUS_SUCCESS(status)) {
1944 mlme_debug(CM_PREFIX_FMT "Connect will continue after bearer switch",
1945 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
1946 return QDF_STATUS_SUCCESS;
1947 }
1948
1949 status = cm_check_for_hw_mode_change(psoc, cm_req->candidate_list,
1950 vdev_id, cm_req->cm_id);
1951 if (QDF_IS_STATUS_ERROR(status) && status != QDF_STATUS_E_ALREADY) {
1952 reason = CM_HW_MODE_FAILURE;
1953 mlme_err(CM_PREFIX_FMT "Failed to set HW mode change",
1954 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
1955 goto connect_err;
1956 } else if (QDF_IS_STATUS_SUCCESS(status)) {
1957 mlme_debug(CM_PREFIX_FMT "Connect will continue after HW mode change",
1958 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
1959 return QDF_STATUS_SUCCESS;
1960 }
1961
1962 status = cm_ser_connect_req(pdev, cm_ctx, cm_req);
1963
1964 if (QDF_IS_STATUS_ERROR(status)) {
1965 reason = CM_SER_FAILURE;
1966 goto connect_err;
1967 }
1968
1969 return QDF_STATUS_SUCCESS;
1970
1971 connect_err:
1972 return cm_send_connect_start_fail(cm_ctx, cm_req, reason);
1973 }
1974
1975 #if defined(CONN_MGR_ADV_FEATURE) && defined(WLAN_FEATURE_11BE_MLO)
1976 static void
cm_modify_partner_info_based_on_dbs_or_sbs_mode(struct wlan_objmgr_vdev * vdev,wlan_cm_id cm_id,struct scan_cache_entry * scan_entry,struct mlo_partner_info * partner_info)1977 cm_modify_partner_info_based_on_dbs_or_sbs_mode(struct wlan_objmgr_vdev *vdev,
1978 wlan_cm_id cm_id,
1979 struct scan_cache_entry *scan_entry,
1980 struct mlo_partner_info *partner_info)
1981 {
1982 struct wlan_objmgr_psoc *psoc = NULL;
1983 uint16_t i;
1984 qdf_freq_t assoc_freq, partner_freq;
1985 struct mlo_link_info tmp_link_info;
1986 uint8_t best_partner_idx, best_partner_idx_2g, best_partner_idx_5g;
1987
1988 psoc = wlan_vdev_get_psoc(vdev);
1989 if (!psoc)
1990 return;
1991
1992 assoc_freq = scan_entry->channel.chan_freq;
1993 best_partner_idx_2g = partner_info->num_partner_links;
1994 best_partner_idx_5g = partner_info->num_partner_links;
1995
1996 for (i = 0; i < partner_info->num_partner_links; i++) {
1997 partner_freq = partner_info->partner_link_info[i].chan_freq;
1998 if (!policy_mgr_2_freq_always_on_same_mac(psoc, assoc_freq,
1999 partner_freq)) {
2000 if (wlan_reg_is_24ghz_ch_freq(partner_freq))
2001 best_partner_idx_2g = i;
2002 else
2003 best_partner_idx_5g = i;
2004
2005 break;
2006 }
2007 }
2008
2009 if (best_partner_idx_5g == partner_info->num_partner_links &&
2010 best_partner_idx_2g == partner_info->num_partner_links)
2011 return;
2012
2013 if (best_partner_idx_5g != partner_info->num_partner_links)
2014 best_partner_idx = best_partner_idx_5g;
2015 else if (best_partner_idx_2g != partner_info->num_partner_links)
2016 best_partner_idx = best_partner_idx_2g;
2017 else
2018 return;
2019
2020 if (best_partner_idx == 0)
2021 return;
2022
2023 /* Based on DBS or SBS mode, reorder the partner_link_info */
2024 tmp_link_info = partner_info->partner_link_info[0];
2025 partner_info->partner_link_info[0] =
2026 partner_info->partner_link_info[best_partner_idx];
2027 partner_info->partner_link_info[best_partner_idx] = tmp_link_info;
2028
2029 mlme_debug(CM_PREFIX_FMT "Updated no. of partner links: %d",
2030 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cm_id),
2031 partner_info->num_partner_links);
2032
2033 for (i = 0; i < partner_info->num_partner_links; i++)
2034 mlme_debug(CM_PREFIX_FMT "Partner link id: %d mac:" QDF_MAC_ADDR_FMT " freq: %d",
2035 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cm_id),
2036 partner_info->partner_link_info[i].link_id,
2037 QDF_MAC_ADDR_REF(partner_info->partner_link_info[i].link_addr.bytes),
2038 partner_info->partner_link_info[i].chan_freq);
2039 }
2040
2041 static void
cm_connect_req_update_ml_partner_info(struct cnx_mgr * cm_ctx,struct cm_req * cm_req,bool same_candidate_used)2042 cm_connect_req_update_ml_partner_info(struct cnx_mgr *cm_ctx,
2043 struct cm_req *cm_req,
2044 bool same_candidate_used)
2045 {
2046 bool eht_capable = false;
2047 struct cm_connect_req *conn_req = &cm_req->connect_req;
2048 struct wlan_objmgr_pdev *pdev;
2049 uint8_t cur_vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
2050
2051 pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
2052 if (!pdev) {
2053 mlme_err(CM_PREFIX_FMT "Failed to find pdev",
2054 CM_PREFIX_REF(cur_vdev_id, cm_req->cm_id));
2055 return;
2056 }
2057
2058 wlan_psoc_mlme_get_11be_capab(wlan_vdev_get_psoc(cm_ctx->vdev),
2059 &eht_capable);
2060 if (!same_candidate_used && eht_capable &&
2061 cm_bss_peer_is_assoc_peer(conn_req)) {
2062 cm_get_ml_partner_info(pdev, conn_req);
2063 cm_modify_partner_info_based_on_dbs_or_sbs_mode(
2064 cm_ctx->vdev, cm_req->cm_id,
2065 conn_req->cur_candidate->entry,
2066 &conn_req->req.ml_parnter_info);
2067 }
2068 }
2069 #else
2070 static void
cm_connect_req_update_ml_partner_info(struct cnx_mgr * cm_ctx,struct cm_req * cm_req,bool same_candidate_used)2071 cm_connect_req_update_ml_partner_info(struct cnx_mgr *cm_ctx,
2072 struct cm_req *cm_req,
2073 bool same_candidate_used)
2074 {}
2075 #endif
2076
2077 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE)
2078 static void
cm_override_partner_link_akm(struct cnx_mgr * cm_ctx,struct cm_req * cm_req)2079 cm_override_partner_link_akm(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
2080 {
2081 struct scan_cache_entry *cur_entry;
2082 struct wlan_objmgr_vdev *assoc_vdev;
2083
2084 if (!cm_req->connect_req.cur_candidate)
2085 return;
2086
2087 assoc_vdev = wlan_mlo_get_assoc_link_vdev(cm_ctx->vdev);
2088 if (!assoc_vdev) {
2089 mlme_err("Assoc vdev not found");
2090 return;
2091 }
2092
2093 /* Partner link might have common AKM with assoc link but that
2094 * AKM might not be the superior AKM of the available AKMs for
2095 * the partner link.
2096 * Override partner link AKM with assoc link chosen AKM so that
2097 * same AKM will be chosen for partner link as well.
2098 *
2099 * Example: Assoc link: WPA2-PSK
2100 * Partner link: WPA3-SAE and WPA2-PSK
2101 *
2102 * Even WPA2-PSK is matching with assoc link, WPA3-SAE is more secure
2103 * AKM for partner link and in order to avoid selecting WPA3-SAE for
2104 * partner link, override that AKM with the common AKM from assoc link.
2105 */
2106 cur_entry = cm_req->connect_req.cur_candidate->entry;
2107 cur_entry->neg_sec_info.key_mgmt =
2108 wlan_crypto_get_param(assoc_vdev, WLAN_CRYPTO_PARAM_KEY_MGMT);
2109 }
2110 #else
2111 static inline void
cm_override_partner_link_akm(struct cnx_mgr * cm_ctx,struct cm_req * cm_req)2112 cm_override_partner_link_akm(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
2113 {
2114 }
2115 #endif
2116
2117 /**
2118 * cm_get_valid_candidate() - This API will be called to get the next valid
2119 * candidate
2120 * @cm_ctx: connection manager context
2121 * @cm_req: Connect request.
2122 * @resp: connect resp from previous connection attempt
2123 * @same_candidate_used: this will be set if same candidate used
2124 *
2125 * This function return a valid candidate to try connection. It return failure
2126 * if no valid candidate is present or all valid candidate are tried.
2127 *
2128 * Return: QDF status
2129 */
cm_get_valid_candidate(struct cnx_mgr * cm_ctx,struct cm_req * cm_req,struct wlan_cm_connect_resp * resp,bool * same_candidate_used)2130 static QDF_STATUS cm_get_valid_candidate(struct cnx_mgr *cm_ctx,
2131 struct cm_req *cm_req,
2132 struct wlan_cm_connect_resp *resp,
2133 bool *same_candidate_used)
2134 {
2135 struct wlan_objmgr_psoc *psoc;
2136 struct scan_cache_node *scan_node = NULL;
2137 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
2138 struct scan_cache_node *new_candidate = NULL, *prev_candidate;
2139 QDF_STATUS status = QDF_STATUS_SUCCESS;
2140 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
2141 bool use_same_candidate = false;
2142 int32_t akm;
2143 struct qdf_mac_addr *pmksa_mac;
2144
2145 psoc = wlan_vdev_get_psoc(cm_ctx->vdev);
2146 if (!psoc) {
2147 mlme_err(CM_PREFIX_FMT "Failed to find psoc",
2148 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
2149 return QDF_STATUS_E_FAILURE;
2150 }
2151
2152 prev_candidate = cm_req->connect_req.cur_candidate;
2153 /*
2154 * In case of STA/CLI + STA/CLI, if a STA/CLI is in connecting state and
2155 * a disconnect is received on any other STA/CLI, the disconnect can
2156 * timeout waiting for the connection on first STA/CLI to get completed.
2157 * This is because the connect is a blocking serialization command and
2158 * it can try multiple candidates and thus can take upto 30+ sec to
2159 * complete.
2160 *
2161 * Now osif will proceed with vdev delete after disconnect timeout.
2162 * This can lead to vdev delete sent without vdev down/stop/peer delete
2163 * for the vdev.
2164 *
2165 * Same way if a SAP/GO has start/stop command or peer disconnect in
2166 * pending queue, delay in processing it can cause timeouts and other
2167 * issues.
2168 *
2169 * So abort the next connection attempt if any of the vdev is waiting
2170 * for vdev operation to avoid timeouts
2171 */
2172 if (cm_is_any_other_vdev_connecting_disconnecting(cm_ctx, cm_req)) {
2173 status = QDF_STATUS_E_FAILURE;
2174 goto flush_single_pmk;
2175 }
2176
2177 if (cm_req->connect_req.connect_attempts >=
2178 cm_ctx->max_connect_attempts) {
2179 mlme_info(CM_PREFIX_FMT "%d attempts tried, max %d",
2180 CM_PREFIX_REF(vdev_id, cm_req->cm_id),
2181 cm_req->connect_req.connect_attempts,
2182 cm_ctx->max_connect_attempts);
2183 status = QDF_STATUS_E_FAILURE;
2184 goto flush_single_pmk;
2185 }
2186
2187 /* From 2nd attempt onward, check if time allows for a new attempt */
2188 if (cm_req->connect_req.connect_attempts &&
2189 !cm_is_time_allowed_for_connect_attempt(cm_ctx,
2190 &cm_req->connect_req)) {
2191 status = QDF_STATUS_E_FAILURE;
2192 goto flush_single_pmk;
2193 }
2194
2195 if (prev_candidate && resp &&
2196 cm_is_retry_with_same_candidate(cm_ctx, &cm_req->connect_req,
2197 resp)) {
2198 new_candidate = prev_candidate;
2199 use_same_candidate = true;
2200 goto try_same_candidate;
2201 }
2202
2203 /*
2204 * Get next candidate if prev_candidate is not NULL, else get
2205 * the first candidate
2206 */
2207 if (prev_candidate) {
2208 /* Fetch new candidate list and append new entries to the
2209 * current candidate list.
2210 */
2211 cm_update_candidate_list(cm_ctx, &cm_req->connect_req,
2212 prev_candidate);
2213 qdf_list_peek_next(cm_req->connect_req.candidate_list,
2214 &prev_candidate->node, &cur_node);
2215 } else {
2216 qdf_list_peek_front(cm_req->connect_req.candidate_list,
2217 &cur_node);
2218 }
2219
2220 while (cur_node) {
2221 qdf_list_peek_next(cm_req->connect_req.candidate_list,
2222 cur_node, &next_node);
2223 scan_node = qdf_container_of(cur_node, struct scan_cache_node,
2224 node);
2225 status = cm_if_mgr_validate_candidate(cm_ctx, scan_node->entry);
2226 if (QDF_IS_STATUS_SUCCESS(status)) {
2227 new_candidate = scan_node;
2228 break;
2229 }
2230
2231 /*
2232 * stored failure response for first candidate only but
2233 * indicate the failure response to osif for all candidates.
2234 */
2235 cm_store_n_send_failed_candidate(cm_ctx, cm_req->cm_id);
2236
2237 cur_node = next_node;
2238 next_node = NULL;
2239 }
2240
2241 /*
2242 * If cur_node is NULL prev candidate was last to be tried so no more
2243 * candidates left for connect now.
2244 */
2245 if (!cur_node) {
2246 mlme_debug(CM_PREFIX_FMT "No more candidates left",
2247 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
2248 cm_req->connect_req.cur_candidate = NULL;
2249 status = QDF_STATUS_E_FAILURE;
2250 goto flush_single_pmk;
2251 }
2252
2253 /* Reset current candidate retries when a new candidate is tried */
2254 cm_req->connect_req.cur_candidate_retries = 0;
2255
2256 try_same_candidate:
2257 cm_req->connect_req.connect_attempts++;
2258 cm_req->connect_req.cur_candidate = new_candidate;
2259
2260 cm_connect_req_update_ml_partner_info(cm_ctx, cm_req,
2261 use_same_candidate);
2262 if (!use_same_candidate &&
2263 wlan_vdev_mlme_is_mlo_link_vdev(cm_ctx->vdev)) {
2264 cm_override_partner_link_akm(cm_ctx, cm_req);
2265 }
2266
2267 flush_single_pmk:
2268 akm = wlan_crypto_get_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_KEY_MGMT);
2269 /*
2270 * If connection fails with Single PMK bssid (prev candidate),
2271 * clear the pmk entry. Flush only in case if we are not trying again
2272 * with same candidate again.
2273 */
2274 if (prev_candidate && !use_same_candidate &&
2275 util_scan_entry_single_pmk(psoc, prev_candidate->entry) &&
2276 (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE) ||
2277 QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY))) {
2278 pmksa_mac = &prev_candidate->entry->bssid;
2279 cm_delete_pmksa_for_single_pmk_bssid(cm_ctx, pmksa_mac);
2280
2281 /* If the candidate is ML capable, the PMKSA entry might
2282 * exist with it's MLD address, so check and purge the
2283 * PMKSA entry with MLD address for ML candidate.
2284 */
2285 pmksa_mac = (struct qdf_mac_addr *)
2286 util_scan_entry_mldaddr(prev_candidate->entry);
2287 if (pmksa_mac)
2288 cm_delete_pmksa_for_single_pmk_bssid(cm_ctx, pmksa_mac);
2289 }
2290
2291 if (same_candidate_used)
2292 *same_candidate_used = use_same_candidate;
2293
2294 return status;
2295 }
2296
2297 static QDF_STATUS
cm_send_bss_select_ind(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)2298 cm_send_bss_select_ind(struct cnx_mgr *cm_ctx, struct cm_connect_req *req)
2299 {
2300 QDF_STATUS status;
2301 struct wlan_cm_vdev_connect_req vdev_req;
2302 struct wlan_cm_connect_resp *resp;
2303
2304 vdev_req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
2305 vdev_req.cm_id = req->cm_id;
2306 vdev_req.bss = req->cur_candidate;
2307
2308 status = mlme_cm_bss_select_ind(cm_ctx->vdev, &vdev_req);
2309 if (QDF_IS_STATUS_SUCCESS(status) ||
2310 status == QDF_STATUS_E_NOSUPPORT)
2311 return status;
2312
2313 /* In supported and failure try with next candidate */
2314 mlme_err(CM_PREFIX_FMT "mlme candidate select indication failed %d",
2315 CM_PREFIX_REF(vdev_req.vdev_id, req->cm_id), status);
2316 resp = qdf_mem_malloc(sizeof(*resp));
2317 if (!resp)
2318 return QDF_STATUS_E_FAILURE;
2319
2320 cm_fill_failure_resp_from_cm_id(cm_ctx, resp, req->cm_id,
2321 CM_BSS_SELECT_IND_FAILED);
2322 cm_sm_deliver_event_sync(cm_ctx,
2323 WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE,
2324 sizeof(*resp), resp);
2325 qdf_mem_free(resp);
2326
2327 return QDF_STATUS_SUCCESS;
2328 }
2329
cm_update_ser_timer_for_new_candidate(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id)2330 static void cm_update_ser_timer_for_new_candidate(struct cnx_mgr *cm_ctx,
2331 wlan_cm_id cm_id)
2332 {
2333 struct wlan_serialization_command cmd;
2334
2335 cmd.cmd_type = WLAN_SER_CMD_VDEV_CONNECT;
2336 cmd.cmd_id = cm_id;
2337 cmd.cmd_timeout_duration = cm_ctx->connect_timeout;
2338 cmd.vdev = cm_ctx->vdev;
2339
2340 wlan_serialization_update_timer(&cmd);
2341 }
2342
cm_try_next_candidate(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)2343 QDF_STATUS cm_try_next_candidate(struct cnx_mgr *cm_ctx,
2344 struct wlan_cm_connect_resp *resp)
2345 {
2346 QDF_STATUS status;
2347 struct cm_req *cm_req;
2348 bool same_candidate_used = false;
2349
2350 cm_req = cm_get_req_by_cm_id(cm_ctx, resp->cm_id);
2351 if (!cm_req)
2352 return QDF_STATUS_E_FAILURE;
2353
2354 status = cm_get_valid_candidate(cm_ctx, cm_req, resp,
2355 &same_candidate_used);
2356 if (QDF_IS_STATUS_ERROR(status))
2357 goto connect_err;
2358
2359 /*
2360 * cached the first failure response if candidate is different from
2361 * previous.
2362 * Do not indicate to OSIF if same candidate is used again as we are not
2363 * done with this candidate. So inform once we move to next candidate.
2364 * This will also avoid flush for the scan entry.
2365 */
2366 if (!same_candidate_used) {
2367 cm_store_first_candidate_rsp(cm_ctx, resp->cm_id, resp);
2368 mlme_cm_osif_failed_candidate_ind(cm_ctx->vdev, resp);
2369 }
2370
2371 cm_update_ser_timer_for_new_candidate(cm_ctx, resp->cm_id);
2372
2373 status = cm_send_bss_select_ind(cm_ctx, &cm_req->connect_req);
2374
2375 /*
2376 * If candidate select indication is not supported continue with bss
2377 * peer create, else peer will be created after resp.
2378 */
2379 if (status == QDF_STATUS_E_NOSUPPORT) {
2380 /* Update vdev mlme mac address based on connection type */
2381 status = cm_update_vdev_mlme_macaddr(cm_ctx,
2382 &cm_req->connect_req);
2383 if (QDF_IS_STATUS_ERROR(status))
2384 goto connect_err;
2385
2386 cm_create_bss_peer(cm_ctx, &cm_req->connect_req);
2387 } else if (QDF_IS_STATUS_ERROR(status)) {
2388 goto connect_err;
2389 }
2390
2391 return QDF_STATUS_SUCCESS;
2392
2393 connect_err:
2394 return cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_CONNECT_FAILURE,
2395 sizeof(*resp), resp);
2396
2397 }
2398
cm_connect_resp_cmid_match_list_head(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)2399 bool cm_connect_resp_cmid_match_list_head(struct cnx_mgr *cm_ctx,
2400 struct wlan_cm_connect_resp *resp)
2401 {
2402 return cm_check_cmid_match_list_head(cm_ctx, &resp->cm_id);
2403 }
2404
cm_fill_vdev_crypto_params(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_req * req)2405 void cm_fill_vdev_crypto_params(struct cnx_mgr *cm_ctx,
2406 struct wlan_cm_connect_req *req)
2407 {
2408 /* fill vdev crypto from the connect req */
2409 wlan_crypto_set_vdev_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_AUTH_MODE,
2410 req->crypto.auth_type);
2411 wlan_crypto_set_vdev_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_KEY_MGMT,
2412 req->crypto.akm_suites);
2413 wlan_crypto_set_vdev_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_UCAST_CIPHER,
2414 req->crypto.ciphers_pairwise);
2415 wlan_crypto_set_vdev_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_MCAST_CIPHER,
2416 req->crypto.group_cipher);
2417 wlan_crypto_set_vdev_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_MGMT_CIPHER,
2418 req->crypto.mgmt_ciphers);
2419 wlan_crypto_set_vdev_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_RSN_CAP,
2420 req->crypto.rsn_caps);
2421 }
2422
2423 static QDF_STATUS
cm_if_mgr_inform_connect_active(struct wlan_objmgr_vdev * vdev)2424 cm_if_mgr_inform_connect_active(struct wlan_objmgr_vdev *vdev)
2425 {
2426 return if_mgr_deliver_event(vdev, WLAN_IF_MGR_EV_CONNECT_ACTIVE, NULL);
2427 }
2428
cm_connect_active(struct cnx_mgr * cm_ctx,wlan_cm_id * cm_id)2429 QDF_STATUS cm_connect_active(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
2430 {
2431 struct cm_req *cm_req;
2432 QDF_STATUS status;
2433 struct wlan_cm_connect_req *req;
2434
2435 cm_if_mgr_inform_connect_active(cm_ctx->vdev);
2436
2437 cm_ctx->active_cm_id = *cm_id;
2438 cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
2439 if (!cm_req) {
2440 /*
2441 * Remove the command from serialization active queue, if
2442 * connect req was not found, to avoid active cmd timeout.
2443 * This can happen if a thread tried to flush the pending
2444 * connect request and while doing so, it removed the
2445 * CM pending request, but before it tried to remove pending
2446 * command from serialization, the command becomes active in
2447 * another thread.
2448 */
2449 cm_remove_cmd_from_serialization(cm_ctx, *cm_id);
2450 return QDF_STATUS_E_INVAL;
2451 }
2452
2453 cm_req->connect_req.connect_active_time =
2454 qdf_mc_timer_get_system_time();
2455 req = &cm_req->connect_req.req;
2456 wlan_vdev_mlme_set_ssid(cm_ctx->vdev, req->ssid.ssid, req->ssid.length);
2457 /*
2458 * free vdev keys before setting crypto params for 1x/ owe roaming,
2459 * link vdev keys would be cleaned in osif
2460 */
2461 if (!wlan_vdev_mlme_is_mlo_link_vdev(cm_ctx->vdev)) {
2462 mlme_cm_osif_connect_active_notify(wlan_vdev_get_id(cm_ctx->vdev));
2463 if (!wlan_cm_check_mlo_roam_auth_status(cm_ctx->vdev))
2464 wlan_crypto_free_vdev_key(cm_ctx->vdev);
2465 }
2466 cm_fill_vdev_crypto_params(cm_ctx, req);
2467 cm_store_wep_key(cm_ctx, &req->crypto, *cm_id);
2468
2469 if (mlo_is_sta_bridge_vdev(cm_ctx->vdev))
2470 status = QDF_STATUS_SUCCESS;
2471 else
2472 status = cm_get_valid_candidate(cm_ctx, cm_req, NULL, NULL);
2473
2474 if (QDF_IS_STATUS_ERROR(status))
2475 goto connect_err;
2476
2477 status = cm_send_bss_select_ind(cm_ctx, &cm_req->connect_req);
2478 /*
2479 * If candidate select indication is not supported continue with bss
2480 * peer create, else peer will be created after resp.
2481 */
2482 if (status == QDF_STATUS_E_NOSUPPORT) {
2483 /* Update vdev mlme mac address based on connection type */
2484 status = cm_update_vdev_mlme_macaddr(cm_ctx,
2485 &cm_req->connect_req);
2486 if (QDF_IS_STATUS_ERROR(status))
2487 goto connect_err;
2488
2489 cm_create_bss_peer(cm_ctx, &cm_req->connect_req);
2490 } else if (QDF_IS_STATUS_ERROR(status)) {
2491 goto connect_err;
2492 }
2493
2494 return QDF_STATUS_SUCCESS;
2495
2496 connect_err:
2497 return cm_send_connect_start_fail(cm_ctx,
2498 &cm_req->connect_req, CM_JOIN_FAILED);
2499 }
2500
2501 #ifdef WLAN_FEATURE_FILS_SK
cm_copy_fils_info(struct wlan_cm_vdev_connect_req * req,struct cm_req * cm_req)2502 static void cm_copy_fils_info(struct wlan_cm_vdev_connect_req *req,
2503 struct cm_req *cm_req)
2504 {
2505 req->fils_info = &cm_req->connect_req.req.fils_info;
2506 }
2507
cm_set_fils_connection(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)2508 static inline void cm_set_fils_connection(struct cnx_mgr *cm_ctx,
2509 struct wlan_cm_connect_resp *resp)
2510 {
2511 int32_t key_mgmt;
2512
2513 /*
2514 * Check and set only in case of failure and when
2515 * resp->is_fils_connection is not already set, else return.
2516 */
2517 if (QDF_IS_STATUS_SUCCESS(resp->connect_status) ||
2518 resp->is_fils_connection)
2519 return;
2520
2521 key_mgmt = wlan_crypto_get_param(cm_ctx->vdev,
2522 WLAN_CRYPTO_PARAM_KEY_MGMT);
2523
2524 if (key_mgmt & (1 << WLAN_CRYPTO_KEY_MGMT_FILS_SHA256 |
2525 1 << WLAN_CRYPTO_KEY_MGMT_FILS_SHA384 |
2526 1 << WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256 |
2527 1 << WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384))
2528 resp->is_fils_connection = true;
2529 }
2530 #else
cm_copy_fils_info(struct wlan_cm_vdev_connect_req * req,struct cm_req * cm_req)2531 static inline void cm_copy_fils_info(struct wlan_cm_vdev_connect_req *req,
2532 struct cm_req *cm_req)
2533 {
2534 }
2535
cm_set_fils_connection(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)2536 static inline void cm_set_fils_connection(struct cnx_mgr *cm_ctx,
2537 struct wlan_cm_connect_resp *resp)
2538 {
2539 }
2540 #endif
2541
2542 #ifdef WLAN_FEATURE_11BE_MLO
2543 static inline
cm_update_ml_partner_info(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req,struct wlan_cm_vdev_connect_req * connect_req)2544 void cm_update_ml_partner_info(struct wlan_objmgr_vdev *vdev,
2545 struct wlan_cm_connect_req *req,
2546 struct wlan_cm_vdev_connect_req *connect_req)
2547 {
2548 if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
2549 return;
2550
2551 qdf_mem_copy(&connect_req->ml_parnter_info,
2552 &req->ml_parnter_info,
2553 sizeof(struct mlo_partner_info));
2554 }
2555 #else
2556 static inline
cm_update_ml_partner_info(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req,struct wlan_cm_vdev_connect_req * connect_req)2557 void cm_update_ml_partner_info(struct wlan_objmgr_vdev *vdev,
2558 struct wlan_cm_connect_req *req,
2559 struct wlan_cm_vdev_connect_req *connect_req)
2560 {
2561 }
2562 #endif
2563
2564 static
cm_update_per_peer_key_mgmt_crypto_params(struct wlan_objmgr_vdev * vdev,struct security_info * neg_sec_info)2565 void cm_update_per_peer_key_mgmt_crypto_params(struct wlan_objmgr_vdev *vdev,
2566 struct security_info *neg_sec_info)
2567 {
2568 wlan_crypto_key_mgmt akm;
2569 uint32_t key_mgmt = 0x0;
2570
2571 /*
2572 * As there can be multiple AKM present select the most secured AKM
2573 * present
2574 */
2575
2576 akm = wlan_crypto_get_secure_akm_available(neg_sec_info->key_mgmt);
2577 /* If not matches any AKM, set to same AKM */
2578 if (akm == WLAN_CRYPTO_KEY_MGMT_MAX)
2579 key_mgmt = neg_sec_info->key_mgmt;
2580 else
2581 QDF_SET_PARAM(key_mgmt, akm);
2582
2583 wlan_crypto_set_vdev_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT, key_mgmt);
2584
2585 /*
2586 * Overwrite the key mgmt with single key_mgmt if multiple are present
2587 */
2588 neg_sec_info->key_mgmt = key_mgmt;
2589 }
2590
2591 static
cm_update_per_peer_ucastcipher_crypto_params(struct wlan_objmgr_vdev * vdev,struct security_info * neg_sec_info)2592 void cm_update_per_peer_ucastcipher_crypto_params(struct wlan_objmgr_vdev *vdev,
2593 struct security_info *neg_sec_info)
2594 {
2595 int32_t ucastcipherset = 0;
2596
2597 /*
2598 * As there can be multiple ucastcipher present select the most secured
2599 * ucastcipher present.
2600 */
2601 if (QDF_HAS_PARAM(neg_sec_info->ucastcipherset,
2602 WLAN_CRYPTO_CIPHER_AES_GCM_256))
2603 QDF_SET_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_AES_GCM_256);
2604 else if (QDF_HAS_PARAM(neg_sec_info->ucastcipherset,
2605 WLAN_CRYPTO_CIPHER_AES_CCM_256))
2606 QDF_SET_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_AES_CCM_256);
2607 else if (QDF_HAS_PARAM(neg_sec_info->ucastcipherset,
2608 WLAN_CRYPTO_CIPHER_AES_GCM))
2609 QDF_SET_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_AES_GCM);
2610 else if (QDF_HAS_PARAM(neg_sec_info->ucastcipherset,
2611 WLAN_CRYPTO_CIPHER_AES_CCM))
2612 QDF_SET_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_AES_CCM);
2613 else if (QDF_HAS_PARAM(neg_sec_info->ucastcipherset,
2614 WLAN_CRYPTO_CIPHER_TKIP))
2615 QDF_SET_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_TKIP);
2616 else
2617 ucastcipherset = neg_sec_info->ucastcipherset;
2618
2619 wlan_crypto_set_vdev_param(vdev, WLAN_CRYPTO_PARAM_UCAST_CIPHER,
2620 ucastcipherset);
2621 /*
2622 * Overwrite the ucastcipher with single ucast cipher if multiple are
2623 * present
2624 */
2625 neg_sec_info->ucastcipherset = ucastcipherset;
2626 }
2627
2628 static
cm_update_per_peer_crypto_params(struct wlan_objmgr_vdev * vdev,struct cm_connect_req * connect_req)2629 void cm_update_per_peer_crypto_params(struct wlan_objmgr_vdev *vdev,
2630 struct cm_connect_req *connect_req)
2631 {
2632 struct security_info *neg_sec_info;
2633 uint16_t rsn_caps;
2634
2635 /* Do only for WPA/WPA2/WPA3 */
2636 if (!connect_req->req.crypto.wpa_versions)
2637 return;
2638
2639 /*
2640 * Some non PMF AP misbehave if in assoc req RSN IE contain PMF capable
2641 * bit set. Thus only if AP and self are capable, try PMF connection
2642 * else set PMF as 0. The PMF filtering is already taken care in
2643 * get scan results.
2644 */
2645 neg_sec_info = &connect_req->cur_candidate->entry->neg_sec_info;
2646 rsn_caps = connect_req->req.crypto.rsn_caps;
2647 if (!(neg_sec_info->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED &&
2648 rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) {
2649 rsn_caps &= ~WLAN_CRYPTO_RSN_CAP_MFP_ENABLED;
2650 rsn_caps &= ~WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED;
2651 rsn_caps &= ~WLAN_CRYPTO_RSN_CAP_OCV_SUPPORTED;
2652 }
2653
2654 /* Update the new rsn caps */
2655 wlan_crypto_set_vdev_param(vdev, WLAN_CRYPTO_PARAM_RSN_CAP,
2656 rsn_caps);
2657
2658 cm_update_per_peer_key_mgmt_crypto_params(vdev, neg_sec_info);
2659 cm_update_per_peer_ucastcipher_crypto_params(vdev, neg_sec_info);
2660 }
2661
2662 QDF_STATUS
cm_resume_connect_after_peer_create(struct cnx_mgr * cm_ctx,wlan_cm_id * cm_id)2663 cm_resume_connect_after_peer_create(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
2664 {
2665 struct wlan_cm_vdev_connect_req req;
2666 struct cm_req *cm_req;
2667 QDF_STATUS status;
2668 struct security_info *neg_sec_info;
2669 uint8_t country_code[REG_ALPHA2_LEN + 1] = {0};
2670 struct wlan_objmgr_psoc *psoc;
2671 struct cm_connect_req *conn_req = NULL;
2672
2673 psoc = wlan_pdev_get_psoc(wlan_vdev_get_pdev(cm_ctx->vdev));
2674
2675 cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
2676 if (!cm_req)
2677 return QDF_STATUS_E_FAILURE;
2678
2679 conn_req = &cm_req->connect_req;
2680 /* Handle WDS bridge vdev */
2681 if (mlo_is_sta_bridge_vdev(cm_ctx->vdev) && conn_req) {
2682 req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
2683 req.cm_id = *cm_id;
2684 req.force_rsne_override = conn_req->req.force_rsne_override;
2685 req.is_wps_connection = conn_req->req.is_wps_connection;
2686 req.is_osen_connection = conn_req->req.is_osen_connection;
2687 req.assoc_ie = conn_req->req.assoc_ie;
2688 req.scan_ie = conn_req->req.scan_ie;
2689 cm_copy_fils_info(&req, cm_req);
2690 req.ht_caps = conn_req->req.ht_caps;
2691 req.ht_caps_mask = conn_req->req.ht_caps_mask;
2692 req.vht_caps = conn_req->req.vht_caps;
2693 req.vht_caps_mask = conn_req->req.vht_caps_mask;
2694 req.is_non_assoc_link = conn_req->req.is_non_assoc_link;
2695 cm_update_ml_partner_info(cm_ctx->vdev, &conn_req->req, &req);
2696 wlan_reg_get_cc_and_src(psoc, country_code);
2697 goto connect_req;
2698 }
2699
2700 /*
2701 * As keymgmt and ucast cipher can be multiple.
2702 * Choose one keymgmt and one ucastcipherset based on higher security.
2703 */
2704 cm_update_per_peer_crypto_params(cm_ctx->vdev, &cm_req->connect_req);
2705
2706 req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
2707 req.cm_id = *cm_id;
2708 req.force_rsne_override = cm_req->connect_req.req.force_rsne_override;
2709 req.is_wps_connection = cm_req->connect_req.req.is_wps_connection;
2710 req.is_osen_connection = cm_req->connect_req.req.is_osen_connection;
2711 req.assoc_ie = cm_req->connect_req.req.assoc_ie;
2712 req.scan_ie = cm_req->connect_req.req.scan_ie;
2713 req.bss = cm_req->connect_req.cur_candidate;
2714 cm_copy_fils_info(&req, cm_req);
2715 req.ht_caps = cm_req->connect_req.req.ht_caps;
2716 req.ht_caps_mask = cm_req->connect_req.req.ht_caps_mask;
2717 req.vht_caps = cm_req->connect_req.req.vht_caps;
2718 req.vht_caps_mask = cm_req->connect_req.req.vht_caps_mask;
2719 req.is_non_assoc_link = cm_req->connect_req.req.is_non_assoc_link;
2720 cm_update_ml_partner_info(cm_ctx->vdev, &cm_req->connect_req.req, &req);
2721
2722 neg_sec_info = &cm_req->connect_req.cur_candidate->entry->neg_sec_info;
2723 if (util_scan_entry_is_hidden_ap(req.bss->entry) &&
2724 QDF_HAS_PARAM(neg_sec_info->key_mgmt, WLAN_CRYPTO_KEY_MGMT_OWE)) {
2725 mlme_debug(CM_PREFIX_FMT "OWE transition candidate has wildcard ssid",
2726 CM_PREFIX_REF(req.vdev_id, req.cm_id));
2727 req.owe_trans_ssid = cm_req->connect_req.req.ssid;
2728 }
2729
2730 wlan_reg_get_cc_and_src(psoc, country_code);
2731 mlme_nofl_info(CM_PREFIX_FMT "Connecting to " QDF_SSID_FMT " " QDF_MAC_ADDR_FMT " rssi: %d freq: %d akm 0x%x cipher: uc 0x%x mc 0x%x, wps %d osen %d force RSN %d CC: %c%c",
2732 CM_PREFIX_REF(req.vdev_id, req.cm_id),
2733 QDF_SSID_REF(cm_req->connect_req.req.ssid.length,
2734 cm_req->connect_req.req.ssid.ssid),
2735 QDF_MAC_ADDR_REF(req.bss->entry->bssid.bytes),
2736 req.bss->entry->rssi_raw,
2737 req.bss->entry->channel.chan_freq,
2738 neg_sec_info->key_mgmt, neg_sec_info->ucastcipherset,
2739 neg_sec_info->mcastcipherset, req.is_wps_connection,
2740 req.is_osen_connection, req.force_rsne_override,
2741 country_code[0],
2742 country_code[1]);
2743 cm_cp_stats_cstats_log_connecting_event(cm_ctx->vdev, &req, cm_req);
2744 connect_req:
2745 status = mlme_cm_connect_req(cm_ctx->vdev, &req);
2746 if (QDF_IS_STATUS_ERROR(status)) {
2747 mlme_err(CM_PREFIX_FMT "connect request failed",
2748 CM_PREFIX_REF(req.vdev_id, req.cm_id));
2749 /* try delete bss peer if req fails */
2750 mlme_cm_bss_peer_delete_req(cm_ctx->vdev);
2751 status = cm_send_connect_start_fail(cm_ctx,
2752 &cm_req->connect_req,
2753 CM_JOIN_FAILED);
2754 }
2755
2756 return status;
2757 }
2758
2759 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE)
cm_inform_bcn_probe_handler(struct cnx_mgr * cm_ctx,struct scan_cache_entry * bss,wlan_cm_id cm_id)2760 static void cm_inform_bcn_probe_handler(struct cnx_mgr *cm_ctx,
2761 struct scan_cache_entry *bss,
2762 wlan_cm_id cm_id)
2763 {
2764 struct element_info *bcn_probe_rsp;
2765 int32_t rssi;
2766 qdf_freq_t freq;
2767
2768 bcn_probe_rsp = &bss->raw_frame;
2769 rssi = bss->rssi_raw;
2770 freq = util_scan_entry_channel_frequency(bss);
2771
2772 cm_inform_bcn_probe(cm_ctx, bcn_probe_rsp->ptr, bcn_probe_rsp->len,
2773 freq, rssi, cm_id);
2774 }
2775
cm_update_partner_link_scan_db(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id,qdf_list_t * candidate_list,struct scan_cache_entry * cur_bss)2776 static void cm_update_partner_link_scan_db(struct cnx_mgr *cm_ctx,
2777 wlan_cm_id cm_id,
2778 qdf_list_t *candidate_list,
2779 struct scan_cache_entry *cur_bss)
2780 {
2781 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
2782 struct scan_cache_node *candidate;
2783 struct scan_cache_entry *bss;
2784
2785 qdf_list_peek_front(candidate_list, &cur_node);
2786
2787 while (cur_node) {
2788 qdf_list_peek_next(candidate_list, cur_node, &next_node);
2789 candidate = qdf_container_of(cur_node, struct scan_cache_node,
2790 node);
2791 bss = candidate->entry;
2792 /*
2793 * If BSS is ML and not current bss and BSS mld mac is same as
2794 * cur bss then inform it to scan cache to avoid scan cache
2795 * ageing out.
2796 */
2797 if (!qdf_is_macaddr_equal(&bss->bssid, &cur_bss->bssid) &&
2798 qdf_is_macaddr_equal(&bss->ml_info.mld_mac_addr,
2799 &cur_bss->ml_info.mld_mac_addr)) {
2800 mlme_debug(CM_PREFIX_FMT "Inform Partner bssid: " QDF_MAC_ADDR_FMT " to kernel",
2801 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
2802 cm_id),
2803 QDF_MAC_ADDR_REF(bss->bssid.bytes));
2804 cm_inform_bcn_probe_handler(cm_ctx, bss, cm_id);
2805 }
2806 cur_node = next_node;
2807 next_node = NULL;
2808 }
2809 }
2810 #else
2811 static
cm_update_partner_link_scan_db(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id,qdf_list_t * candidate_list,struct scan_cache_entry * cur_bss)2812 inline void cm_update_partner_link_scan_db(struct cnx_mgr *cm_ctx,
2813 wlan_cm_id cm_id,
2814 qdf_list_t *candidate_list,
2815 struct scan_cache_entry *cur_bss)
2816 {
2817 }
2818 #endif
2819
2820 /**
2821 * cm_update_scan_db_on_connect_success() - update scan db with beacon or
2822 * probe resp
2823 * @cm_ctx: connection manager context
2824 * @resp: connect resp
2825 *
2826 * update scan db, so that kernel and driver do not age out
2827 * the connected AP entry.
2828 *
2829 * Context: Can be called from any context and to be used only if connect
2830 * is successful and SM is in connected state. i.e. SM lock is hold.
2831 *
2832 * Return: void
2833 */
2834 static void
cm_update_scan_db_on_connect_success(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)2835 cm_update_scan_db_on_connect_success(struct cnx_mgr *cm_ctx,
2836 struct wlan_cm_connect_resp *resp)
2837 {
2838 struct element_info *bcn_probe_rsp;
2839 struct cm_req *cm_req;
2840 int32_t rssi;
2841 struct scan_cache_node *cur_candidate;
2842
2843 if (!cm_is_vdev_connected(cm_ctx->vdev))
2844 return;
2845
2846 cm_req = cm_get_req_by_cm_id(cm_ctx, resp->cm_id);
2847 if (!cm_req)
2848 return;
2849 /* if reassoc get from roam req else from connect req */
2850 if (resp->is_reassoc)
2851 cur_candidate = cm_req->roam_req.cur_candidate;
2852 else
2853 cur_candidate = cm_req->connect_req.cur_candidate;
2854
2855 if (!cur_candidate)
2856 return;
2857
2858 /*
2859 * Get beacon or probe resp from connect response, and if not present
2860 * use cur candidate to get beacon or probe resp
2861 */
2862 if (resp->connect_ies.bcn_probe_rsp.ptr)
2863 bcn_probe_rsp = &resp->connect_ies.bcn_probe_rsp;
2864 else
2865 bcn_probe_rsp = &cur_candidate->entry->raw_frame;
2866
2867 rssi = cur_candidate->entry->rssi_raw;
2868
2869 cm_inform_bcn_probe(cm_ctx, bcn_probe_rsp->ptr, bcn_probe_rsp->len,
2870 resp->freq, rssi, resp->cm_id);
2871
2872 /*
2873 * If vdev is an MLO vdev and not reassoc then use partner link info to
2874 * inform partner link scan entry to kernel.
2875 */
2876 if (!resp->is_reassoc && wlan_vdev_mlme_is_mlo_vdev(cm_ctx->vdev))
2877 cm_update_partner_link_scan_db(cm_ctx, resp->cm_id,
2878 cm_req->connect_req.candidate_list,
2879 cur_candidate->entry);
2880 }
2881
2882 #ifdef WLAN_FEATURE_11BE_MLO
2883 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
2884 static inline void
cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev * vdev)2885 cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
2886 {
2887 wlan_vdev_mlme_clear_mlo_vdev(vdev);
2888 }
2889 #else /*WLAN_FEATURE_11BE_MLO_ADV_FEATURE*/
2890 static inline void
cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev * vdev)2891 cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
2892 {
2893 /* If the connect req fails on assoc link, reset
2894 * the MLO cap flags. The flags will be updated based
2895 * on next connect req
2896 */
2897 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
2898 ucfg_mlo_mld_clear_mlo_cap(vdev);
2899
2900 wlan_vdev_set_link_id(vdev, WLAN_LINK_ID_INVALID);
2901 }
2902 #endif /*WLAN_FEATURE_11BE_MLO_ADV_FEATURE*/
2903 #else /*WLAN_FEATURE_11BE_MLO*/
2904 static inline void
cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev * vdev)2905 cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
2906 { }
2907 #endif /*WLAN_FEATURE_11BE_MLO*/
2908
2909 /**
2910 * cm_is_connect_id_reassoc_in_non_init()
2911 * @cm_ctx: connection manager context
2912 * @cm_id: cm id
2913 *
2914 * If connect req is a reassoc req and received in non init state.
2915 * Caller should take cm_ctx lock.
2916 *
2917 * Return: bool
2918 */
cm_is_connect_id_reassoc_in_non_init(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id)2919 static bool cm_is_connect_id_reassoc_in_non_init(struct cnx_mgr *cm_ctx,
2920 wlan_cm_id cm_id)
2921 {
2922 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
2923 struct cm_req *cm_req;
2924 uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
2925 bool is_reassoc = false;
2926
2927 if (prefix != CONNECT_REQ_PREFIX)
2928 return is_reassoc;
2929
2930 qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
2931 while (cur_node) {
2932 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
2933 cm_req = qdf_container_of(cur_node, struct cm_req, node);
2934
2935 if (cm_req->cm_id == cm_id) {
2936 if (cm_req->connect_req.req.reassoc_in_non_init)
2937 is_reassoc = true;
2938 return is_reassoc;
2939 }
2940
2941 cur_node = next_node;
2942 next_node = NULL;
2943 }
2944
2945 return is_reassoc;
2946 }
2947
2948 #ifdef CONN_MGR_ADV_FEATURE
2949 /**
2950 * cm_osif_connect_complete() - This API will send the response to osif layer
2951 * @cm_ctx: connection manager context
2952 * @resp: connect resp sent to osif
2953 *
2954 * This function fetches the first response in case of connect failure and sent
2955 * it to the osif layer, otherwise, sent the provided response to osif.
2956 *
2957 * Return:void
2958 */
cm_osif_connect_complete(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)2959 static void cm_osif_connect_complete(struct cnx_mgr *cm_ctx,
2960 struct wlan_cm_connect_resp *resp)
2961 {
2962 struct wlan_cm_connect_resp first_failure_resp = {0};
2963 QDF_STATUS status = QDF_STATUS_E_FAILURE;
2964 struct wlan_cm_connect_resp *connect_rsp = resp;
2965
2966 /* Currently, driver only notifies the first candidate failure to upper
2967 * layers, to post disconnect rsp to clear kernel connected state, need
2968 * copy send_disconnect flag from last candidate to first candidate.
2969 */
2970 if (QDF_IS_STATUS_ERROR(resp->connect_status)) {
2971 status = cm_get_first_candidate_rsp(cm_ctx, resp->cm_id,
2972 &first_failure_resp);
2973 if (QDF_IS_STATUS_SUCCESS(status)) {
2974 connect_rsp = &first_failure_resp;
2975 if (resp->send_disconnect) {
2976 connect_rsp->send_disconnect = resp->send_disconnect;
2977 mlme_debug(CM_PREFIX_FMT "sent disconnect rsp for first candidate",
2978 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
2979 resp->cm_id));
2980 }
2981 }
2982 }
2983
2984 mlme_cm_osif_connect_complete(cm_ctx->vdev, connect_rsp);
2985
2986 if (QDF_IS_STATUS_SUCCESS(status))
2987 cm_free_connect_rsp_ies(connect_rsp);
2988 }
2989 #else
cm_osif_connect_complete(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)2990 static void cm_osif_connect_complete(struct cnx_mgr *cm_ctx,
2991 struct wlan_cm_connect_resp *resp)
2992 {
2993 mlme_cm_osif_connect_complete(cm_ctx->vdev, resp);
2994 }
2995 #endif
2996
cm_notify_connect_complete(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp,bool acquire_lock)2997 QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
2998 struct wlan_cm_connect_resp *resp,
2999 bool acquire_lock)
3000 {
3001 enum wlan_cm_sm_state sm_state;
3002
3003 sm_state = cm_get_state(cm_ctx);
3004
3005 mlme_cm_connect_complete_ind(cm_ctx->vdev, resp);
3006 mlo_sta_link_connect_notify(cm_ctx->vdev, resp);
3007 /*
3008 * If connect req was a reassoc req and was received in not connected
3009 * state send disconnect instead of connect resp to kernel to cleanup
3010 * kernel flags
3011 */
3012 if (QDF_IS_STATUS_ERROR(resp->connect_status) &&
3013 sm_state == WLAN_CM_S_INIT) {
3014 if (acquire_lock)
3015 cm_req_lock_acquire(cm_ctx);
3016 if (cm_is_connect_id_reassoc_in_non_init(cm_ctx, resp->cm_id)) {
3017 resp->send_disconnect = true;
3018 mlme_debug(CM_PREFIX_FMT "Set send disconnect to true to indicate disconnect instead of connect resp",
3019 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
3020 resp->cm_id));
3021 }
3022 if (acquire_lock)
3023 cm_req_lock_release(cm_ctx);
3024 }
3025 cm_osif_connect_complete(cm_ctx, resp);
3026 cm_if_mgr_inform_connect_complete(cm_ctx->vdev,
3027 resp->connect_status);
3028 cm_inform_dlm_connect_complete(cm_ctx->vdev, resp);
3029 if (QDF_IS_STATUS_ERROR(resp->connect_status) &&
3030 sm_state == WLAN_CM_S_INIT && !cm_is_link_switch_connect_resp(resp))
3031 cm_clear_vdev_mlo_cap(cm_ctx->vdev);
3032
3033 return QDF_STATUS_SUCCESS;
3034 }
3035
3036 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
3037 static enum phy_ch_width
cm_get_ch_width_from_phymode(enum wlan_phymode phy_mode)3038 cm_get_ch_width_from_phymode(enum wlan_phymode phy_mode)
3039 {
3040 enum phy_ch_width ch_width;
3041
3042 if (IS_WLAN_PHYMODE_320MHZ(phy_mode))
3043 ch_width = CH_WIDTH_320MHZ;
3044 else if (IS_WLAN_PHYMODE_160MHZ(phy_mode))
3045 ch_width = CH_WIDTH_160MHZ;
3046 else if (IS_WLAN_PHYMODE_80MHZ(phy_mode))
3047 ch_width = CH_WIDTH_80MHZ;
3048 else if (IS_WLAN_PHYMODE_40MHZ(phy_mode))
3049 ch_width = CH_WIDTH_40MHZ;
3050 else
3051 ch_width = CH_WIDTH_20MHZ;
3052
3053 return ch_width;
3054 }
3055
3056 static
cm_update_link_channel_info(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * mac_addr,qdf_freq_t freq)3057 void cm_update_link_channel_info(struct wlan_objmgr_vdev *vdev,
3058 struct qdf_mac_addr *mac_addr,
3059 qdf_freq_t freq)
3060 {
3061 struct wlan_objmgr_pdev *pdev;
3062 uint8_t link_id;
3063 struct scan_cache_entry *cache_entry;
3064 struct wlan_channel channel = {0};
3065
3066 pdev = wlan_vdev_get_pdev(vdev);
3067 cache_entry = wlan_scan_get_scan_entry_by_mac_freq(pdev, mac_addr,
3068 freq);
3069 if (!cache_entry) {
3070 mlme_debug("not found the mac_addr from scan entry");
3071 return;
3072 }
3073
3074 link_id = cache_entry->ml_info.self_link_id;
3075
3076 channel.ch_freq = cache_entry->channel.chan_freq;
3077 channel.ch_ieee = wlan_reg_freq_to_chan(pdev, channel.ch_freq);
3078 channel.ch_phymode = cache_entry->phy_mode;
3079 channel.ch_cfreq1 = cache_entry->channel.cfreq0;
3080 channel.ch_cfreq2 = cache_entry->channel.cfreq1;
3081 channel.ch_width = cm_get_ch_width_from_phymode(cache_entry->phy_mode);
3082 /*
3083 * Supplicant needs non zero center_freq1 in case of 20 MHz connection
3084 * also as a response of get_channel request. In case of 20 MHz channel
3085 * width central frequency is same as channel frequency
3086 */
3087 if (channel.ch_width == CH_WIDTH_20MHZ)
3088 channel.ch_cfreq1 = channel.ch_freq;
3089
3090 util_scan_free_cache_entry(cache_entry);
3091 mlo_mgr_update_ap_channel_info(vdev, link_id, (uint8_t *)mac_addr,
3092 channel);
3093 }
3094 #else
cm_update_link_channel_info(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * mac_addr,qdf_freq_t freq)3095 static void cm_update_link_channel_info(struct wlan_objmgr_vdev *vdev,
3096 struct qdf_mac_addr *mac_addr,
3097 qdf_freq_t freq)
3098 {
3099 }
3100 #endif
3101
cm_update_scan_mlme_info(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)3102 void cm_update_scan_mlme_info(struct cnx_mgr *cm_ctx,
3103 struct wlan_cm_connect_resp *resp)
3104 {
3105 struct mlme_info mlme_info = {0};
3106 struct bss_info bss_info = {0};
3107
3108 /* Update scan entry in case connect is success or fails with bssid */
3109 if (qdf_is_macaddr_zero(&resp->bssid))
3110 goto update_standby;
3111
3112 if (QDF_IS_STATUS_SUCCESS(resp->connect_status))
3113 mlme_info.assoc_state = SCAN_ENTRY_CON_STATE_ASSOC;
3114 else
3115 mlme_info.assoc_state = SCAN_ENTRY_CON_STATE_NONE;
3116
3117 qdf_copy_macaddr(&bss_info.bssid, &resp->bssid);
3118 bss_info.freq = resp->freq;
3119
3120 bss_info.ssid.length = resp->ssid.length;
3121 qdf_mem_copy(&bss_info.ssid.ssid, resp->ssid.ssid,
3122 bss_info.ssid.length);
3123
3124 wlan_scan_update_mlme_by_bssinfo(
3125 wlan_vdev_get_pdev(cm_ctx->vdev),
3126 &bss_info, &mlme_info);
3127 cm_update_link_channel_info(cm_ctx->vdev, &resp->bssid,
3128 resp->freq);
3129
3130 update_standby:
3131 cm_standby_link_update_mlme_by_bssid(cm_ctx->vdev,
3132 mlme_info.assoc_state,
3133 resp->ssid);
3134 }
3135
cm_connect_complete(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_resp * resp)3136 QDF_STATUS cm_connect_complete(struct cnx_mgr *cm_ctx,
3137 struct wlan_cm_connect_resp *resp)
3138 {
3139 enum wlan_cm_sm_state sm_state;
3140 bool send_ind = true;
3141
3142 /*
3143 * If the entry is not present in the list, it must have been cleared
3144 * already.
3145 */
3146 if (!cm_get_req_by_cm_id(cm_ctx, resp->cm_id))
3147 return QDF_STATUS_SUCCESS;
3148
3149 sm_state = cm_get_state(cm_ctx);
3150 cm_set_fils_connection(cm_ctx, resp);
3151 if (QDF_IS_STATUS_SUCCESS(resp->connect_status) &&
3152 sm_state == WLAN_CM_S_CONNECTED) {
3153 cm_update_scan_db_on_connect_success(cm_ctx, resp);
3154 /* set WEP and FILS key on success */
3155 cm_set_fils_wep_key(cm_ctx, resp);
3156 }
3157
3158 /* In case of reassoc failure no need to inform osif/legacy/ifmanager */
3159 if (resp->is_reassoc && QDF_IS_STATUS_ERROR(resp->connect_status))
3160 send_ind = false;
3161
3162 if (send_ind)
3163 cm_notify_connect_complete(cm_ctx, resp, 1);
3164
3165
3166 cm_update_scan_mlme_info(cm_ctx, resp);
3167
3168 mlme_debug(CM_PREFIX_FMT,
3169 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
3170 resp->cm_id));
3171 cm_remove_cmd(cm_ctx, &resp->cm_id);
3172
3173 if (cm_is_link_switch_connect_resp(resp)) {
3174 cm_reset_active_cm_id(cm_ctx->vdev, resp->cm_id);
3175 mlo_mgr_link_switch_connect_done(cm_ctx->vdev,
3176 resp->connect_status);
3177 }
3178
3179 return QDF_STATUS_SUCCESS;
3180 }
3181
cm_add_connect_req_to_list(struct cnx_mgr * cm_ctx,struct cm_connect_req * req)3182 QDF_STATUS cm_add_connect_req_to_list(struct cnx_mgr *cm_ctx,
3183 struct cm_connect_req *req)
3184 {
3185 QDF_STATUS status;
3186 struct cm_req *cm_req;
3187
3188 cm_req = qdf_container_of(req, struct cm_req, connect_req);
3189 req->cm_id = cm_get_cm_id(cm_ctx, req->req.source);
3190 cm_req->cm_id = req->cm_id;
3191 status = cm_add_req_to_list_and_indicate_osif(cm_ctx, cm_req,
3192 req->req.source);
3193
3194 return status;
3195 }
3196
cm_connect_rsp(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_resp * resp)3197 QDF_STATUS cm_connect_rsp(struct wlan_objmgr_vdev *vdev,
3198 struct wlan_cm_connect_resp *resp)
3199 {
3200 struct cnx_mgr *cm_ctx;
3201 QDF_STATUS qdf_status;
3202 wlan_cm_id cm_id;
3203 uint32_t prefix;
3204 struct qdf_mac_addr pmksa_mac = QDF_MAC_ADDR_ZERO_INIT;
3205
3206 cm_ctx = cm_get_cm_ctx(vdev);
3207 if (!cm_ctx)
3208 return QDF_STATUS_E_INVAL;
3209
3210 cm_id = cm_ctx->active_cm_id;
3211 prefix = CM_ID_GET_PREFIX(cm_id);
3212
3213 if (prefix != CONNECT_REQ_PREFIX || cm_id != resp->cm_id) {
3214 mlme_err(CM_PREFIX_FMT " Active cm_id 0x%x is different",
3215 CM_PREFIX_REF(wlan_vdev_get_id(vdev), resp->cm_id),
3216 cm_id);
3217 qdf_status = QDF_STATUS_E_FAILURE;
3218 goto post_err;
3219 }
3220
3221 cm_connect_rsp_get_mld_addr_or_bssid(resp, &pmksa_mac);
3222
3223 if (QDF_IS_STATUS_SUCCESS(resp->connect_status)) {
3224 /*
3225 * On successful connection to sae single pmk AP,
3226 * clear all the single pmk AP.
3227 */
3228 if (cm_is_cm_id_current_candidate_single_pmk(cm_ctx, cm_id))
3229 wlan_crypto_selective_clear_sae_single_pmk_entries(vdev,
3230 &pmksa_mac);
3231 qdf_status =
3232 cm_sm_deliver_event(vdev,
3233 WLAN_CM_SM_EV_CONNECT_SUCCESS,
3234 sizeof(*resp), resp);
3235 if (QDF_IS_STATUS_SUCCESS(qdf_status))
3236 return qdf_status;
3237 /*
3238 * failure mean that the new connect/disconnect is received so
3239 * cleanup.
3240 */
3241 goto post_err;
3242 }
3243
3244 /*
3245 * Delete the PMKID of the BSSID for which the assoc reject is
3246 * received from the AP due to invalid PMKID reason.
3247 * This will avoid the driver trying to connect to same AP with
3248 * the same stale PMKID. when connection is tried again with this AP.
3249 */
3250 if (resp->status_code == STATUS_INVALID_PMKID)
3251 cm_delete_pmksa_for_bssid(cm_ctx, &pmksa_mac);
3252
3253 /* In case of failure try with next candidate */
3254 qdf_status =
3255 cm_sm_deliver_event(vdev,
3256 WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE,
3257 sizeof(*resp), resp);
3258
3259 if (QDF_IS_STATUS_SUCCESS(qdf_status))
3260 return qdf_status;
3261 /*
3262 * If connection fails with Single PMK bssid, clear this pmk
3263 * entry in case of post failure.
3264 */
3265 if (cm_is_cm_id_current_candidate_single_pmk(cm_ctx, cm_id))
3266 cm_delete_pmksa_for_single_pmk_bssid(cm_ctx, &pmksa_mac);
3267 post_err:
3268 /*
3269 * If there is a event posting error it means the SM state is not in
3270 * JOIN ACTIVE (some new cmd has changed the state of SM), so just
3271 * complete the connect command.
3272 */
3273 cm_connect_complete(cm_ctx, resp);
3274
3275 return qdf_status;
3276 }
3277
3278 #if defined(CONN_MGR_ADV_FEATURE) && defined(WLAN_FEATURE_11BE_MLO)
cm_bss_peer_create_resp_mlo_attach(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * peer_mac)3279 QDF_STATUS cm_bss_peer_create_resp_mlo_attach(struct wlan_objmgr_vdev *vdev,
3280 struct qdf_mac_addr *peer_mac)
3281 {
3282 QDF_STATUS status;
3283 struct wlan_objmgr_psoc *psoc;
3284 struct wlan_objmgr_peer *link_peer;
3285 struct mlo_partner_info partner_info;
3286
3287 if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
3288 return QDF_STATUS_SUCCESS;
3289
3290 psoc = wlan_vdev_get_psoc(vdev);
3291 if (!psoc)
3292 return QDF_STATUS_E_NULL_VALUE;
3293
3294 link_peer = wlan_objmgr_get_peer_by_mac(psoc, (uint8_t *)peer_mac,
3295 WLAN_MLME_CM_ID);
3296 if (!link_peer)
3297 return QDF_STATUS_E_NULL_VALUE;
3298
3299 partner_info.num_partner_links = 1;
3300 qdf_mem_copy(partner_info.partner_link_info[0].link_addr.bytes,
3301 vdev->vdev_mlme.macaddr, QDF_MAC_ADDR_SIZE);
3302 partner_info.partner_link_info[0].link_id = wlan_vdev_get_link_id(vdev);
3303
3304 status = wlan_mlo_peer_create(vdev, link_peer, &partner_info, NULL, 0);
3305 if (QDF_IS_STATUS_ERROR(status)) {
3306 mlme_err("Failed to attach MLO peer " QDF_MAC_ADDR_FMT,
3307 QDF_MAC_ADDR_REF(peer_mac->bytes));
3308 }
3309
3310 wlan_objmgr_peer_release_ref(link_peer, WLAN_MLME_CM_ID);
3311
3312 return status;
3313 }
3314 #endif
3315
cm_bss_peer_create_rsp(struct wlan_objmgr_vdev * vdev,QDF_STATUS status,struct qdf_mac_addr * peer_mac)3316 QDF_STATUS cm_bss_peer_create_rsp(struct wlan_objmgr_vdev *vdev,
3317 QDF_STATUS status,
3318 struct qdf_mac_addr *peer_mac)
3319 {
3320 struct cnx_mgr *cm_ctx;
3321 QDF_STATUS qdf_status;
3322 wlan_cm_id cm_id;
3323 uint32_t prefix;
3324 struct wlan_cm_connect_resp *resp;
3325
3326 cm_ctx = cm_get_cm_ctx(vdev);
3327 if (!cm_ctx)
3328 return QDF_STATUS_E_INVAL;
3329
3330 cm_id = cm_ctx->active_cm_id;
3331 prefix = CM_ID_GET_PREFIX(cm_id);
3332
3333 if (prefix != CONNECT_REQ_PREFIX) {
3334 mlme_err(CM_PREFIX_FMT "active req is not connect req",
3335 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
3336 mlme_cm_bss_peer_delete_req(vdev);
3337 return QDF_STATUS_E_INVAL;
3338 }
3339
3340 if (QDF_IS_STATUS_SUCCESS(status)) {
3341 qdf_status = cm_bss_peer_create_resp_mlo_attach(vdev, peer_mac);
3342 if (QDF_IS_STATUS_ERROR(qdf_status)) {
3343 mlme_cm_bss_peer_delete_req(vdev);
3344 goto next_candidate;
3345 }
3346
3347 qdf_status =
3348 cm_sm_deliver_event(vdev,
3349 WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS,
3350 sizeof(wlan_cm_id), &cm_id);
3351 if (QDF_IS_STATUS_SUCCESS(qdf_status))
3352 return qdf_status;
3353
3354 mlme_cm_bss_peer_delete_req(vdev);
3355 goto post_err;
3356 }
3357
3358 next_candidate:
3359 /* In case of failure try with next candidate */
3360 resp = qdf_mem_malloc(sizeof(*resp));
3361 if (!resp) {
3362 qdf_status = QDF_STATUS_E_NOMEM;
3363 goto post_err;
3364 }
3365
3366 cm_fill_failure_resp_from_cm_id(cm_ctx, resp, cm_id,
3367 CM_PEER_CREATE_FAILED);
3368 qdf_status =
3369 cm_sm_deliver_event(vdev,
3370 WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE,
3371 sizeof(*resp), resp);
3372 qdf_mem_free(resp);
3373 if (QDF_IS_STATUS_SUCCESS(qdf_status))
3374 return qdf_status;
3375
3376 post_err:
3377 /*
3378 * If there is a event posting error it means the SM state is not in
3379 * JOIN ACTIVE (some new cmd has changed the state of SM), so just
3380 * complete the connect command.
3381 */
3382 cm_connect_handle_event_post_fail(cm_ctx, cm_id);
3383 return qdf_status;
3384 }
3385
3386 static void
cm_copy_crypto_prarams(struct wlan_cm_connect_crypto_info * dst_params,struct wlan_crypto_params * src_params)3387 cm_copy_crypto_prarams(struct wlan_cm_connect_crypto_info *dst_params,
3388 struct wlan_crypto_params *src_params)
3389 {
3390 /*
3391 * As akm suites and ucast ciphers can be multiple. So, do ORing to
3392 * keep it along with newly added one's (newly added one will anyway
3393 * be part of it)
3394 */
3395 dst_params->akm_suites |= src_params->key_mgmt;
3396 dst_params->auth_type = src_params->authmodeset;
3397 dst_params->ciphers_pairwise |= src_params->ucastcipherset;
3398 dst_params->group_cipher = src_params->mcastcipherset;
3399 dst_params->mgmt_ciphers = src_params->mgmtcipherset;
3400 dst_params->rsn_caps = src_params->rsn_caps;
3401 }
3402
3403 static void
cm_set_crypto_params_from_ie(struct wlan_cm_connect_req * req)3404 cm_set_crypto_params_from_ie(struct wlan_cm_connect_req *req)
3405 {
3406 struct wlan_crypto_params crypto_params;
3407 QDF_STATUS status;
3408 uint8_t wsc_oui[OUI_LENGTH];
3409 uint8_t osen_oui[OUI_LENGTH];
3410 uint32_t oui_cpu;
3411
3412 if (!req->assoc_ie.ptr)
3413 return;
3414
3415 oui_cpu = qdf_be32_to_cpu(WSC_OUI);
3416 qdf_mem_copy(wsc_oui, &oui_cpu, OUI_LENGTH);
3417 oui_cpu = qdf_be32_to_cpu(OSEN_OUI);
3418 qdf_mem_copy(osen_oui, &oui_cpu, OUI_LENGTH);
3419 if (wlan_get_vendor_ie_ptr_from_oui(osen_oui, OUI_LENGTH,
3420 req->assoc_ie.ptr,
3421 req->assoc_ie.len))
3422 req->is_osen_connection = true;
3423
3424 if (wlan_get_vendor_ie_ptr_from_oui(wsc_oui, OUI_LENGTH,
3425 req->assoc_ie.ptr,
3426 req->assoc_ie.len))
3427 req->is_wps_connection = true;
3428
3429 status = wlan_get_crypto_params_from_rsn_ie(&crypto_params,
3430 req->assoc_ie.ptr,
3431 req->assoc_ie.len);
3432 if (QDF_IS_STATUS_SUCCESS(status)) {
3433 cm_copy_crypto_prarams(&req->crypto, &crypto_params);
3434 return;
3435 }
3436
3437 status = wlan_get_crypto_params_from_wpa_ie(&crypto_params,
3438 req->assoc_ie.ptr,
3439 req->assoc_ie.len);
3440 if (QDF_IS_STATUS_SUCCESS(status)) {
3441 cm_copy_crypto_prarams(&req->crypto, &crypto_params);
3442 return;
3443 }
3444
3445 status = wlan_get_crypto_params_from_wapi_ie(&crypto_params,
3446 req->assoc_ie.ptr,
3447 req->assoc_ie.len);
3448 if (QDF_IS_STATUS_SUCCESS(status))
3449 cm_copy_crypto_prarams(&req->crypto, &crypto_params);
3450 }
3451
3452 static QDF_STATUS
cm_allocate_and_copy_ies_and_keys(struct wlan_cm_connect_req * target,struct wlan_cm_connect_req * source)3453 cm_allocate_and_copy_ies_and_keys(struct wlan_cm_connect_req *target,
3454 struct wlan_cm_connect_req *source)
3455 {
3456 /* Reset the copied pointers of target */
3457 target->assoc_ie.ptr = NULL;
3458 target->crypto.wep_keys.key = NULL;
3459 target->crypto.wep_keys.seq = NULL;
3460 target->scan_ie.ptr = NULL;
3461
3462 if (source->scan_ie.ptr) {
3463 target->scan_ie.ptr = qdf_mem_malloc(source->scan_ie.len);
3464 if (!target->scan_ie.ptr)
3465 target->scan_ie.len = 0;
3466 else
3467 qdf_mem_copy(target->scan_ie.ptr,
3468 source->scan_ie.ptr, source->scan_ie.len);
3469 }
3470
3471 if (source->assoc_ie.ptr) {
3472 target->assoc_ie.ptr = qdf_mem_malloc(source->assoc_ie.len);
3473 if (!target->assoc_ie.ptr)
3474 return QDF_STATUS_E_NOMEM;
3475
3476 qdf_mem_copy(target->assoc_ie.ptr, source->assoc_ie.ptr,
3477 source->assoc_ie.len);
3478 }
3479
3480 if (source->crypto.wep_keys.key) {
3481 target->crypto.wep_keys.key =
3482 qdf_mem_malloc(source->crypto.wep_keys.key_len);
3483 if (!target->crypto.wep_keys.key)
3484 return QDF_STATUS_E_NOMEM;
3485
3486 qdf_mem_copy(target->crypto.wep_keys.key,
3487 source->crypto.wep_keys.key,
3488 source->crypto.wep_keys.key_len);
3489 }
3490
3491 if (source->crypto.wep_keys.seq) {
3492 target->crypto.wep_keys.seq =
3493 qdf_mem_malloc(source->crypto.wep_keys.seq_len);
3494 if (!target->crypto.wep_keys.seq)
3495 return QDF_STATUS_E_NOMEM;
3496
3497 qdf_mem_copy(target->crypto.wep_keys.seq,
3498 source->crypto.wep_keys.seq,
3499 source->crypto.wep_keys.seq_len);
3500 }
3501
3502 return QDF_STATUS_SUCCESS;
3503 }
3504
cm_connect_start_req(struct wlan_objmgr_vdev * vdev,struct wlan_cm_connect_req * req)3505 QDF_STATUS cm_connect_start_req(struct wlan_objmgr_vdev *vdev,
3506 struct wlan_cm_connect_req *req)
3507 {
3508 struct cnx_mgr *cm_ctx;
3509 struct cm_req *cm_req;
3510 struct cm_connect_req *connect_req;
3511 QDF_STATUS status;
3512
3513 cm_ctx = cm_get_cm_ctx(vdev);
3514 if (!cm_ctx)
3515 return QDF_STATUS_E_INVAL;
3516
3517 cm_vdev_scan_cancel(wlan_vdev_get_pdev(cm_ctx->vdev), cm_ctx->vdev);
3518
3519 /*
3520 * This would be freed as part of removal from cm req list if adding
3521 * to list is success after posting WLAN_CM_SM_EV_CONNECT_REQ.
3522 */
3523 cm_req = qdf_mem_malloc(sizeof(*cm_req));
3524 if (!cm_req)
3525 return QDF_STATUS_E_NOMEM;
3526
3527 if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
3528 wlan_vdev_mlme_is_mlo_link_vdev(vdev))
3529 req->is_non_assoc_link = 1;
3530
3531 connect_req = &cm_req->connect_req;
3532 connect_req->req = *req;
3533
3534 status = cm_allocate_and_copy_ies_and_keys(&connect_req->req, req);
3535 if (QDF_IS_STATUS_ERROR(status))
3536 goto err;
3537
3538 cm_set_crypto_params_from_ie(&connect_req->req);
3539
3540 cm_handle_connect_start_req(vdev, req);
3541
3542 status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_CONNECT_REQ,
3543 sizeof(*connect_req), connect_req);
3544
3545 err:
3546 /* free the req if connect is not handled */
3547 if (QDF_IS_STATUS_ERROR(status)) {
3548 cm_free_connect_req_mem(connect_req);
3549 qdf_mem_free(cm_req);
3550 }
3551
3552 return status;
3553 }
3554