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