xref: /wlan-driver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_connect.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
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