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