xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_main.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2012-2015, 2020-2021, 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 init/deinit specific apis of connection manager
19  */
20 
21 #include "wlan_cm_main.h"
22 #include "wlan_cm_roam.h"
23 #include "wlan_cm_main_api.h"
24 #include "wlan_scan_api.h"
25 
26 #ifdef WLAN_CM_USE_SPINLOCK
27 /**
28  * cm_req_lock_create - Create CM req SM mutex/spinlock
29  * @cm_ctx:  connection manager ctx
30  *
31  * Creates CM SM mutex/spinlock
32  *
33  * Return: void
34  */
35 static inline void
36 cm_req_lock_create(struct cnx_mgr *cm_ctx)
37 {
38 	qdf_spinlock_create(&cm_ctx->cm_req_lock);
39 }
40 
41 /**
42  * cm_req_lock_destroy - Destroy CM SM mutex/spinlock
43  * @cm_ctx:  connection manager ctx
44  *
45  * Destroy CM SM mutex/spinlock
46  *
47  * Return: void
48  */
49 static inline void
50 cm_req_lock_destroy(struct cnx_mgr *cm_ctx)
51 {
52 	qdf_spinlock_destroy(&cm_ctx->cm_req_lock);
53 }
54 #else
55 static inline void
56 cm_req_lock_create(struct cnx_mgr *cm_ctx)
57 {
58 	qdf_mutex_create(&cm_ctx->cm_req_lock);
59 }
60 
61 static inline void
62 cm_req_lock_destroy(struct cnx_mgr *cm_ctx)
63 {
64 	qdf_mutex_destroy(&cm_ctx->cm_req_lock);
65 }
66 #endif /* WLAN_CM_USE_SPINLOCK */
67 
68 QDF_STATUS wlan_cm_init(struct vdev_mlme_obj *vdev_mlme)
69 {
70 	struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev;
71 	enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev);
72 	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
73 	QDF_STATUS status;
74 
75 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
76 		return QDF_STATUS_SUCCESS;
77 
78 	vdev_mlme->cnx_mgr_ctx = qdf_mem_malloc(sizeof(struct cnx_mgr));
79 	if (!vdev_mlme->cnx_mgr_ctx)
80 		return QDF_STATUS_E_NOMEM;
81 
82 	vdev_mlme->cnx_mgr_ctx->vdev = vdev;
83 	status = mlme_cm_ext_hdl_create(vdev,
84 					&vdev_mlme->cnx_mgr_ctx->ext_cm_ptr);
85 	if (QDF_IS_STATUS_ERROR(status)) {
86 		qdf_mem_free(vdev_mlme->cnx_mgr_ctx);
87 		vdev_mlme->cnx_mgr_ctx = NULL;
88 		return status;
89 	}
90 
91 	status = cm_sm_create(vdev_mlme->cnx_mgr_ctx);
92 	if (QDF_IS_STATUS_ERROR(status)) {
93 		mlme_cm_ext_hdl_destroy(vdev,
94 					vdev_mlme->cnx_mgr_ctx->ext_cm_ptr);
95 		vdev_mlme->cnx_mgr_ctx->ext_cm_ptr = NULL;
96 		qdf_mem_free(vdev_mlme->cnx_mgr_ctx);
97 		vdev_mlme->cnx_mgr_ctx = NULL;
98 		return status;
99 	}
100 	vdev_mlme->cnx_mgr_ctx->max_connect_attempts =
101 					CM_MAX_CONNECT_ATTEMPTS;
102 	vdev_mlme->cnx_mgr_ctx->connect_timeout =
103 					CM_MAX_PER_CANDIDATE_CONNECT_TIMEOUT;
104 	qdf_list_create(&vdev_mlme->cnx_mgr_ctx->req_list, CM_MAX_REQ);
105 	cm_req_lock_create(vdev_mlme->cnx_mgr_ctx);
106 
107 	vdev_mlme->cnx_mgr_ctx->scan_requester_id =
108 		wlan_scan_register_requester(psoc,
109 					     "CM",
110 					     wlan_cm_scan_cb,
111 					     vdev_mlme->cnx_mgr_ctx);
112 	qdf_event_create(&vdev_mlme->cnx_mgr_ctx->disconnect_complete);
113 	cm_req_history_init(vdev_mlme->cnx_mgr_ctx);
114 
115 	return QDF_STATUS_SUCCESS;
116 }
117 
118 static void cm_deinit_req_list(struct cnx_mgr *cm_ctx)
119 {
120 	uint32_t prefix;
121 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
122 	struct cm_req *cm_req = NULL;
123 
124 	/*
125 	 * flush unhandled req from the list, this should not happen if SM is
126 	 * handled properly, but in cases of active command timeout
127 	 * (which needs be debugged and avoided anyway) if VDEV/PEER SM
128 	 * is not able to handle the req it may send out of sync command and
129 	 * thus resulting in a unhandled request. Thus to avoid memleak flush
130 	 * all unhandled req before destroying the list.
131 	 */
132 	cm_req_lock_acquire(cm_ctx);
133 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
134 	while (cur_node) {
135 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
136 
137 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
138 		prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
139 		qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
140 		mlme_info(CM_PREFIX_FMT "flush prefix %x",
141 			  CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
142 					cm_req->cm_id), prefix);
143 		if (prefix == CONNECT_REQ_PREFIX) {
144 			cm_ctx->connect_count--;
145 			cm_free_connect_req_mem(&cm_req->connect_req);
146 		} else if (prefix == ROAM_REQ_PREFIX) {
147 			cm_free_roam_req_mem(&cm_req->roam_req);
148 		} else if (prefix == DISCONNECT_REQ_PREFIX) {
149 			cm_ctx->disconnect_count--;
150 		}
151 		qdf_mem_free(cm_req);
152 
153 		cur_node = next_node;
154 		next_node = NULL;
155 		cm_req = NULL;
156 	}
157 	cm_req_lock_release(cm_ctx);
158 
159 	cm_req_lock_destroy(cm_ctx);
160 	qdf_list_destroy(&cm_ctx->req_list);
161 }
162 
163 QDF_STATUS wlan_cm_deinit(struct vdev_mlme_obj *vdev_mlme)
164 {
165 	struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev;
166 	enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev);
167 	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
168 	wlan_scan_requester scan_requester_id;
169 	struct cnx_mgr *cm_ctx;
170 
171 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
172 		return QDF_STATUS_SUCCESS;
173 
174 	cm_ctx = vdev_mlme->cnx_mgr_ctx;
175 	cm_req_history_deinit(cm_ctx);
176 	qdf_event_destroy(&cm_ctx->disconnect_complete);
177 	scan_requester_id = cm_ctx->scan_requester_id;
178 	wlan_scan_unregister_requester(psoc, scan_requester_id);
179 
180 	cm_deinit_req_list(cm_ctx);
181 	cm_sm_destroy(cm_ctx);
182 	mlme_cm_ext_hdl_destroy(vdev, cm_ctx->ext_cm_ptr);
183 	cm_ctx->ext_cm_ptr = NULL;
184 	qdf_mem_free(cm_ctx);
185 	vdev_mlme->cnx_mgr_ctx = NULL;
186 
187 	return QDF_STATUS_SUCCESS;
188 }
189