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