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