xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_util.c (revision 2888b71da71bce103343119fa1b31f4a0cee07c8)
1 /*
2  * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 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 general util apis of connection manager
20  */
21 
22 #include "wlan_cm_main_api.h"
23 #include "wlan_scan_api.h"
24 #include "wlan_cm_public_struct.h"
25 #include "wlan_serialization_api.h"
26 #include "wlan_cm_bss_score_param.h"
27 #ifdef WLAN_POLICY_MGR_ENABLE
28 #include <wlan_policy_mgr_api.h>
29 #endif
30 #include "wlan_cm_roam.h"
31 #include <qdf_platform.h>
32 
33 static uint32_t cm_get_prefix_for_cm_id(enum wlan_cm_source source) {
34 	switch (source) {
35 	case CM_OSIF_CONNECT:
36 	case CM_OSIF_CFG_CONNECT:
37 		return CONNECT_REQ_PREFIX;
38 	case CM_ROAMING_HOST:
39 	case CM_ROAMING_FW:
40 	case CM_ROAMING_NUD_FAILURE:
41 		return ROAM_REQ_PREFIX;
42 	default:
43 		return DISCONNECT_REQ_PREFIX;
44 	}
45 }
46 
47 wlan_cm_id cm_get_cm_id(struct cnx_mgr *cm_ctx, enum wlan_cm_source source)
48 {
49 	wlan_cm_id cm_id;
50 	uint32_t prefix;
51 	uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
52 
53 	prefix = cm_get_prefix_for_cm_id(source);
54 
55 	cm_id = qdf_atomic_inc_return(&cm_ctx->global_cmd_id);
56 	cm_id = (cm_id & CM_ID_MASK);
57 	cm_id = CM_ID_SET_VDEV_ID(cm_id, vdev_id);
58 	cm_id = (cm_id | prefix);
59 
60 	return cm_id;
61 }
62 
63 struct cnx_mgr *cm_get_cm_ctx_fl(struct wlan_objmgr_vdev *vdev,
64 				 const char *func, uint32_t line)
65 {
66 	struct vdev_mlme_obj *vdev_mlme;
67 	struct cnx_mgr *cm_ctx = NULL;
68 
69 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
70 	if (vdev_mlme)
71 		cm_ctx = vdev_mlme->cnx_mgr_ctx;
72 
73 	if (!cm_ctx)
74 		mlme_nofl_err("%s:%u: vdev %d cm_ctx is NULL", func, line,
75 			      wlan_vdev_get_id(vdev));
76 
77 	return cm_ctx;
78 }
79 
80 cm_ext_t *cm_get_ext_hdl_fl(struct wlan_objmgr_vdev *vdev,
81 			    const char *func, uint32_t line)
82 {
83 	struct cnx_mgr *cm_ctx;
84 	cm_ext_t *ext_ctx = NULL;
85 
86 	cm_ctx = cm_get_cm_ctx_fl(vdev, func, line);
87 	if (cm_ctx)
88 		ext_ctx = cm_ctx->ext_cm_ptr;
89 
90 	if (!ext_ctx)
91 		mlme_nofl_err("%s:%u: vdev %d cm ext ctx is NULL", func, line,
92 			      wlan_vdev_get_id(vdev));
93 	return ext_ctx;
94 }
95 
96 void cm_reset_active_cm_id(struct wlan_objmgr_vdev *vdev, wlan_cm_id cm_id)
97 {
98 	struct cnx_mgr *cm_ctx;
99 
100 	cm_ctx = cm_get_cm_ctx(vdev);
101 	if (!cm_ctx)
102 		return;
103 
104 	/* Reset active cm id if cm id match */
105 	if (cm_ctx->active_cm_id == cm_id)
106 		cm_ctx->active_cm_id = CM_ID_INVALID;
107 }
108 
109 
110 #ifdef WLAN_CM_USE_SPINLOCK
111 /**
112  * cm_req_lock_acquire - acquire CM SM mutex/spinlock
113  * @cm_ctx:  connection manager ctx
114  *
115  * acquire CM SM mutex/spinlock
116  *
117  * return: void
118  */
119 inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
120 {
121 	qdf_spinlock_acquire(&cm_ctx->cm_req_lock);
122 }
123 
124 /**
125  * cm_req_lock_release - release CM SM mutex/spinlock
126  * @cm_ctx:  connection manager ctx
127  *
128  * release CM SM mutex/spinlock
129  *
130  * return: void
131  */
132 inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
133 {
134 	qdf_spinlock_release(&cm_ctx->cm_req_lock);
135 }
136 
137 QDF_STATUS cm_activate_cmd_req_flush_cb(struct scheduler_msg *msg)
138 {
139 	struct wlan_serialization_command *cmd = msg->bodyptr;
140 
141 	if (!cmd || !cmd->vdev) {
142 		mlme_err("Null input cmd:%pK", cmd);
143 		return QDF_STATUS_E_INVAL;
144 	}
145 
146 	wlan_objmgr_vdev_release_ref(cmd->vdev, WLAN_MLME_CM_ID);
147 	return QDF_STATUS_SUCCESS;
148 }
149 
150 #else
151 inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
152 {
153 	qdf_mutex_acquire(&cm_ctx->cm_req_lock);
154 }
155 
156 inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
157 {
158 	qdf_mutex_release(&cm_ctx->cm_req_lock);
159 }
160 #endif /* WLAN_CM_USE_SPINLOCK */
161 
162 #ifdef CRYPTO_SET_KEY_CONVERGED
163 QDF_STATUS cm_set_key(struct cnx_mgr *cm_ctx, bool unicast,
164 		      uint8_t key_idx, struct qdf_mac_addr *bssid)
165 {
166 	enum wlan_crypto_cipher_type cipher;
167 	struct wlan_crypto_key *crypto_key;
168 	uint8_t wep_key_idx = 0;
169 
170 	cipher = wlan_crypto_get_cipher(cm_ctx->vdev, unicast, key_idx);
171 	if (IS_WEP_CIPHER(cipher)) {
172 		wep_key_idx = wlan_crypto_get_default_key_idx(cm_ctx->vdev,
173 							      !unicast);
174 		crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_key_idx);
175 		qdf_mem_copy(crypto_key->macaddr, bssid->bytes,
176 			     QDF_MAC_ADDR_SIZE);
177 	} else {
178 		crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_idx);
179 	}
180 
181 	return wlan_crypto_set_key_req(cm_ctx->vdev, crypto_key, (unicast ?
182 				       WLAN_CRYPTO_KEY_TYPE_UNICAST :
183 				       WLAN_CRYPTO_KEY_TYPE_GROUP));
184 }
185 #endif
186 
187 #ifdef CONN_MGR_ADV_FEATURE
188 void cm_store_wep_key(struct cnx_mgr *cm_ctx,
189 		      struct wlan_cm_connect_crypto_info *crypto,
190 		      wlan_cm_id cm_id)
191 {
192 	struct wlan_crypto_key *crypto_key = NULL;
193 	QDF_STATUS status;
194 	enum wlan_crypto_cipher_type cipher_type;
195 	struct wlan_cm_wep_key_params *wep_keys;
196 
197 	if (!(crypto->ciphers_pairwise & (1 << WLAN_CRYPTO_CIPHER_WEP_40 |
198 					  1 << WLAN_CRYPTO_CIPHER_WEP_104)))
199 		return;
200 
201 	if (crypto->ciphers_pairwise & 1 << WLAN_CRYPTO_CIPHER_WEP_40)
202 		cipher_type = WLAN_CRYPTO_CIPHER_WEP_40;
203 	else
204 		cipher_type = WLAN_CRYPTO_CIPHER_WEP_104;
205 
206 	wep_keys = &crypto->wep_keys;
207 	status = wlan_crypto_validate_key_params(cipher_type,
208 						 wep_keys->key_idx,
209 						 wep_keys->key_len,
210 						 wep_keys->seq_len);
211 	if (QDF_IS_STATUS_ERROR(status)) {
212 		mlme_err(CM_PREFIX_FMT "Invalid key params",
213 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
214 		return;
215 	}
216 
217 	crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_keys->key_idx);
218 	if (!crypto_key) {
219 		crypto_key = qdf_mem_malloc(sizeof(*crypto_key));
220 		if (!crypto_key)
221 			return;
222 
223 		status = wlan_crypto_save_key(cm_ctx->vdev, wep_keys->key_idx,
224 					      crypto_key);
225 		if (QDF_IS_STATUS_ERROR(status)) {
226 			mlme_err(CM_PREFIX_FMT "Failed to save key",
227 				 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
228 					       cm_id));
229 			qdf_mem_free(crypto_key);
230 			return;
231 		}
232 	}
233 	qdf_mem_zero(crypto_key, sizeof(*crypto_key));
234 	crypto_key->cipher_type = cipher_type;
235 	crypto_key->keylen = wep_keys->key_len;
236 	crypto_key->keyix = wep_keys->key_idx;
237 	qdf_mem_copy(&crypto_key->keyval[0], wep_keys->key, wep_keys->key_len);
238 	qdf_mem_copy(&crypto_key->keyrsc[0], wep_keys->seq, wep_keys->seq_len);
239 	mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, seq_len %d",
240 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
241 		   crypto_key->cipher_type, wep_keys->key_len,
242 		   wep_keys->seq_len);
243 }
244 
245 void cm_trigger_panic_on_cmd_timeout(struct wlan_objmgr_vdev *vdev)
246 {
247 	struct wlan_objmgr_psoc *psoc;
248 
249 	psoc = wlan_vdev_get_psoc(vdev);
250 	if (!psoc)
251 		return;
252 
253 	if (qdf_is_recovering() || qdf_is_fw_down())
254 		return;
255 
256 	qdf_trigger_self_recovery(psoc, QDF_ACTIVE_LIST_TIMEOUT);
257 }
258 
259 #else
260 void cm_trigger_panic_on_cmd_timeout(struct wlan_objmgr_vdev *vdev)
261 {
262 	struct vdev_mlme_obj *vdev_mlme = NULL;
263 	struct wlan_sm *vdev_sm = NULL;
264 
265 	vdev_mlme = wlan_objmgr_vdev_get_comp_private_obj(
266 			vdev,
267 			WLAN_UMAC_COMP_MLME);
268 	if (!vdev_mlme) {
269 		mlme_err("VDEV MLME is null");
270 		goto error;
271 	}
272 
273 	vdev_sm = vdev_mlme->sm_hdl;
274 	if (!vdev_sm) {
275 		mlme_err("VDEV SM is null");
276 		goto error;
277 	}
278 
279 	wlan_sm_print_history(vdev_sm);
280 	cm_sm_history_print(vdev);
281 error:
282 	QDF_ASSERT(0);
283 }
284 #endif
285 
286 #ifdef WLAN_FEATURE_FILS_SK
287 void cm_store_fils_key(struct cnx_mgr *cm_ctx, bool unicast,
288 		       uint8_t key_id, uint16_t key_length,
289 		       uint8_t *key, struct qdf_mac_addr *bssid,
290 		       wlan_cm_id cm_id)
291 {
292 	struct wlan_crypto_key *crypto_key = NULL;
293 	QDF_STATUS status;
294 	uint8_t i;
295 	int32_t cipher;
296 	enum wlan_crypto_cipher_type cipher_type = WLAN_CRYPTO_CIPHER_NONE;
297 
298 	if (unicast)
299 		cipher = wlan_crypto_get_param(cm_ctx->vdev,
300 					       WLAN_CRYPTO_PARAM_UCAST_CIPHER);
301 	else
302 		cipher = wlan_crypto_get_param(cm_ctx->vdev,
303 					       WLAN_CRYPTO_PARAM_MCAST_CIPHER);
304 
305 	for (i = 0; i <= WLAN_CRYPTO_CIPHER_MAX; i++) {
306 		if (QDF_HAS_PARAM(cipher, i)) {
307 			cipher_type = i;
308 			break;
309 		}
310 	}
311 	crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_id);
312 	if (!crypto_key) {
313 		crypto_key = qdf_mem_malloc(sizeof(*crypto_key));
314 		if (!crypto_key)
315 			return;
316 		status = wlan_crypto_save_key(cm_ctx->vdev, key_id, crypto_key);
317 		if (QDF_IS_STATUS_ERROR(status)) {
318 			mlme_err(CM_PREFIX_FMT "Failed to save key",
319 				 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
320 					       cm_id));
321 			qdf_mem_free(crypto_key);
322 			return;
323 		}
324 	}
325 	qdf_mem_zero(crypto_key, sizeof(*crypto_key));
326 	crypto_key->cipher_type = cipher_type;
327 	crypto_key->keylen = key_length;
328 	crypto_key->keyix = key_id;
329 	qdf_mem_copy(&crypto_key->keyval[0], key, key_length);
330 	qdf_mem_copy(crypto_key->macaddr, bssid->bytes, QDF_MAC_ADDR_SIZE);
331 	mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, key_id %d mac:" QDF_MAC_ADDR_FMT,
332 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
333 		   crypto_key->cipher_type, crypto_key->keylen,
334 		   crypto_key->keyix, QDF_MAC_ADDR_REF(crypto_key->macaddr));
335 }
336 static void cm_set_fils_connection_from_req(struct wlan_cm_connect_req *req,
337 					    struct wlan_cm_connect_resp *resp)
338 {
339 	resp->is_fils_connection = req->fils_info.is_fils_connection;
340 }
341 #else
342 static inline
343 void cm_set_fils_connection_from_req(struct wlan_cm_connect_req *req,
344 				     struct wlan_cm_connect_resp *resp)
345 {}
346 #endif
347 
348 bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
349 {
350 	qdf_list_node_t *cur_node = NULL;
351 	struct cm_req *cm_req;
352 	bool match = false;
353 	wlan_cm_id head_cm_id = 0;
354 
355 	if (!cm_id)
356 		return false;
357 
358 	cm_req_lock_acquire(cm_ctx);
359 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
360 	if (!cur_node)
361 		goto exit;
362 
363 	cm_req = qdf_container_of(cur_node, struct cm_req, node);
364 	head_cm_id = cm_req->cm_id;
365 	if (head_cm_id == *cm_id)
366 		match = true;
367 
368 exit:
369 	cm_req_lock_release(cm_ctx);
370 	if (!match)
371 		mlme_info("head_cm_id 0x%x didn't match the given cm_id 0x%x",
372 			  head_cm_id, *cm_id);
373 
374 	return match;
375 }
376 
377 bool cm_check_scanid_match_list_head(struct cnx_mgr *cm_ctx,
378 				     wlan_scan_id *scan_id)
379 {
380 	qdf_list_node_t *cur_node = NULL;
381 	struct cm_req *cm_req;
382 	bool match = false;
383 	wlan_cm_id head_scan_id = 0;
384 	uint32_t prefix = 0;
385 
386 	if (!scan_id)
387 		return false;
388 
389 	cm_req_lock_acquire(cm_ctx);
390 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
391 	if (!cur_node)
392 		goto exit;
393 
394 	cm_req = qdf_container_of(cur_node, struct cm_req, node);
395 	prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
396 	/* Check only if head is connect req */
397 	if (prefix != CONNECT_REQ_PREFIX)
398 		goto exit;
399 	head_scan_id = cm_req->connect_req.scan_id;
400 	if (head_scan_id == *scan_id)
401 		match = true;
402 
403 exit:
404 	cm_req_lock_release(cm_ctx);
405 	if (!match)
406 		mlme_info("head_scan_id 0x%x didn't match the given scan_id 0x%x prefix 0x%x",
407 			  head_scan_id, *scan_id, prefix);
408 
409 	return match;
410 }
411 
412 struct cm_req *cm_get_req_by_cm_id_fl(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id,
413 				      const char *func, uint32_t line)
414 {
415 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
416 	struct cm_req * cm_req;
417 
418 	cm_req_lock_acquire(cm_ctx);
419 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
420 	while (cur_node) {
421 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
422 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
423 
424 		if (cm_req->cm_id == cm_id) {
425 			cm_req_lock_release(cm_ctx);
426 			return cm_req;
427 		}
428 
429 		cur_node = next_node;
430 		next_node = NULL;
431 	}
432 	cm_req_lock_release(cm_ctx);
433 
434 	mlme_nofl_info("%s:%u: cm req not found for cm id 0x%x", func,
435 		       line, cm_id);
436 
437 	return NULL;
438 }
439 
440 /**
441  * cm_fill_connect_resp_from_req() - Fill connect resp from connect request
442  * @resp: cm connect response
443  * @cm_req: cm request
444  *
445  * Context: Can be called from APIs holding cm request list lock
446  *
447  * Return: void
448  */
449 static void
450 cm_fill_connect_resp_from_req(struct wlan_cm_connect_resp *resp,
451 			      struct cm_req *cm_req)
452 {
453 	struct scan_cache_node *candidate;
454 	struct wlan_cm_connect_req *req;
455 
456 	req = &cm_req->connect_req.req;
457 	candidate = cm_req->connect_req.cur_candidate;
458 	if (candidate)
459 		qdf_copy_macaddr(&resp->bssid, &candidate->entry->bssid);
460 	else if (!qdf_is_macaddr_zero(&req->bssid))
461 		qdf_copy_macaddr(&resp->bssid, &req->bssid);
462 	else
463 		qdf_copy_macaddr(&resp->bssid, &req->bssid_hint);
464 
465 	if (candidate)
466 		resp->freq = candidate->entry->channel.chan_freq;
467 	else
468 		resp->freq = req->chan_freq;
469 
470 	resp->ssid = req->ssid;
471 	resp->is_wps_connection = req->is_wps_connection;
472 	resp->is_osen_connection = req->is_osen_connection;
473 	cm_set_fils_connection_from_req(req, resp);
474 }
475 
476 /**
477  * cm_handle_connect_flush() - Fill fail connect resp from req and indicate
478  * same to osif
479  * @cm_ctx: connection manager context
480  * @cm_req: cm request
481  *
482  * Context: Can be called from APIs holding cm request list lock
483  *
484  * Return: void
485  */
486 static void
487 cm_handle_connect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
488 {
489 	struct wlan_cm_connect_resp *resp;
490 
491 	resp = qdf_mem_malloc(sizeof(*resp));
492 	if (!resp)
493 		return;
494 
495 	resp->connect_status = QDF_STATUS_E_FAILURE;
496 	resp->cm_id = cm_req->cm_id;
497 	resp->vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
498 	if (cm_req->failed_req)
499 		resp->reason = CM_GENERIC_FAILURE;
500 	else
501 		resp->reason = CM_ABORT_DUE_TO_NEW_REQ_RECVD;
502 
503 	/* Get bssid and ssid and freq for the cm id from the req list */
504 	cm_fill_connect_resp_from_req(resp, cm_req);
505 
506 	cm_notify_connect_complete(cm_ctx, resp);
507 	qdf_mem_free(resp);
508 }
509 
510 /**
511  * cm_handle_disconnect_flush() - Fill disconnect resp from req and indicate
512  * same to osif
513  * @cm_ctx: connection manager context
514  * @cm_req: cm request
515  *
516  * Context: Can be called from APIs holding cm request list lock
517  *
518  * Return: void
519  */
520 static void
521 cm_handle_disconnect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
522 {
523 	struct wlan_cm_discon_rsp resp;
524 
525 	qdf_mem_zero(&resp, sizeof(resp));
526 	resp.req.cm_id = cm_req->cm_id;
527 	resp.req.req = cm_req->discon_req.req;
528 	/*
529 	 * Indicate to OSIF to inform kernel if not already done and this is
530 	 * the latest disconnect req received. If this is not the latest, it
531 	 * will be dropped in OSIF as src and cm_id will not match. A flushed
532 	 * disconnect can be last of this was received when previous disconnect
533 	 * was already in serialization active queue and thus wasn't flushed.
534 	 */
535 	mlme_cm_osif_disconnect_complete(cm_ctx->vdev, &resp);
536 }
537 
538 void cm_remove_cmd_from_serialization(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
539 {
540 	struct wlan_serialization_queued_cmd_info cmd_info;
541 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
542 
543 	qdf_mem_zero(&cmd_info, sizeof(cmd_info));
544 	cmd_info.cmd_id = cm_id;
545 	cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
546 
547 	if (prefix == CONNECT_REQ_PREFIX) {
548 		cmd_info.cmd_type = WLAN_SER_CMD_VDEV_CONNECT;
549 	} else if (prefix == ROAM_REQ_PREFIX) {
550 		/*
551 		 * Try removing PREAUTH command when in preauth state else
552 		 * try remove ROAM command
553 		 */
554 		if (cm_ctx->preauth_in_progress)
555 			cmd_info.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH;
556 		else
557 			cmd_info.cmd_type = WLAN_SER_CMD_VDEV_ROAM;
558 		cm_ctx->preauth_in_progress = false;
559 	} else if (prefix == DISCONNECT_REQ_PREFIX) {
560 		cmd_info.cmd_type = WLAN_SER_CMD_VDEV_DISCONNECT;
561 	} else {
562 		mlme_err(CM_PREFIX_FMT "Invalid prefix %x",
563 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
564 			 prefix);
565 		return;
566 	}
567 
568 	cmd_info.vdev = cm_ctx->vdev;
569 
570 	if (cm_id == cm_ctx->active_cm_id) {
571 		mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from active",
572 			   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
573 			   cmd_info.cmd_type);
574 		cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
575 		/*
576 		 * Active command id is reset during memory release, but a new
577 		 * command will become active before memory release of
578 		 * serialization command, and if it try to check the active
579 		 * cm_id(using cm_get_active_req_type) it will be valid (), so
580 		 * reset the cm id for active command before calling release
581 		 * active command.
582 		 * One example: For ML vdevs, disconnect on Assoc vdev can get
583 		 * activated before release memory of link vdev command which
584 		 * reset active CM id, and thus during RSO stop can lead to
585 		 * assumption that link vdev disconnect is active when it is not.
586 		 */
587 		cm_reset_active_cm_id(cm_ctx->vdev, cm_id);
588 		wlan_serialization_remove_cmd(&cmd_info);
589 	} else {
590 		mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from pending",
591 			   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
592 			   cmd_info.cmd_type);
593 		cmd_info.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE;
594 		wlan_serialization_cancel_request(&cmd_info);
595 	}
596 }
597 
598 void
599 cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix,
600 			 bool only_failed_req)
601 {
602 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
603 	struct cm_req *cm_req;
604 	uint32_t req_prefix;
605 	bool roam_offload = false;
606 
607 	if (cm_roam_offload_enabled(wlan_vdev_get_psoc(cm_ctx->vdev)) &&
608 	     prefix == ROAM_REQ_PREFIX)
609 		roam_offload = true;
610 
611 	cm_req_lock_acquire(cm_ctx);
612 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
613 	while (cur_node) {
614 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
615 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
616 
617 		req_prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
618 
619 		/*
620 		 * Only remove requests matching the flush prefix and
621 		 * the pending req for non roam offload(LFR3) commands
622 		 * (roam command is dummy in FW roam/LFR3 so active
623 		 * command can be removed)
624 		 */
625 		if (req_prefix != prefix ||
626 		    (!roam_offload && cm_req->cm_id == cm_ctx->active_cm_id))
627 			goto next;
628 
629 		/* If only_failed_req is set flush only failed req */
630 		if (only_failed_req && !cm_req->failed_req)
631 			goto next;
632 
633 		if (req_prefix == CONNECT_REQ_PREFIX) {
634 			cm_handle_connect_flush(cm_ctx, cm_req);
635 			cm_ctx->connect_count--;
636 			cm_free_connect_req_mem(&cm_req->connect_req);
637 		} else if (req_prefix == ROAM_REQ_PREFIX) {
638 			cm_free_roam_req_mem(&cm_req->roam_req);
639 		} else if (req_prefix == DISCONNECT_REQ_PREFIX) {
640 			cm_handle_disconnect_flush(cm_ctx, cm_req);
641 			cm_ctx->disconnect_count--;
642 		} else {
643 			mlme_err(CM_PREFIX_FMT "Invalid prefix %x",
644 				 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
645 					       cm_req->cm_id), prefix);
646 		}
647 
648 		cm_req_history_del(cm_ctx, cm_req, CM_REQ_DEL_FLUSH);
649 		mlme_debug(CM_PREFIX_FMT,
650 			   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
651 					 cm_req->cm_id));
652 		cm_remove_cmd_from_serialization(cm_ctx, cm_req->cm_id);
653 		qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
654 		qdf_mem_free(cm_req);
655 next:
656 		cur_node = next_node;
657 		next_node = NULL;
658 	}
659 
660 	cm_req_lock_release(cm_ctx);
661 }
662 
663 QDF_STATUS
664 cm_fill_bss_info_in_connect_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
665 					 wlan_cm_id cm_id,
666 					 struct wlan_cm_connect_resp *resp)
667 {
668 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
669 	struct cm_req *cm_req;
670 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
671 
672 	if (prefix != CONNECT_REQ_PREFIX)
673 		return QDF_STATUS_E_INVAL;
674 
675 	cm_req_lock_acquire(cm_ctx);
676 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
677 	while (cur_node) {
678 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
679 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
680 
681 		if (cm_req->cm_id == cm_id) {
682 			cm_fill_connect_resp_from_req(resp, cm_req);
683 			cm_req_lock_release(cm_ctx);
684 			return QDF_STATUS_SUCCESS;
685 		}
686 
687 		cur_node = next_node;
688 		next_node = NULL;
689 	}
690 	cm_req_lock_release(cm_ctx);
691 
692 	return QDF_STATUS_E_FAILURE;
693 }
694 
695 #if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
696 bool cm_is_cm_id_current_candidate_single_pmk(struct cnx_mgr *cm_ctx,
697 					      wlan_cm_id cm_id)
698 {
699 	struct wlan_objmgr_psoc *psoc;
700 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
701 	struct cm_req *cm_req;
702 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
703 	int32_t akm;
704 	struct scan_cache_node *candidate;
705 	bool is_single_pmk = false;
706 
707 	psoc = wlan_vdev_get_psoc(cm_ctx->vdev);
708 	if (!psoc) {
709 		mlme_err(CM_PREFIX_FMT "Failed to find psoc",
710 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
711 				       cm_id));
712 		return is_single_pmk;
713 	}
714 
715 	if (prefix != CONNECT_REQ_PREFIX)
716 		return is_single_pmk;
717 
718 	akm = wlan_crypto_get_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_KEY_MGMT);
719 	if (!QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE))
720 		return is_single_pmk;
721 
722 	cm_req_lock_acquire(cm_ctx);
723 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
724 	while (cur_node) {
725 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
726 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
727 
728 		if (cm_req->cm_id == cm_id) {
729 			candidate = cm_req->connect_req.cur_candidate;
730 			if (candidate &&
731 			    util_scan_entry_single_pmk(psoc, candidate->entry))
732 				is_single_pmk = true;
733 			break;
734 		}
735 
736 		cur_node = next_node;
737 		next_node = NULL;
738 	}
739 	cm_req_lock_release(cm_ctx);
740 
741 	return is_single_pmk;
742 }
743 #endif
744 
745 QDF_STATUS cm_add_req_to_list_and_indicate_osif(struct cnx_mgr *cm_ctx,
746 						struct cm_req *cm_req,
747 						enum wlan_cm_source source)
748 {
749 	uint32_t prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
750 
751 	cm_req_lock_acquire(cm_ctx);
752 	if (qdf_list_size(&cm_ctx->req_list) >= CM_MAX_REQ) {
753 		cm_req_lock_release(cm_ctx);
754 		mlme_err(CM_PREFIX_FMT "List full size %d",
755 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
756 				       cm_req->cm_id),
757 			 qdf_list_size(&cm_ctx->req_list));
758 		return QDF_STATUS_E_FAILURE;
759 	}
760 
761 	qdf_list_insert_front(&cm_ctx->req_list, &cm_req->node);
762 	if (prefix == CONNECT_REQ_PREFIX)
763 		cm_ctx->connect_count++;
764 	else if (prefix == DISCONNECT_REQ_PREFIX)
765 		cm_ctx->disconnect_count++;
766 
767 	cm_req_history_add(cm_ctx, cm_req);
768 	cm_req_lock_release(cm_ctx);
769 	mlme_debug(CM_PREFIX_FMT,
770 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
771 				 cm_req->cm_id));
772 
773 	mlme_cm_osif_update_id_and_src(cm_ctx->vdev, source, cm_req->cm_id);
774 
775 	return QDF_STATUS_SUCCESS;
776 }
777 
778 static void cm_zero_and_free_memory(uint8_t *ptr, uint32_t len)
779 {
780 	if (!ptr)
781 		return;
782 
783 	qdf_mem_zero(ptr, len);
784 	qdf_mem_free(ptr);
785 }
786 
787 void cm_free_connect_req_mem(struct cm_connect_req *connect_req)
788 {
789 	struct wlan_cm_connect_req *req;
790 
791 	req = &connect_req->req;
792 
793 	if (connect_req->candidate_list)
794 		wlan_scan_purge_results(connect_req->candidate_list);
795 
796 	cm_zero_and_free_memory(req->assoc_ie.ptr, req->assoc_ie.len);
797 	cm_zero_and_free_memory(req->scan_ie.ptr, req->scan_ie.len);
798 
799 	cm_zero_and_free_memory(req->crypto.wep_keys.key,
800 				req->crypto.wep_keys.key_len);
801 	cm_zero_and_free_memory(req->crypto.wep_keys.seq,
802 				req->crypto.wep_keys.seq_len);
803 
804 	qdf_mem_zero(connect_req, sizeof(*connect_req));
805 }
806 
807 QDF_STATUS
808 cm_delete_req_from_list(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
809 {
810 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
811 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
812 	struct cm_req *cm_req = NULL;
813 
814 	cm_req_lock_acquire(cm_ctx);
815 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
816 	while (cur_node) {
817 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
818 
819 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
820 		if (cm_req->cm_id == cm_id)
821 			break;
822 
823 		cur_node = next_node;
824 		next_node = NULL;
825 		cm_req = NULL;
826 	}
827 
828 	if (!cm_req) {
829 		cm_req_lock_release(cm_ctx);
830 		mlme_err(CM_PREFIX_FMT " req not found",
831 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
832 		return QDF_STATUS_E_FAILURE;
833 	}
834 
835 	qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
836 	if (prefix == CONNECT_REQ_PREFIX) {
837 		cm_ctx->connect_count--;
838 		cm_free_connect_req_mem(&cm_req->connect_req);
839 	} else if (prefix == ROAM_REQ_PREFIX) {
840 		cm_free_roam_req_mem(&cm_req->roam_req);
841 	} else if (prefix == DISCONNECT_REQ_PREFIX) {
842 		cm_ctx->disconnect_count--;
843 	} else {
844 		mlme_err(CM_PREFIX_FMT "Invalid prefix %x",
845 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
846 				       cm_req->cm_id), prefix);
847 	}
848 
849 	if (cm_id == cm_ctx->active_cm_id)
850 		cm_req_history_del(cm_ctx, cm_req, CM_REQ_DEL_ACTIVE);
851 	else
852 		cm_req_history_del(cm_ctx, cm_req, CM_REQ_DEL_PENDING);
853 
854 	mlme_debug(CM_PREFIX_FMT,
855 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
856 				 cm_req->cm_id));
857 
858 	qdf_mem_free(cm_req);
859 	cm_req_lock_release(cm_ctx);
860 
861 	return QDF_STATUS_SUCCESS;
862 }
863 
864 void cm_remove_cmd(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id_to_remove)
865 {
866 	struct wlan_objmgr_psoc *psoc;
867 	QDF_STATUS status;
868 	wlan_cm_id cm_id;
869 
870 	if (!cm_id_to_remove) {
871 		mlme_err("cm_id_to_remove is null");
872 		return;
873 	}
874 
875 	/*
876 	 * store local value as cm_delete_req_from_list may free the
877 	 * cm_id_to_remove pointer
878 	 */
879 	cm_id = *cm_id_to_remove;
880 	/* return if zero or invalid cm_id */
881 	if (!cm_id || cm_id == CM_ID_INVALID) {
882 		mlme_debug(CM_PREFIX_FMT " Invalid cm_id",
883 			   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
884 					 cm_id));
885 		return;
886 	}
887 
888 	psoc = wlan_vdev_get_psoc(cm_ctx->vdev);
889 	if (!psoc) {
890 		mlme_err(CM_PREFIX_FMT "Failed to find psoc",
891 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
892 		return;
893 	}
894 
895 	status = cm_delete_req_from_list(cm_ctx, cm_id);
896 	if (QDF_IS_STATUS_ERROR(status))
897 		return;
898 
899 	cm_remove_cmd_from_serialization(cm_ctx, cm_id);
900 }
901 
902 void cm_vdev_scan_cancel(struct wlan_objmgr_pdev *pdev,
903 			 struct wlan_objmgr_vdev *vdev)
904 {
905 	struct scan_cancel_request *req;
906 	QDF_STATUS status;
907 
908 	req = qdf_mem_malloc(sizeof(*req));
909 	if (!req)
910 		return;
911 
912 	req->vdev = vdev;
913 	req->cancel_req.scan_id = INVAL_SCAN_ID;
914 	req->cancel_req.vdev_id = wlan_vdev_get_id(vdev);
915 	req->cancel_req.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
916 	req->cancel_req.req_type = WLAN_SCAN_CANCEL_VDEV_ALL;
917 
918 	status = wlan_scan_cancel(req);
919 	/* In success/failure case wlan_scan_cancel free the req memory */
920 	if (QDF_IS_STATUS_ERROR(status))
921 		mlme_err("vdev %d cancel scan request failed",
922 			 wlan_vdev_get_id(vdev));
923 }
924 
925 void cm_set_max_connect_attempts(struct wlan_objmgr_vdev *vdev,
926 				 uint8_t max_connect_attempts)
927 {
928 	struct cnx_mgr *cm_ctx;
929 
930 	cm_ctx = cm_get_cm_ctx(vdev);
931 	if (!cm_ctx)
932 		return;
933 
934 	cm_ctx->max_connect_attempts =
935 		QDF_MIN(max_connect_attempts, CM_MAX_CONNECT_ATTEMPTS);
936 	mlme_debug("vdev %d max connect attempts set to %d, requested %d",
937 		   wlan_vdev_get_id(vdev),
938 		   cm_ctx->max_connect_attempts, max_connect_attempts);
939 }
940 
941 void cm_set_max_connect_timeout(struct wlan_objmgr_vdev *vdev,
942 				uint32_t max_connect_timeout)
943 {
944 	struct cnx_mgr *cm_ctx;
945 
946 	cm_ctx = cm_get_cm_ctx(vdev);
947 	if (!cm_ctx)
948 		return;
949 
950 	cm_ctx->connect_timeout = max_connect_timeout;
951 }
952 
953 QDF_STATUS
954 cm_fill_disconnect_resp_from_cm_id(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id,
955 				   struct wlan_cm_discon_rsp *resp)
956 {
957 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
958 	struct cm_req *cm_req;
959 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
960 
961 	if (prefix != DISCONNECT_REQ_PREFIX)
962 		return QDF_STATUS_E_INVAL;
963 
964 	cm_req_lock_acquire(cm_ctx);
965 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
966 	while (cur_node) {
967 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
968 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
969 
970 		if (cm_req->cm_id == cm_id) {
971 			resp->req.cm_id = cm_id;
972 			resp->req.req = cm_req->discon_req.req;
973 			cm_req_lock_release(cm_ctx);
974 			return QDF_STATUS_SUCCESS;
975 		}
976 
977 		cur_node = next_node;
978 		next_node = NULL;
979 	}
980 	cm_req_lock_release(cm_ctx);
981 
982 	return QDF_STATUS_E_FAILURE;
983 }
984 
985 void cm_inform_bcn_probe(struct cnx_mgr *cm_ctx, uint8_t *bcn_probe,
986 			 uint32_t len, qdf_freq_t freq, int32_t rssi,
987 			 wlan_cm_id cm_id)
988 {
989 	qdf_nbuf_t buf;
990 	struct wlan_objmgr_pdev *pdev;
991 	uint8_t *data, i, vdev_id;
992 	struct mgmt_rx_event_params rx_param = {0};
993 	struct wlan_frame_hdr *hdr;
994 	enum mgmt_frame_type frm_type = MGMT_BEACON;
995 
996 	vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
997 	if (!bcn_probe || !len || (len < sizeof(*hdr))) {
998 		mlme_err(CM_PREFIX_FMT "bcn_probe is null or invalid len %d",
999 			 CM_PREFIX_REF(vdev_id, cm_id), len);
1000 		return;
1001 	}
1002 
1003 	pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
1004 	if (!pdev) {
1005 		mlme_err(CM_PREFIX_FMT "Failed to find pdev",
1006 			 CM_PREFIX_REF(vdev_id, cm_id));
1007 		return;
1008 	}
1009 
1010 	hdr = (struct wlan_frame_hdr *)bcn_probe;
1011 	if ((hdr->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_MASK) ==
1012 	    MGMT_SUBTYPE_PROBE_RESP)
1013 		frm_type = MGMT_PROBE_RESP;
1014 
1015 	rx_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1016 	rx_param.chan_freq = freq;
1017 	rx_param.rssi = rssi;
1018 
1019 	/* Set all per chain rssi as invalid */
1020 	for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++)
1021 		rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI;
1022 
1023 	buf = qdf_nbuf_alloc(NULL, qdf_roundup(len, 4), 0, 4, false);
1024 	if (!buf)
1025 		return;
1026 
1027 	qdf_nbuf_put_tail(buf, len);
1028 	qdf_nbuf_set_protocol(buf, ETH_P_CONTROL);
1029 
1030 	data = qdf_nbuf_data(buf);
1031 	qdf_mem_copy(data, bcn_probe, len);
1032 	/* buf will be freed by scan module in error or success case */
1033 	wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(pdev), buf,
1034 					    &rx_param, frm_type);
1035 }
1036 
1037 bool cm_is_vdev_connecting(struct wlan_objmgr_vdev *vdev)
1038 {
1039 	struct cnx_mgr *cm_ctx;
1040 	enum wlan_cm_sm_state state;
1041 
1042 	cm_ctx = cm_get_cm_ctx(vdev);
1043 	if (!cm_ctx)
1044 		return false;
1045 
1046 	state = cm_get_state(cm_ctx);
1047 
1048 	if (state == WLAN_CM_S_CONNECTING)
1049 		return true;
1050 
1051 	return false;
1052 }
1053 
1054 bool cm_is_vdev_connected(struct wlan_objmgr_vdev *vdev)
1055 {
1056 	struct cnx_mgr *cm_ctx;
1057 	enum wlan_cm_sm_state state;
1058 
1059 	cm_ctx = cm_get_cm_ctx(vdev);
1060 	if (!cm_ctx)
1061 		return false;
1062 
1063 	state = cm_get_state(cm_ctx);
1064 
1065 	if (state == WLAN_CM_S_CONNECTED)
1066 		return true;
1067 
1068 	return false;
1069 }
1070 
1071 bool cm_is_vdev_active(struct wlan_objmgr_vdev *vdev)
1072 {
1073 	struct cnx_mgr *cm_ctx;
1074 	enum wlan_cm_sm_state state;
1075 
1076 	cm_ctx = cm_get_cm_ctx(vdev);
1077 	if (!cm_ctx)
1078 		return false;
1079 
1080 	state = cm_get_state(cm_ctx);
1081 
1082 	if (state == WLAN_CM_S_CONNECTED || state == WLAN_CM_S_ROAMING)
1083 		return true;
1084 
1085 	return false;
1086 }
1087 
1088 bool cm_is_vdev_disconnecting(struct wlan_objmgr_vdev *vdev)
1089 {
1090 	struct cnx_mgr *cm_ctx;
1091 	enum wlan_cm_sm_state state;
1092 
1093 	cm_ctx = cm_get_cm_ctx(vdev);
1094 	if (!cm_ctx)
1095 		return false;
1096 
1097 	state = cm_get_state(cm_ctx);
1098 
1099 	if (state == WLAN_CM_S_DISCONNECTING)
1100 		return true;
1101 
1102 	return false;
1103 }
1104 
1105 bool cm_is_vdev_disconnected(struct wlan_objmgr_vdev *vdev)
1106 {
1107 	struct cnx_mgr *cm_ctx;
1108 	enum wlan_cm_sm_state state;
1109 
1110 	cm_ctx = cm_get_cm_ctx(vdev);
1111 	if (!cm_ctx)
1112 		return true;
1113 
1114 	state = cm_get_state(cm_ctx);
1115 
1116 	if (state == WLAN_CM_S_INIT)
1117 		return true;
1118 
1119 	return false;
1120 }
1121 
1122 bool cm_is_vdev_roaming(struct wlan_objmgr_vdev *vdev)
1123 {
1124 	struct cnx_mgr *cm_ctx;
1125 	enum wlan_cm_sm_state state;
1126 
1127 	cm_ctx = cm_get_cm_ctx(vdev);
1128 	if (!cm_ctx)
1129 		return false;
1130 
1131 	state = cm_get_state(cm_ctx);
1132 
1133 	if (state == WLAN_CM_S_ROAMING)
1134 		return true;
1135 
1136 	return false;
1137 }
1138 
1139 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
1140 bool cm_is_vdev_roam_started(struct wlan_objmgr_vdev *vdev)
1141 {
1142 	struct cnx_mgr *cm_ctx;
1143 	enum wlan_cm_sm_state state;
1144 	enum wlan_cm_sm_state sub_state;
1145 
1146 	cm_ctx = cm_get_cm_ctx(vdev);
1147 	if (!cm_ctx)
1148 		return false;
1149 
1150 	state = cm_get_state(cm_ctx);
1151 	sub_state = cm_get_sub_state(cm_ctx);
1152 	if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_ROAM_STARTED)
1153 		return true;
1154 
1155 	return false;
1156 }
1157 
1158 bool cm_is_vdev_roam_sync_inprogress(struct wlan_objmgr_vdev *vdev)
1159 {
1160 	struct cnx_mgr *cm_ctx;
1161 	enum wlan_cm_sm_state state;
1162 	enum wlan_cm_sm_state sub_state;
1163 
1164 	cm_ctx = cm_get_cm_ctx(vdev);
1165 	if (!cm_ctx)
1166 		return false;
1167 
1168 	state = cm_get_state(cm_ctx);
1169 	sub_state = cm_get_sub_state(cm_ctx);
1170 	if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_ROAM_SYNC)
1171 		return true;
1172 
1173 	return false;
1174 }
1175 #endif
1176 
1177 #ifdef WLAN_FEATURE_HOST_ROAM
1178 bool cm_is_vdev_roam_preauth_state(struct wlan_objmgr_vdev *vdev)
1179 {
1180 	struct cnx_mgr *cm_ctx;
1181 	enum wlan_cm_sm_state state;
1182 	enum wlan_cm_sm_state sub_state;
1183 
1184 	cm_ctx = cm_get_cm_ctx(vdev);
1185 	if (!cm_ctx)
1186 		return false;
1187 
1188 	state = cm_get_state(cm_ctx);
1189 	sub_state = cm_get_sub_state(cm_ctx);
1190 	if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_PREAUTH)
1191 		return true;
1192 
1193 	return false;
1194 }
1195 
1196 bool cm_is_vdev_roam_reassoc_state(struct wlan_objmgr_vdev *vdev)
1197 {
1198 	struct cnx_mgr *cm_ctx;
1199 	enum wlan_cm_sm_state state;
1200 	enum wlan_cm_sm_state sub_state;
1201 
1202 	cm_ctx = cm_get_cm_ctx(vdev);
1203 	if (!cm_ctx)
1204 		return false;
1205 
1206 	state = cm_get_state(cm_ctx);
1207 	sub_state = cm_get_sub_state(cm_ctx);
1208 	if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_REASSOC)
1209 		return true;
1210 
1211 	return false;
1212 }
1213 #endif
1214 
1215 enum wlan_cm_active_request_type
1216 cm_get_active_req_type(struct wlan_objmgr_vdev *vdev)
1217 {
1218 	struct cnx_mgr *cm_ctx;
1219 	wlan_cm_id cm_id;
1220 	uint32_t active_req_prefix = 0;
1221 
1222 	cm_ctx = cm_get_cm_ctx(vdev);
1223 	if (!cm_ctx)
1224 		return CM_NONE;
1225 
1226 	cm_id = cm_ctx->active_cm_id;
1227 
1228 	if (cm_id != CM_ID_INVALID)
1229 		active_req_prefix = CM_ID_GET_PREFIX(cm_id);
1230 
1231 	if (active_req_prefix == CONNECT_REQ_PREFIX)
1232 		return CM_CONNECT_ACTIVE;
1233 	else if (active_req_prefix == DISCONNECT_REQ_PREFIX)
1234 		return CM_DISCONNECT_ACTIVE;
1235 	else if (active_req_prefix == ROAM_REQ_PREFIX)
1236 		return CM_ROAM_ACTIVE;
1237 	else
1238 		return CM_NONE;
1239 }
1240 
1241 #ifdef WLAN_FEATURE_11BE_MLO
1242 static inline
1243 void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req,
1244 			       struct wlan_cm_vdev_connect_req *connect_req)
1245 {
1246 	if (req->ml_parnter_info.num_partner_links)
1247 		qdf_mem_copy(&connect_req->ml_parnter_info,
1248 			     &req->ml_parnter_info,
1249 			     sizeof(struct mlo_partner_info));
1250 }
1251 #else
1252 static inline
1253 void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req,
1254 			     struct wlan_cm_vdev_connect_req *connect_req)
1255 {
1256 }
1257 #endif
1258 
1259 bool cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev,
1260 			       struct wlan_cm_vdev_connect_req *req)
1261 {
1262 	struct cnx_mgr *cm_ctx;
1263 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1264 	struct cm_req *cm_req = NULL;
1265 	bool status = false;
1266 	uint32_t cm_id_prefix;
1267 
1268 	cm_ctx = cm_get_cm_ctx(vdev);
1269 	if (!cm_ctx)
1270 		return status;
1271 
1272 	cm_req_lock_acquire(cm_ctx);
1273 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
1274 	while (cur_node) {
1275 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
1276 
1277 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
1278 		cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id));
1279 
1280 		if (cm_req->cm_id == cm_ctx->active_cm_id &&
1281 		    cm_id_prefix == CONNECT_REQ_PREFIX) {
1282 			req->vdev_id = wlan_vdev_get_id(vdev);
1283 			req->cm_id = cm_req->connect_req.cm_id;
1284 			req->bss =  cm_req->connect_req.cur_candidate;
1285 			req->is_wps_connection =
1286 				cm_req->connect_req.req.is_wps_connection;
1287 			req->is_osen_connection =
1288 				cm_req->connect_req.req.is_osen_connection;
1289 			req->is_non_assoc_link = cm_req->connect_req.req.is_non_assoc_link;
1290 			cm_fill_ml_partner_info(&cm_req->connect_req.req, req);
1291 			status = true;
1292 			cm_req_lock_release(cm_ctx);
1293 			return status;
1294 		}
1295 
1296 		cur_node = next_node;
1297 		next_node = NULL;
1298 	}
1299 	cm_req_lock_release(cm_ctx);
1300 
1301 	return status;
1302 }
1303 
1304 bool cm_get_active_disconnect_req(struct wlan_objmgr_vdev *vdev,
1305 				  struct wlan_cm_vdev_discon_req *req)
1306 {
1307 	struct cnx_mgr *cm_ctx;
1308 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1309 	struct cm_req *cm_req = NULL;
1310 	bool status = false;
1311 	uint32_t cm_id_prefix;
1312 
1313 	cm_ctx = cm_get_cm_ctx(vdev);
1314 	if (!cm_ctx)
1315 		return status;
1316 
1317 	cm_req_lock_acquire(cm_ctx);
1318 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
1319 	while (cur_node) {
1320 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
1321 
1322 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
1323 		cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id));
1324 
1325 		if (cm_req->cm_id == cm_ctx->active_cm_id &&
1326 		    cm_id_prefix == DISCONNECT_REQ_PREFIX) {
1327 			req->cm_id = cm_req->cm_id;
1328 			req->req.vdev_id = wlan_vdev_get_id(vdev);
1329 			req->req.source = cm_req->discon_req.req.source;
1330 			req->req.reason_code =
1331 					cm_req->discon_req.req.reason_code;
1332 			req->req.bssid = cm_req->discon_req.req.bssid;
1333 			req->req.is_no_disassoc_disconnect =
1334 				cm_req->discon_req.req.is_no_disassoc_disconnect;
1335 			status = true;
1336 			cm_req_lock_release(cm_ctx);
1337 			return status;
1338 		}
1339 
1340 		cur_node = next_node;
1341 		next_node = NULL;
1342 	}
1343 	cm_req_lock_release(cm_ctx);
1344 
1345 	return status;
1346 }
1347 
1348 struct cm_req *cm_get_req_by_scan_id(struct cnx_mgr *cm_ctx,
1349 				     wlan_scan_id scan_id)
1350 {
1351 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1352 	struct cm_req *cm_req;
1353 
1354 	cm_req_lock_acquire(cm_ctx);
1355 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
1356 	while (cur_node) {
1357 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
1358 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
1359 
1360 		if (cm_req->connect_req.scan_id == scan_id) {
1361 			cm_req_lock_release(cm_ctx);
1362 			return cm_req;
1363 		}
1364 
1365 		cur_node = next_node;
1366 		next_node = NULL;
1367 	}
1368 	cm_req_lock_release(cm_ctx);
1369 
1370 	return NULL;
1371 }
1372 
1373 wlan_cm_id cm_get_cm_id_by_scan_id(struct cnx_mgr *cm_ctx,
1374 				   wlan_scan_id scan_id)
1375 {
1376 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1377 	struct cm_req *cm_req;
1378 
1379 	cm_req_lock_acquire(cm_ctx);
1380 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
1381 	while (cur_node) {
1382 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
1383 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
1384 
1385 		if (cm_req->connect_req.scan_id == scan_id) {
1386 			cm_req_lock_release(cm_ctx);
1387 			return cm_req->cm_id;
1388 		}
1389 
1390 		cur_node = next_node;
1391 		next_node = NULL;
1392 	}
1393 	cm_req_lock_release(cm_ctx);
1394 
1395 	return CM_ID_INVALID;
1396 }
1397 
1398 #ifdef WLAN_POLICY_MGR_ENABLE
1399 static void
1400 cm_get_pcl_chan_weigtage_for_sta(struct wlan_objmgr_pdev *pdev,
1401 				 struct pcl_freq_weight_list *pcl_lst)
1402 {
1403 	enum QDF_OPMODE opmode = QDF_STA_MODE;
1404 	enum policy_mgr_con_mode pm_mode;
1405 	uint32_t num_entries = 0;
1406 	QDF_STATUS status;
1407 
1408 	if (!pcl_lst)
1409 		return;
1410 
1411 	if (policy_mgr_map_concurrency_mode(&opmode, &pm_mode)) {
1412 		status = policy_mgr_get_pcl(wlan_pdev_get_psoc(pdev), pm_mode,
1413 					    pcl_lst->pcl_freq_list,
1414 					    &num_entries,
1415 					    pcl_lst->pcl_weight_list,
1416 					    NUM_CHANNELS);
1417 		if (QDF_IS_STATUS_ERROR(status))
1418 			return;
1419 		pcl_lst->num_of_pcl_channels = num_entries;
1420 	}
1421 }
1422 
1423 void cm_calculate_scores(struct cnx_mgr *cm_ctx,
1424 			 struct wlan_objmgr_pdev *pdev,
1425 			 struct scan_filter *filter, qdf_list_t *list)
1426 {
1427 	struct pcl_freq_weight_list *pcl_lst = NULL;
1428 
1429 	if (!filter->num_of_bssid) {
1430 		pcl_lst = qdf_mem_malloc(sizeof(*pcl_lst));
1431 		cm_get_pcl_chan_weigtage_for_sta(pdev, pcl_lst);
1432 		if (pcl_lst && !pcl_lst->num_of_pcl_channels) {
1433 			qdf_mem_free(pcl_lst);
1434 			pcl_lst = NULL;
1435 		}
1436 	}
1437 	wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint);
1438 	if (pcl_lst)
1439 		qdf_mem_free(pcl_lst);
1440 }
1441 #else
1442 inline
1443 void cm_calculate_scores(struct cnx_mgr *cm_ctx,
1444 			 struct wlan_objmgr_pdev *pdev,
1445 			 struct scan_filter *filter, qdf_list_t *list)
1446 {
1447 	wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint);
1448 
1449 	/*
1450 	 * Custom sorting if enabled
1451 	 */
1452 	if (cm_ctx && cm_ctx->cm_candidate_list_custom_sort)
1453 		cm_ctx->cm_candidate_list_custom_sort(cm_ctx->vdev, list);
1454 }
1455 #endif
1456 
1457 #ifdef SM_ENG_HIST_ENABLE
1458 static const char *cm_id_to_string(wlan_cm_id cm_id)
1459 {
1460 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
1461 
1462 	switch (prefix) {
1463 	case CONNECT_REQ_PREFIX:
1464 		return "CONNECT";
1465 	case DISCONNECT_REQ_PREFIX:
1466 		return "DISCONNECT";
1467 	case ROAM_REQ_PREFIX:
1468 		return "ROAM";
1469 	default:
1470 		return "INVALID";
1471 	}
1472 }
1473 
1474 void cm_req_history_add(struct cnx_mgr *cm_ctx,
1475 			struct cm_req *cm_req)
1476 {
1477 	struct cm_req_history *history = &cm_ctx->req_history;
1478 	struct cm_req_history_info *data;
1479 
1480 	qdf_spin_lock_bh(&history->cm_req_hist_lock);
1481 	data = &history->data[history->index];
1482 	history->index++;
1483 	history->index %= CM_REQ_HISTORY_SIZE;
1484 
1485 	qdf_mem_zero(data, sizeof(*data));
1486 	data->cm_id = cm_req->cm_id;
1487 	data->add_time = qdf_get_log_timestamp();
1488 	data->add_cm_state = cm_get_state(cm_ctx);
1489 	qdf_spin_unlock_bh(&history->cm_req_hist_lock);
1490 }
1491 
1492 void cm_req_history_del(struct cnx_mgr *cm_ctx,
1493 			struct cm_req *cm_req,
1494 			enum cm_req_del_type del_type)
1495 {
1496 	uint8_t i, idx;
1497 	struct cm_req_history_info *data;
1498 	struct cm_req_history *history = &cm_ctx->req_history;
1499 
1500 	qdf_spin_lock_bh(&history->cm_req_hist_lock);
1501 	for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) {
1502 		if (history->index < i)
1503 			idx = CM_REQ_HISTORY_SIZE + history->index - i;
1504 		else
1505 			idx = history->index - i;
1506 
1507 		data = &history->data[idx];
1508 		if (data->cm_id == cm_req->cm_id) {
1509 			data->del_time = qdf_get_log_timestamp();
1510 			data->del_cm_state = cm_get_state(cm_ctx);
1511 			data->del_type = del_type;
1512 			break;
1513 		}
1514 
1515 		if (!data->cm_id)
1516 			break;
1517 	}
1518 	qdf_spin_unlock_bh(&history->cm_req_hist_lock);
1519 }
1520 
1521 void cm_req_history_init(struct cnx_mgr *cm_ctx)
1522 {
1523 	qdf_spinlock_create(&cm_ctx->req_history.cm_req_hist_lock);
1524 	qdf_mem_zero(&cm_ctx->req_history, sizeof(struct cm_req_history));
1525 }
1526 
1527 void cm_req_history_deinit(struct cnx_mgr *cm_ctx)
1528 {
1529 	qdf_spinlock_destroy(&cm_ctx->req_history.cm_req_hist_lock);
1530 }
1531 
1532 static inline void cm_req_history_print_entry(uint16_t idx,
1533 					      struct cm_req_history_info *data)
1534 {
1535 	if (!data->cm_id)
1536 		return;
1537 
1538 	mlme_nofl_err("    |%6u | 0x%016llx | 0x%016llx |%12s | 0x%08x |%15s |%15s |%8u",
1539 		      idx, data->add_time, data->del_time,
1540 		      cm_id_to_string(data->cm_id), data->cm_id,
1541 		      cm_sm_info[data->add_cm_state].name,
1542 		      cm_sm_info[data->del_cm_state].name,
1543 		      data->del_type);
1544 }
1545 
1546 void cm_req_history_print(struct cnx_mgr *cm_ctx)
1547 {
1548 	struct cm_req_history *history = &cm_ctx->req_history;
1549 	uint8_t i, idx;
1550 
1551 	mlme_nofl_err("CM Request history is as below");
1552 	mlme_nofl_err("|%6s |%19s |%19s |%12s |%11s |%15s |%15s |%8s",
1553 		      "Index", "Add Time", "Del Time", "Req type",
1554 		      "Cm Id", "Add State", "Del State", "Del Type");
1555 
1556 	qdf_spin_lock_bh(&history->cm_req_hist_lock);
1557 	for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) {
1558 		idx = (history->index + i) % CM_REQ_HISTORY_SIZE;
1559 		cm_req_history_print_entry(idx, &history->data[idx]);
1560 	}
1561 	qdf_spin_unlock_bh(&history->cm_req_hist_lock);
1562 }
1563 #endif
1564 
1565 #ifndef CONN_MGR_ADV_FEATURE
1566 void cm_set_candidate_advance_filter_cb(
1567 		struct wlan_objmgr_vdev *vdev,
1568 		void (*filter_fun)(struct wlan_objmgr_vdev *vdev,
1569 				   struct scan_filter *filter))
1570 {
1571 	struct cnx_mgr *cm_ctx;
1572 
1573 	cm_ctx = cm_get_cm_ctx(vdev);
1574 	if (!cm_ctx)
1575 		return;
1576 
1577 	cm_ctx->cm_candidate_advance_filter = filter_fun;
1578 }
1579 
1580 void cm_set_candidate_custom_sort_cb(
1581 		struct wlan_objmgr_vdev *vdev,
1582 		void (*sort_fun)(struct wlan_objmgr_vdev *vdev,
1583 				 qdf_list_t *list))
1584 {
1585 	struct cnx_mgr *cm_ctx;
1586 
1587 	cm_ctx = cm_get_cm_ctx(vdev);
1588 	if (!cm_ctx)
1589 		return;
1590 
1591 	cm_ctx->cm_candidate_list_custom_sort = sort_fun;
1592 }
1593 #endif
1594