xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_util.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
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 							      false);
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_is_connect_req_reassoc(struct wlan_cm_connect_req *req)
1260 {
1261 	if (!qdf_is_macaddr_zero(&req->prev_bssid) &&
1262 	    (!qdf_is_macaddr_zero(&req->bssid) ||
1263 	     !qdf_is_macaddr_zero(&req->bssid_hint)) &&
1264 	    (req->chan_freq || req->chan_freq_hint))
1265 		return true;
1266 
1267 	return false;
1268 }
1269 
1270 bool cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev,
1271 			       struct wlan_cm_vdev_connect_req *req)
1272 {
1273 	struct cnx_mgr *cm_ctx;
1274 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1275 	struct cm_req *cm_req = NULL;
1276 	bool status = false;
1277 	uint32_t cm_id_prefix;
1278 
1279 	cm_ctx = cm_get_cm_ctx(vdev);
1280 	if (!cm_ctx)
1281 		return status;
1282 
1283 	cm_req_lock_acquire(cm_ctx);
1284 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
1285 	while (cur_node) {
1286 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
1287 
1288 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
1289 		cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id));
1290 
1291 		if (cm_req->cm_id == cm_ctx->active_cm_id &&
1292 		    cm_id_prefix == CONNECT_REQ_PREFIX) {
1293 			req->vdev_id = wlan_vdev_get_id(vdev);
1294 			req->cm_id = cm_req->connect_req.cm_id;
1295 			req->bss =  cm_req->connect_req.cur_candidate;
1296 			req->is_wps_connection =
1297 				cm_req->connect_req.req.is_wps_connection;
1298 			req->is_osen_connection =
1299 				cm_req->connect_req.req.is_osen_connection;
1300 			req->is_non_assoc_link = cm_req->connect_req.req.is_non_assoc_link;
1301 			cm_fill_ml_partner_info(&cm_req->connect_req.req, req);
1302 			status = true;
1303 			cm_req_lock_release(cm_ctx);
1304 			return status;
1305 		}
1306 
1307 		cur_node = next_node;
1308 		next_node = NULL;
1309 	}
1310 	cm_req_lock_release(cm_ctx);
1311 
1312 	return status;
1313 }
1314 
1315 bool cm_get_active_disconnect_req(struct wlan_objmgr_vdev *vdev,
1316 				  struct wlan_cm_vdev_discon_req *req)
1317 {
1318 	struct cnx_mgr *cm_ctx;
1319 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1320 	struct cm_req *cm_req = NULL;
1321 	bool status = false;
1322 	uint32_t cm_id_prefix;
1323 
1324 	cm_ctx = cm_get_cm_ctx(vdev);
1325 	if (!cm_ctx)
1326 		return status;
1327 
1328 	cm_req_lock_acquire(cm_ctx);
1329 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
1330 	while (cur_node) {
1331 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
1332 
1333 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
1334 		cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id));
1335 
1336 		if (cm_req->cm_id == cm_ctx->active_cm_id &&
1337 		    cm_id_prefix == DISCONNECT_REQ_PREFIX) {
1338 			req->cm_id = cm_req->cm_id;
1339 			req->req.vdev_id = wlan_vdev_get_id(vdev);
1340 			req->req.source = cm_req->discon_req.req.source;
1341 			req->req.reason_code =
1342 					cm_req->discon_req.req.reason_code;
1343 			req->req.bssid = cm_req->discon_req.req.bssid;
1344 			req->req.is_no_disassoc_disconnect =
1345 				cm_req->discon_req.req.is_no_disassoc_disconnect;
1346 			status = true;
1347 			cm_req_lock_release(cm_ctx);
1348 			return status;
1349 		}
1350 
1351 		cur_node = next_node;
1352 		next_node = NULL;
1353 	}
1354 	cm_req_lock_release(cm_ctx);
1355 
1356 	return status;
1357 }
1358 
1359 struct cm_req *cm_get_req_by_scan_id(struct cnx_mgr *cm_ctx,
1360 				     wlan_scan_id scan_id)
1361 {
1362 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1363 	struct cm_req *cm_req;
1364 
1365 	cm_req_lock_acquire(cm_ctx);
1366 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
1367 	while (cur_node) {
1368 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
1369 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
1370 
1371 		if (cm_req->connect_req.scan_id == scan_id) {
1372 			cm_req_lock_release(cm_ctx);
1373 			return cm_req;
1374 		}
1375 
1376 		cur_node = next_node;
1377 		next_node = NULL;
1378 	}
1379 	cm_req_lock_release(cm_ctx);
1380 
1381 	return NULL;
1382 }
1383 
1384 wlan_cm_id cm_get_cm_id_by_scan_id(struct cnx_mgr *cm_ctx,
1385 				   wlan_scan_id scan_id)
1386 {
1387 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1388 	struct cm_req *cm_req;
1389 
1390 	cm_req_lock_acquire(cm_ctx);
1391 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
1392 	while (cur_node) {
1393 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
1394 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
1395 
1396 		if (cm_req->connect_req.scan_id == scan_id) {
1397 			cm_req_lock_release(cm_ctx);
1398 			return cm_req->cm_id;
1399 		}
1400 
1401 		cur_node = next_node;
1402 		next_node = NULL;
1403 	}
1404 	cm_req_lock_release(cm_ctx);
1405 
1406 	return CM_ID_INVALID;
1407 }
1408 
1409 #ifdef WLAN_POLICY_MGR_ENABLE
1410 static void
1411 cm_get_pcl_chan_weigtage_for_sta(struct wlan_objmgr_pdev *pdev,
1412 				 struct pcl_freq_weight_list *pcl_lst)
1413 {
1414 	enum QDF_OPMODE opmode = QDF_STA_MODE;
1415 	enum policy_mgr_con_mode pm_mode;
1416 	uint32_t num_entries = 0;
1417 	QDF_STATUS status;
1418 
1419 	if (!pcl_lst)
1420 		return;
1421 
1422 	if (policy_mgr_map_concurrency_mode(&opmode, &pm_mode)) {
1423 		status = policy_mgr_get_pcl(wlan_pdev_get_psoc(pdev), pm_mode,
1424 					    pcl_lst->pcl_freq_list,
1425 					    &num_entries,
1426 					    pcl_lst->pcl_weight_list,
1427 					    NUM_CHANNELS);
1428 		if (QDF_IS_STATUS_ERROR(status))
1429 			return;
1430 		pcl_lst->num_of_pcl_channels = num_entries;
1431 	}
1432 }
1433 
1434 void cm_calculate_scores(struct cnx_mgr *cm_ctx,
1435 			 struct wlan_objmgr_pdev *pdev,
1436 			 struct scan_filter *filter, qdf_list_t *list)
1437 {
1438 	struct pcl_freq_weight_list *pcl_lst = NULL;
1439 
1440 	if (!filter->num_of_bssid) {
1441 		pcl_lst = qdf_mem_malloc(sizeof(*pcl_lst));
1442 		cm_get_pcl_chan_weigtage_for_sta(pdev, pcl_lst);
1443 		if (pcl_lst && !pcl_lst->num_of_pcl_channels) {
1444 			qdf_mem_free(pcl_lst);
1445 			pcl_lst = NULL;
1446 		}
1447 	}
1448 	wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint);
1449 	if (pcl_lst)
1450 		qdf_mem_free(pcl_lst);
1451 }
1452 #else
1453 inline
1454 void cm_calculate_scores(struct cnx_mgr *cm_ctx,
1455 			 struct wlan_objmgr_pdev *pdev,
1456 			 struct scan_filter *filter, qdf_list_t *list)
1457 {
1458 	wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint);
1459 
1460 	/*
1461 	 * Custom sorting if enabled
1462 	 */
1463 	if (cm_ctx && cm_ctx->cm_candidate_list_custom_sort)
1464 		cm_ctx->cm_candidate_list_custom_sort(cm_ctx->vdev, list);
1465 }
1466 #endif
1467 
1468 #ifdef SM_ENG_HIST_ENABLE
1469 static const char *cm_id_to_string(wlan_cm_id cm_id)
1470 {
1471 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
1472 
1473 	switch (prefix) {
1474 	case CONNECT_REQ_PREFIX:
1475 		return "CONNECT";
1476 	case DISCONNECT_REQ_PREFIX:
1477 		return "DISCONNECT";
1478 	case ROAM_REQ_PREFIX:
1479 		return "ROAM";
1480 	default:
1481 		return "INVALID";
1482 	}
1483 }
1484 
1485 void cm_req_history_add(struct cnx_mgr *cm_ctx,
1486 			struct cm_req *cm_req)
1487 {
1488 	struct cm_req_history *history = &cm_ctx->req_history;
1489 	struct cm_req_history_info *data;
1490 
1491 	qdf_spin_lock_bh(&history->cm_req_hist_lock);
1492 	data = &history->data[history->index];
1493 	history->index++;
1494 	history->index %= CM_REQ_HISTORY_SIZE;
1495 
1496 	qdf_mem_zero(data, sizeof(*data));
1497 	data->cm_id = cm_req->cm_id;
1498 	data->add_time = qdf_get_log_timestamp();
1499 	data->add_cm_state = cm_get_state(cm_ctx);
1500 	qdf_spin_unlock_bh(&history->cm_req_hist_lock);
1501 }
1502 
1503 void cm_req_history_del(struct cnx_mgr *cm_ctx,
1504 			struct cm_req *cm_req,
1505 			enum cm_req_del_type del_type)
1506 {
1507 	uint8_t i, idx;
1508 	struct cm_req_history_info *data;
1509 	struct cm_req_history *history = &cm_ctx->req_history;
1510 
1511 	qdf_spin_lock_bh(&history->cm_req_hist_lock);
1512 	for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) {
1513 		if (history->index < i)
1514 			idx = CM_REQ_HISTORY_SIZE + history->index - i;
1515 		else
1516 			idx = history->index - i;
1517 
1518 		data = &history->data[idx];
1519 		if (data->cm_id == cm_req->cm_id) {
1520 			data->del_time = qdf_get_log_timestamp();
1521 			data->del_cm_state = cm_get_state(cm_ctx);
1522 			data->del_type = del_type;
1523 			break;
1524 		}
1525 
1526 		if (!data->cm_id)
1527 			break;
1528 	}
1529 	qdf_spin_unlock_bh(&history->cm_req_hist_lock);
1530 }
1531 
1532 void cm_req_history_init(struct cnx_mgr *cm_ctx)
1533 {
1534 	qdf_spinlock_create(&cm_ctx->req_history.cm_req_hist_lock);
1535 	qdf_mem_zero(&cm_ctx->req_history, sizeof(struct cm_req_history));
1536 }
1537 
1538 void cm_req_history_deinit(struct cnx_mgr *cm_ctx)
1539 {
1540 	qdf_spinlock_destroy(&cm_ctx->req_history.cm_req_hist_lock);
1541 }
1542 
1543 static inline void cm_req_history_print_entry(uint16_t idx,
1544 					      struct cm_req_history_info *data)
1545 {
1546 	if (!data->cm_id)
1547 		return;
1548 
1549 	mlme_nofl_err("    |%6u | 0x%016llx | 0x%016llx |%12s | 0x%08x |%15s |%15s |%8u",
1550 		      idx, data->add_time, data->del_time,
1551 		      cm_id_to_string(data->cm_id), data->cm_id,
1552 		      cm_sm_info[data->add_cm_state].name,
1553 		      cm_sm_info[data->del_cm_state].name,
1554 		      data->del_type);
1555 }
1556 
1557 void cm_req_history_print(struct cnx_mgr *cm_ctx)
1558 {
1559 	struct cm_req_history *history = &cm_ctx->req_history;
1560 	uint8_t i, idx;
1561 
1562 	mlme_nofl_err("CM Request history is as below");
1563 	mlme_nofl_err("|%6s |%19s |%19s |%12s |%11s |%15s |%15s |%8s",
1564 		      "Index", "Add Time", "Del Time", "Req type",
1565 		      "Cm Id", "Add State", "Del State", "Del Type");
1566 
1567 	qdf_spin_lock_bh(&history->cm_req_hist_lock);
1568 	for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) {
1569 		idx = (history->index + i) % CM_REQ_HISTORY_SIZE;
1570 		cm_req_history_print_entry(idx, &history->data[idx]);
1571 	}
1572 	qdf_spin_unlock_bh(&history->cm_req_hist_lock);
1573 }
1574 #endif
1575 
1576 #ifndef CONN_MGR_ADV_FEATURE
1577 void cm_set_candidate_advance_filter_cb(
1578 		struct wlan_objmgr_vdev *vdev,
1579 		void (*filter_fun)(struct wlan_objmgr_vdev *vdev,
1580 				   struct scan_filter *filter))
1581 {
1582 	struct cnx_mgr *cm_ctx;
1583 
1584 	cm_ctx = cm_get_cm_ctx(vdev);
1585 	if (!cm_ctx)
1586 		return;
1587 
1588 	cm_ctx->cm_candidate_advance_filter = filter_fun;
1589 }
1590 
1591 void cm_set_candidate_custom_sort_cb(
1592 		struct wlan_objmgr_vdev *vdev,
1593 		void (*sort_fun)(struct wlan_objmgr_vdev *vdev,
1594 				 qdf_list_t *list))
1595 {
1596 	struct cnx_mgr *cm_ctx;
1597 
1598 	cm_ctx = cm_get_cm_ctx(vdev);
1599 	if (!cm_ctx)
1600 		return;
1601 
1602 	cm_ctx->cm_candidate_list_custom_sort = sort_fun;
1603 }
1604 #endif
1605