xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_util.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
1 /*
2  * Copyright (c) 2012-2015, 2020, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * DOC: Implements general util apis of connection manager
19  */
20 
21 #include "wlan_cm_main_api.h"
22 #include "wlan_scan_api.h"
23 #include "wlan_cm_public_struct.h"
24 #include "wlan_serialization_api.h"
25 
26 static uint32_t cm_get_prefix_for_cm_id(enum wlan_cm_source source) {
27 	switch (source) {
28 	case CM_OSIF_CONNECT:
29 	case CM_ROAMING:
30 		return CONNECT_REQ_PREFIX;
31 	default:
32 		return DISCONNECT_REQ_PREFIX;
33 	}
34 }
35 
36 wlan_cm_id cm_get_cm_id(struct cnx_mgr *cm_ctx, enum wlan_cm_source source)
37 {
38 	wlan_cm_id cmd_id;
39 	uint32_t prefix;
40 
41 	prefix = cm_get_prefix_for_cm_id(source);
42 
43 	cmd_id = qdf_atomic_inc_return(&cm_ctx->global_cmd_id);
44 	cmd_id = (cmd_id & CM_ID_MASK);
45 	cmd_id = (cmd_id | prefix);
46 
47 	return cmd_id;
48 }
49 
50 struct cnx_mgr *cm_get_cm_ctx_fl(struct wlan_objmgr_vdev *vdev,
51 				 const char *func, uint32_t line)
52 {
53 	struct vdev_mlme_obj *vdev_mlme;
54 	struct cnx_mgr *cm_ctx = NULL;
55 
56 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
57 	if (vdev_mlme)
58 		cm_ctx = vdev_mlme->cnx_mgr_ctx;
59 
60 	if (!cm_ctx)
61 		mlme_nofl_err("%s:%u: vdev %d cm_ctx is NULL", func, line,
62 			      wlan_vdev_get_id(vdev));
63 
64 	return cm_ctx;
65 }
66 
67 void cm_reset_active_cm_id(struct wlan_objmgr_vdev *vdev, wlan_cm_id cm_id)
68 {
69 	struct cnx_mgr *cm_ctx;
70 
71 	cm_ctx = cm_get_cm_ctx(vdev);
72 	if (!cm_ctx)
73 		return;
74 
75 	/* Reset active cm id if cm id match */
76 	if (cm_ctx->active_cm_id == cm_id)
77 		cm_ctx->active_cm_id = CM_ID_INVALID;
78 }
79 
80 
81 #ifdef WLAN_CM_USE_SPINLOCK
82 /**
83  * cm_req_lock_acquire - acquire CM SM mutex/spinlock
84  * @cm_ctx:  connection manager ctx
85  *
86  * acquire CM SM mutex/spinlock
87  *
88  * return: void
89  */
90 static inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
91 {
92 	qdf_spinlock_acquire(&cm_ctx->cm_req_lock);
93 }
94 
95 /**
96  * cm_req_lock_release - release CM SM mutex/spinlock
97  * @cm_ctx:  connection manager ctx
98  *
99  * release CM SM mutex/spinlock
100  *
101  * return: void
102  */
103 static inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
104 {
105 	qdf_spinlock_release(&cm_ctx->cm_req_lock);
106 }
107 #else
108 static inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
109 {
110 	qdf_mutex_acquire(&cm_ctx->cm_req_lock);
111 }
112 
113 static inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
114 {
115 	qdf_mutex_release(&cm_ctx->cm_req_lock);
116 }
117 #endif /* WLAN_CM_USE_SPINLOCK */
118 
119 #ifdef CRYPTO_SET_KEY_CONVERGED
120 QDF_STATUS cm_set_key(struct cnx_mgr *cm_ctx, bool unicast,
121 		      uint8_t key_idx, struct qdf_mac_addr *bssid)
122 {
123 	enum wlan_crypto_cipher_type cipher;
124 	struct wlan_crypto_key *crypto_key;
125 	uint8_t wep_key_idx = 0;
126 
127 	cipher = wlan_crypto_get_cipher(cm_ctx->vdev, unicast, key_idx);
128 	if (IS_WEP_CIPHER(cipher)) {
129 		wep_key_idx = wlan_crypto_get_default_key_idx(cm_ctx->vdev,
130 							      !unicast);
131 		crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_key_idx);
132 		qdf_mem_copy(crypto_key->macaddr, bssid->bytes,
133 			     QDF_MAC_ADDR_SIZE);
134 	} else {
135 		crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_idx);
136 	}
137 
138 	return wlan_crypto_set_key_req(cm_ctx->vdev, crypto_key, (unicast ?
139 				       WLAN_CRYPTO_KEY_TYPE_UNICAST :
140 				       WLAN_CRYPTO_KEY_TYPE_GROUP));
141 }
142 #endif
143 
144 #ifdef CONN_MGR_ADV_FEATURE
145 void cm_store_wep_key(struct cnx_mgr *cm_ctx,
146 		      struct wlan_cm_connect_crypto_info *crypto,
147 		      wlan_cm_id cm_id)
148 {
149 	struct wlan_crypto_key *crypto_key = NULL;
150 	QDF_STATUS status;
151 	enum wlan_crypto_cipher_type cipher_type;
152 	struct wlan_cm_wep_key_params *wep_keys;
153 
154 	if (!(crypto->ciphers_pairwise & (1 << WLAN_CRYPTO_CIPHER_WEP_40 |
155 					  1 << WLAN_CRYPTO_CIPHER_WEP_104)))
156 		return;
157 
158 	if (crypto->ciphers_pairwise & 1 << WLAN_CRYPTO_CIPHER_WEP_40)
159 		cipher_type = WLAN_CRYPTO_CIPHER_WEP_40;
160 	else
161 		cipher_type = WLAN_CRYPTO_CIPHER_WEP_104;
162 
163 	wep_keys = &crypto->wep_keys;
164 	status = wlan_crypto_validate_key_params(cipher_type,
165 						 wep_keys->key_idx,
166 						 wep_keys->key_len,
167 						 wep_keys->seq_len);
168 	if (QDF_IS_STATUS_ERROR(status)) {
169 		mlme_err(CM_PREFIX_FMT "Invalid key params",
170 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
171 		return;
172 	}
173 
174 	crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_keys->key_idx);
175 	if (!crypto_key) {
176 		crypto_key = qdf_mem_malloc(sizeof(*crypto_key));
177 		if (!crypto_key)
178 			return;
179 
180 		status = wlan_crypto_save_key(cm_ctx->vdev, wep_keys->key_idx,
181 					      crypto_key);
182 		if (QDF_IS_STATUS_ERROR(status)) {
183 			mlme_err(CM_PREFIX_FMT "Failed to save key",
184 				 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
185 					       cm_id));
186 			qdf_mem_free(crypto_key);
187 			return;
188 		}
189 	}
190 	qdf_mem_zero(crypto_key, sizeof(*crypto_key));
191 	crypto_key->cipher_type = cipher_type;
192 	crypto_key->keylen = wep_keys->key_len;
193 	crypto_key->keyix = wep_keys->key_idx;
194 	qdf_mem_copy(&crypto_key->keyval[0], wep_keys->key, wep_keys->key_len);
195 	qdf_mem_copy(&crypto_key->keyrsc[0], wep_keys->seq, wep_keys->seq_len);
196 	mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, seq_len %d",
197 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
198 		   crypto_key->cipher_type, wep_keys->key_len,
199 		   wep_keys->seq_len);
200 }
201 #endif
202 
203 #ifdef WLAN_FEATURE_FILS_SK
204 void cm_store_fils_key(struct cnx_mgr *cm_ctx, bool unicast,
205 		       uint8_t key_id, uint16_t key_length,
206 		       uint8_t *key, struct qdf_mac_addr *bssid,
207 		       wlan_cm_id cm_id)
208 {
209 	struct wlan_crypto_key *crypto_key = NULL;
210 	QDF_STATUS status;
211 	uint8_t i;
212 	int32_t cipher;
213 	enum wlan_crypto_cipher_type cipher_type = WLAN_CRYPTO_CIPHER_NONE;
214 
215 	if (unicast)
216 		cipher = wlan_crypto_get_param(cm_ctx->vdev,
217 					       WLAN_CRYPTO_PARAM_UCAST_CIPHER);
218 	else
219 		cipher = wlan_crypto_get_param(cm_ctx->vdev,
220 					       WLAN_CRYPTO_PARAM_MCAST_CIPHER);
221 
222 	for (i = 0; i <= WLAN_CRYPTO_CIPHER_MAX; i++) {
223 		if (QDF_HAS_PARAM(cipher, i)) {
224 			cipher_type = i;
225 			break;
226 		}
227 	}
228 	crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_id);
229 	if (!crypto_key) {
230 		crypto_key = qdf_mem_malloc(sizeof(*crypto_key));
231 		if (!crypto_key)
232 			return;
233 		status = wlan_crypto_save_key(cm_ctx->vdev, key_id, crypto_key);
234 		if (QDF_IS_STATUS_ERROR(status)) {
235 			mlme_err(CM_PREFIX_FMT "Failed to save key",
236 				 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
237 					       cm_id));
238 			qdf_mem_free(crypto_key);
239 			return;
240 		}
241 	}
242 	qdf_mem_zero(crypto_key, sizeof(*crypto_key));
243 	crypto_key->cipher_type = cipher_type;
244 	crypto_key->keylen = key_length;
245 	crypto_key->keyix = key_id;
246 	qdf_mem_copy(&crypto_key->keyval[0], key, key_length);
247 	qdf_mem_copy(crypto_key->macaddr, bssid->bytes, QDF_MAC_ADDR_SIZE);
248 	mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, key_id %d mac:" QDF_MAC_ADDR_FMT,
249 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
250 		   crypto_key->cipher_type, crypto_key->keylen,
251 		   crypto_key->keyix, QDF_MAC_ADDR_REF(crypto_key->macaddr));
252 }
253 #endif
254 
255 bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
256 {
257 	qdf_list_node_t *cur_node = NULL;
258 	struct cm_req *cm_req;
259 	bool match = false;
260 	wlan_cm_id head_cm_id = 0;
261 
262 	if (!cm_id)
263 		return false;
264 
265 	cm_req_lock_acquire(cm_ctx);
266 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
267 	if (!cur_node)
268 		goto exit;
269 
270 	cm_req = qdf_container_of(cur_node, struct cm_req, node);
271 	head_cm_id = cm_req->cm_id;
272 	if (head_cm_id == *cm_id)
273 		match = true;
274 
275 exit:
276 	cm_req_lock_release(cm_ctx);
277 	if (!match)
278 		mlme_info("head_cm_id 0x%x didn't match the given cm_id 0x%x",
279 			  head_cm_id, *cm_id);
280 
281 	return match;
282 }
283 
284 bool cm_check_scanid_match_list_head(struct cnx_mgr *cm_ctx,
285 				     wlan_scan_id *scan_id)
286 {
287 	qdf_list_node_t *cur_node = NULL;
288 	struct cm_req *cm_req;
289 	bool match = false;
290 	wlan_cm_id head_scan_id = 0;
291 	uint32_t prefix = 0;
292 
293 	if (!scan_id)
294 		return false;
295 
296 	cm_req_lock_acquire(cm_ctx);
297 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
298 	if (!cur_node)
299 		goto exit;
300 
301 	cm_req = qdf_container_of(cur_node, struct cm_req, node);
302 	prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
303 	/* Check only if head is connect req */
304 	if (prefix != CONNECT_REQ_PREFIX)
305 		goto exit;
306 	head_scan_id = cm_req->connect_req.scan_id;
307 	if (head_scan_id == *scan_id)
308 		match = true;
309 
310 exit:
311 	cm_req_lock_release(cm_ctx);
312 	if (!match)
313 		mlme_info("head_scan_id 0x%x didn't match the given scan_id 0x%x prefix 0x%x",
314 			  head_scan_id, *scan_id, prefix);
315 
316 	return match;
317 }
318 
319 struct cm_req *cm_get_req_by_cm_id_fl(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id,
320 				      const char *func, uint32_t line)
321 {
322 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
323 	struct cm_req * cm_req;
324 
325 	cm_req_lock_acquire(cm_ctx);
326 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
327 	while (cur_node) {
328 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
329 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
330 
331 		if (cm_req->cm_id == cm_id) {
332 			cm_req_lock_release(cm_ctx);
333 			return cm_req;
334 		}
335 
336 		cur_node = next_node;
337 		next_node = NULL;
338 	}
339 	cm_req_lock_release(cm_ctx);
340 
341 	mlme_nofl_info("%s:%u: cm req not found for cm id 0x%x", func,
342 		       line, cm_id);
343 
344 	return NULL;
345 }
346 
347 /**
348  * cm_fill_connect_resp_from_req() - Fill connect resp from connect request
349  * @resp: cm connect response
350  * @cm_req: cm request
351  *
352  * Context: Can be called from APIs holding cm request list lock
353  *
354  * Return: void
355  */
356 static void
357 cm_fill_connect_resp_from_req(struct wlan_cm_connect_resp *resp,
358 			      struct cm_req *cm_req)
359 {
360 	struct scan_cache_node *candidate;
361 	struct wlan_cm_connect_req *req;
362 
363 	req = &cm_req->connect_req.req;
364 	candidate = cm_req->connect_req.cur_candidate;
365 	if (candidate)
366 		qdf_copy_macaddr(&resp->bssid, &candidate->entry->bssid);
367 	else if (!qdf_is_macaddr_zero(&req->bssid))
368 		qdf_copy_macaddr(&resp->bssid, &req->bssid);
369 	else
370 		qdf_copy_macaddr(&resp->bssid, &req->bssid_hint);
371 
372 	if (candidate)
373 		resp->freq = candidate->entry->channel.chan_freq;
374 	else
375 		resp->freq = req->chan_freq;
376 
377 	resp->ssid = req->ssid;
378 }
379 
380 /**
381  * cm_handle_connect_flush() - Fill fail connect resp from req and indicate
382  * same to osif
383  * @cm_ctx: connection manager context
384  * @cm_req: cm request
385  *
386  * Context: Can be called from APIs holding cm request list lock
387  *
388  * Return: void
389  */
390 static void
391 cm_handle_connect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
392 {
393 	struct wlan_cm_connect_resp *resp;
394 
395 	resp = qdf_mem_malloc(sizeof(*resp));
396 	if (!resp)
397 		return;
398 
399 	resp->connect_status = QDF_STATUS_E_FAILURE;
400 	resp->cm_id = cm_req->cm_id;
401 	resp->vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
402 	resp->reason = CM_ABORT_DUE_TO_NEW_REQ_RECVD;
403 
404 	/* Get bssid and ssid and freq for the cm id from the req list */
405 	cm_fill_connect_resp_from_req(resp, cm_req);
406 
407 	mlme_cm_osif_connect_complete(cm_ctx->vdev, resp);
408 	qdf_mem_free(resp);
409 }
410 
411 /**
412  * cm_handle_disconnect_flush() - Fill disconnect resp from req and indicate
413  * same to osif
414  * @cm_ctx: connection manager context
415  * @cm_req: cm request
416  *
417  * Context: Can be called from APIs holding cm request list lock
418  *
419  * Return: void
420  */
421 static void
422 cm_handle_disconnect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
423 {
424 	struct wlan_cm_discon_rsp resp;
425 
426 	qdf_mem_zero(&resp, sizeof(resp));
427 	resp.req.cm_id = cm_req->cm_id;
428 	resp.req.req = cm_req->discon_req.req;
429 
430 	mlme_cm_osif_disconnect_complete(cm_ctx->vdev, &resp);
431 }
432 
433 static void cm_remove_cmd_from_serialization(struct cnx_mgr *cm_ctx,
434 					     wlan_cm_id cm_id)
435 {
436 	struct wlan_serialization_queued_cmd_info cmd_info;
437 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
438 
439 	qdf_mem_zero(&cmd_info, sizeof(cmd_info));
440 	cmd_info.cmd_id = cm_id;
441 	cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
442 
443 	if (prefix == CONNECT_REQ_PREFIX)
444 		cmd_info.cmd_type = WLAN_SER_CMD_VDEV_CONNECT;
445 	else
446 		cmd_info.cmd_type = WLAN_SER_CMD_VDEV_DISCONNECT;
447 
448 	cmd_info.vdev = cm_ctx->vdev;
449 
450 	if (cm_id == cm_ctx->active_cm_id) {
451 		mlme_debug(CM_PREFIX_FMT "Remove from active",
452 			   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
453 					 cm_id));
454 		cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
455 		wlan_serialization_remove_cmd(&cmd_info);
456 	} else {
457 		mlme_debug(CM_PREFIX_FMT "Remove from pending",
458 			   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
459 					 cm_id));
460 		cmd_info.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE;
461 		wlan_serialization_cancel_request(&cmd_info);
462 	}
463 }
464 
465 void
466 cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix,
467 			 bool only_failed_req)
468 {
469 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
470 	struct cm_req *cm_req;
471 	uint32_t req_prefix;
472 
473 	cm_req_lock_acquire(cm_ctx);
474 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
475 	while (cur_node) {
476 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
477 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
478 
479 		req_prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
480 
481 		/* Only remove the pending requests matching the flush prefix */
482 		if (req_prefix != prefix ||
483 		    cm_req->cm_id == cm_ctx->active_cm_id)
484 			goto next;
485 
486 		/* If only_failed_req is set flush only failed req */
487 		if (only_failed_req && !cm_req->failed_req)
488 			goto next;
489 
490 		if (req_prefix == CONNECT_REQ_PREFIX) {
491 			cm_handle_connect_flush(cm_ctx, cm_req);
492 			cm_ctx->connect_count--;
493 			cm_free_connect_req_mem(&cm_req->connect_req);
494 		} else {
495 			cm_handle_disconnect_flush(cm_ctx, cm_req);
496 			cm_ctx->disconnect_count--;
497 		}
498 		mlme_debug(CM_PREFIX_FMT,
499 			   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
500 					 cm_req->cm_id));
501 		cm_remove_cmd_from_serialization(cm_ctx, cm_req->cm_id);
502 		qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
503 		qdf_mem_free(cm_req);
504 next:
505 		cur_node = next_node;
506 		next_node = NULL;
507 	}
508 
509 	cm_req_lock_release(cm_ctx);
510 }
511 
512 QDF_STATUS
513 cm_fill_bss_info_in_connect_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
514 					 wlan_cm_id cm_id,
515 					 struct wlan_cm_connect_resp *resp)
516 {
517 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
518 	struct cm_req *cm_req;
519 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
520 
521 	if (prefix != CONNECT_REQ_PREFIX)
522 		return QDF_STATUS_E_INVAL;
523 
524 	cm_req_lock_acquire(cm_ctx);
525 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
526 	while (cur_node) {
527 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
528 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
529 
530 		if (cm_req->cm_id == cm_id) {
531 			cm_fill_connect_resp_from_req(resp, cm_req);
532 			cm_req_lock_release(cm_ctx);
533 			return QDF_STATUS_SUCCESS;
534 		}
535 
536 		cur_node = next_node;
537 		next_node = NULL;
538 	}
539 	cm_req_lock_release(cm_ctx);
540 
541 	return QDF_STATUS_E_FAILURE;
542 }
543 
544 #if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
545 bool cm_is_cm_id_current_candidate_single_pmk(struct cnx_mgr *cm_ctx,
546 					      wlan_cm_id cm_id)
547 {
548 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
549 	struct cm_req *cm_req;
550 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
551 	struct scan_cache_node *candidate;
552 	bool is_single_pmk = false;
553 
554 	if (prefix != CONNECT_REQ_PREFIX)
555 		return is_single_pmk;
556 
557 	cm_req_lock_acquire(cm_ctx);
558 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
559 	while (cur_node) {
560 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
561 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
562 
563 		if (cm_req->cm_id == cm_id) {
564 			candidate = cm_req->connect_req.cur_candidate;
565 			if (candidate &&
566 			    util_scan_entry_single_pmk(candidate->entry))
567 				is_single_pmk = true;
568 			break;
569 		}
570 
571 		cur_node = next_node;
572 		next_node = NULL;
573 	}
574 	cm_req_lock_release(cm_ctx);
575 
576 	return is_single_pmk;
577 }
578 #endif
579 
580 QDF_STATUS cm_add_req_to_list_and_indicate_osif(struct cnx_mgr *cm_ctx,
581 						struct cm_req *cm_req,
582 						enum wlan_cm_source source)
583 {
584 	uint32_t prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
585 
586 	cm_req_lock_acquire(cm_ctx);
587 	if (qdf_list_size(&cm_ctx->req_list) >= CM_MAX_REQ) {
588 		cm_req_lock_release(cm_ctx);
589 		mlme_err(CM_PREFIX_FMT "List full size %d",
590 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
591 				       cm_req->cm_id),
592 			 qdf_list_size(&cm_ctx->req_list));
593 		return QDF_STATUS_E_FAILURE;
594 	}
595 
596 	qdf_list_insert_front(&cm_ctx->req_list, &cm_req->node);
597 	if (prefix == CONNECT_REQ_PREFIX)
598 		cm_ctx->connect_count++;
599 	else
600 		cm_ctx->disconnect_count++;
601 	cm_req_lock_release(cm_ctx);
602 	mlme_debug(CM_PREFIX_FMT,
603 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
604 				 cm_req->cm_id));
605 
606 	mlme_cm_osif_update_id_and_src(cm_ctx->vdev, source, cm_req->cm_id);
607 
608 	return QDF_STATUS_SUCCESS;
609 }
610 
611 static void cm_zero_and_free_memory(uint8_t *ptr, uint32_t len)
612 {
613 	if (!ptr)
614 		return;
615 
616 	qdf_mem_zero(ptr, len);
617 	qdf_mem_free(ptr);
618 }
619 
620 void cm_free_connect_req_mem(struct cm_connect_req *connect_req)
621 {
622 	struct wlan_cm_connect_req *req;
623 
624 	req = &connect_req->req;
625 
626 	if (connect_req->candidate_list)
627 		wlan_scan_purge_results(connect_req->candidate_list);
628 
629 	cm_zero_and_free_memory(req->assoc_ie.ptr, req->assoc_ie.len);
630 	cm_zero_and_free_memory(req->scan_ie.ptr, req->scan_ie.len);
631 
632 	cm_zero_and_free_memory(req->crypto.wep_keys.key,
633 				req->crypto.wep_keys.key_len);
634 	cm_zero_and_free_memory(req->crypto.wep_keys.seq,
635 				req->crypto.wep_keys.seq_len);
636 
637 	qdf_mem_zero(connect_req, sizeof(*connect_req));
638 }
639 
640 QDF_STATUS
641 cm_delete_req_from_list(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
642 {
643 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
644 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
645 	struct cm_req *cm_req = NULL;
646 
647 	cm_req_lock_acquire(cm_ctx);
648 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
649 	while (cur_node) {
650 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
651 
652 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
653 		if (cm_req->cm_id == cm_id)
654 			break;
655 
656 		cur_node = next_node;
657 		next_node = NULL;
658 		cm_req = NULL;
659 	}
660 
661 	if (!cm_req) {
662 		cm_req_lock_release(cm_ctx);
663 		mlme_err(CM_PREFIX_FMT " req not found",
664 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
665 		return QDF_STATUS_E_FAILURE;
666 	}
667 
668 	qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
669 	if (prefix == CONNECT_REQ_PREFIX) {
670 		cm_ctx->connect_count--;
671 		cm_free_connect_req_mem(&cm_req->connect_req);
672 	} else {
673 		cm_ctx->disconnect_count--;
674 	}
675 	mlme_debug(CM_PREFIX_FMT,
676 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
677 				 cm_req->cm_id));
678 
679 	qdf_mem_free(cm_req);
680 	cm_req_lock_release(cm_ctx);
681 
682 	return QDF_STATUS_SUCCESS;
683 }
684 
685 void cm_remove_cmd(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
686 {
687 	struct wlan_objmgr_psoc *psoc;
688 	QDF_STATUS status;
689 
690 	psoc = wlan_vdev_get_psoc(cm_ctx->vdev);
691 	if (!psoc) {
692 		mlme_err(CM_PREFIX_FMT "Failed to find psoc",
693 			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
694 		return;
695 	}
696 
697 	status = cm_delete_req_from_list(cm_ctx, cm_id);
698 	if (QDF_IS_STATUS_ERROR(status))
699 		return;
700 
701 	cm_remove_cmd_from_serialization(cm_ctx, cm_id);
702 }
703 
704 void cm_vdev_scan_cancel(struct wlan_objmgr_pdev *pdev,
705 			 struct wlan_objmgr_vdev *vdev)
706 {
707 	struct scan_cancel_request *req;
708 	QDF_STATUS status;
709 
710 	req = qdf_mem_malloc(sizeof(*req));
711 	if (!req)
712 		return;
713 
714 	req->vdev = vdev;
715 	req->cancel_req.scan_id = INVAL_SCAN_ID;
716 	req->cancel_req.vdev_id = wlan_vdev_get_id(vdev);
717 	req->cancel_req.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
718 	req->cancel_req.req_type = WLAN_SCAN_CANCEL_VDEV_ALL;
719 
720 	status = wlan_scan_cancel(req);
721 	/* In success/failure case wlan_scan_cancel free the req memory */
722 	if (QDF_IS_STATUS_ERROR(status))
723 		mlme_err("vdev %d cancel scan request failed",
724 			 wlan_vdev_get_id(vdev));
725 }
726 
727 void cm_set_max_connect_attempts(struct wlan_objmgr_vdev *vdev,
728 				 uint8_t max_connect_attempts)
729 {
730 	struct cnx_mgr *cm_ctx;
731 
732 	cm_ctx = cm_get_cm_ctx(vdev);
733 	if (!cm_ctx)
734 		return;
735 
736 	cm_ctx->max_connect_attempts =
737 		QDF_MIN(max_connect_attempts, CM_MAX_CONNECT_ATTEMPTS);
738 	mlme_debug("vdev %d max connect attempts set to %d, requested %d",
739 		   wlan_vdev_get_id(vdev),
740 		   cm_ctx->max_connect_attempts, max_connect_attempts);
741 }
742 
743 QDF_STATUS
744 cm_fill_disconnect_resp_from_cm_id(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id,
745 				   struct wlan_cm_discon_rsp *resp)
746 {
747 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
748 	struct cm_req *cm_req;
749 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
750 
751 	if (prefix != DISCONNECT_REQ_PREFIX)
752 		return QDF_STATUS_E_INVAL;
753 
754 	cm_req_lock_acquire(cm_ctx);
755 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
756 	while (cur_node) {
757 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
758 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
759 
760 		if (cm_req->cm_id == cm_id) {
761 			resp->req.cm_id = cm_id;
762 			resp->req.req = cm_req->discon_req.req;
763 			cm_req_lock_release(cm_ctx);
764 			return QDF_STATUS_SUCCESS;
765 		}
766 
767 		cur_node = next_node;
768 		next_node = NULL;
769 	}
770 	cm_req_lock_release(cm_ctx);
771 
772 	return QDF_STATUS_E_FAILURE;
773 }
774 
775 void cm_inform_bcn_probe(struct cnx_mgr *cm_ctx, uint8_t *bcn_probe,
776 			 uint32_t len, qdf_freq_t freq, int32_t rssi,
777 			 wlan_cm_id cm_id)
778 {
779 	qdf_nbuf_t buf;
780 	struct wlan_objmgr_pdev *pdev;
781 	uint8_t *data, i, vdev_id;
782 	struct mgmt_rx_event_params rx_param = {0};
783 	struct wlan_frame_hdr *hdr;
784 	enum mgmt_frame_type frm_type = MGMT_BEACON;
785 
786 	vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
787 	if (!bcn_probe || !len || (len < sizeof(*hdr))) {
788 		mlme_err(CM_PREFIX_FMT "bcn_probe is null or invalid len %d",
789 			 CM_PREFIX_REF(vdev_id, cm_id), len);
790 		return;
791 	}
792 
793 	pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
794 	if (!pdev) {
795 		mlme_err(CM_PREFIX_FMT "Failed to find pdev",
796 			 CM_PREFIX_REF(vdev_id, cm_id));
797 		return;
798 	}
799 
800 	hdr = (struct wlan_frame_hdr *)bcn_probe;
801 	if ((hdr->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_MASK) ==
802 	    MGMT_SUBTYPE_PROBE_RESP)
803 		frm_type = MGMT_PROBE_RESP;
804 
805 	rx_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
806 	rx_param.chan_freq = freq;
807 	rx_param.rssi = rssi;
808 
809 	/* Set all per chain rssi as invalid */
810 	for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++)
811 		rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI;
812 
813 	buf = qdf_nbuf_alloc(NULL, qdf_roundup(len, 4), 0, 4, false);
814 	if (!buf)
815 		return;
816 
817 	qdf_nbuf_put_tail(buf, len);
818 	qdf_nbuf_set_protocol(buf, ETH_P_CONTROL);
819 
820 	data = qdf_nbuf_data(buf);
821 	qdf_mem_copy(data, bcn_probe, len);
822 	/* buf will be freed by scan module in error or success case */
823 	wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(pdev), buf,
824 					    &rx_param, frm_type);
825 }
826 
827 bool cm_is_vdev_connecting(struct wlan_objmgr_vdev *vdev)
828 {
829 	struct cnx_mgr *cm_ctx;
830 	enum wlan_cm_sm_state state;
831 
832 	cm_ctx = cm_get_cm_ctx(vdev);
833 	if (!cm_ctx)
834 		return false;
835 
836 	state = cm_get_state(cm_ctx);
837 
838 	if (state == WLAN_CM_S_CONNECTING)
839 		return true;
840 
841 	return false;
842 }
843 
844 bool cm_is_vdev_connected(struct wlan_objmgr_vdev *vdev)
845 {
846 	struct cnx_mgr *cm_ctx;
847 	enum wlan_cm_sm_state state;
848 
849 	cm_ctx = cm_get_cm_ctx(vdev);
850 	if (!cm_ctx)
851 		return false;
852 
853 	state = cm_get_state(cm_ctx);
854 
855 	if (state == WLAN_CM_S_CONNECTED)
856 		return true;
857 
858 	return false;
859 }
860 
861 bool cm_is_vdev_disconnecting(struct wlan_objmgr_vdev *vdev)
862 {
863 	struct cnx_mgr *cm_ctx;
864 	enum wlan_cm_sm_state state;
865 
866 	cm_ctx = cm_get_cm_ctx(vdev);
867 	if (!cm_ctx)
868 		return false;
869 
870 	state = cm_get_state(cm_ctx);
871 
872 	if (state == WLAN_CM_S_DISCONNECTING)
873 		return true;
874 
875 	return false;
876 }
877 
878 bool cm_is_vdev_disconnected(struct wlan_objmgr_vdev *vdev)
879 {
880 	struct cnx_mgr *cm_ctx;
881 	enum wlan_cm_sm_state state;
882 
883 	cm_ctx = cm_get_cm_ctx(vdev);
884 	if (!cm_ctx)
885 		return false;
886 
887 	state = cm_get_state(cm_ctx);
888 
889 	if (state == WLAN_CM_S_INIT)
890 		return true;
891 
892 	return false;
893 }
894 
895 bool cm_is_vdev_roaming(struct wlan_objmgr_vdev *vdev)
896 {
897 	struct cnx_mgr *cm_ctx;
898 	enum wlan_cm_sm_state state;
899 
900 	cm_ctx = cm_get_cm_ctx(vdev);
901 	if (!cm_ctx)
902 		return false;
903 
904 	state = cm_get_state(cm_ctx);
905 
906 	if (state == WLAN_CM_S_ROAMING)
907 		return true;
908 
909 	return false;
910 }
911 
912 struct cm_req *cm_get_req_by_scan_id(struct cnx_mgr *cm_ctx,
913 				     wlan_scan_id scan_id)
914 {
915 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
916 	struct cm_req *cm_req;
917 
918 	cm_req_lock_acquire(cm_ctx);
919 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
920 	while (cur_node) {
921 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
922 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
923 
924 		if (cm_req->connect_req.scan_id == scan_id) {
925 			cm_req_lock_release(cm_ctx);
926 			return cm_req;
927 		}
928 
929 		cur_node = next_node;
930 		next_node = NULL;
931 	}
932 	cm_req_lock_release(cm_ctx);
933 
934 	return NULL;
935 }
936 
937 wlan_cm_id cm_get_cm_id_by_scan_id(struct cnx_mgr *cm_ctx,
938 				   wlan_scan_id scan_id)
939 {
940 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
941 	struct cm_req *cm_req;
942 
943 	cm_req_lock_acquire(cm_ctx);
944 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
945 	while (cur_node) {
946 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
947 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
948 
949 		if (cm_req->connect_req.scan_id == scan_id) {
950 			cm_req_lock_release(cm_ctx);
951 			return cm_req->cm_id;
952 		}
953 
954 		cur_node = next_node;
955 		next_node = NULL;
956 	}
957 	cm_req_lock_release(cm_ctx);
958 
959 	return CM_ID_INVALID;
960 }
961 
962