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