xref: /wlan-driver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_main.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: Implements init/deinit specific apis of connection manager
20  */
21 
22 #include "wlan_cm_main.h"
23 #include "wlan_cm_roam.h"
24 #include "wlan_cm_main_api.h"
25 #include "wlan_scan_api.h"
26 #include "wlan_mlo_mgr_link_switch.h"
27 
28 #ifdef WLAN_CM_USE_SPINLOCK
29 /**
30  * cm_req_lock_create - Create CM req SM mutex/spinlock
31  * @cm_ctx:  connection manager ctx
32  *
33  * Creates CM SM mutex/spinlock
34  *
35  * Return: void
36  */
37 static inline void
cm_req_lock_create(struct cnx_mgr * cm_ctx)38 cm_req_lock_create(struct cnx_mgr *cm_ctx)
39 {
40 	qdf_spinlock_create(&cm_ctx->cm_req_lock);
41 }
42 
43 /**
44  * cm_req_lock_destroy - Destroy CM SM mutex/spinlock
45  * @cm_ctx:  connection manager ctx
46  *
47  * Destroy CM SM mutex/spinlock
48  *
49  * Return: void
50  */
51 static inline void
cm_req_lock_destroy(struct cnx_mgr * cm_ctx)52 cm_req_lock_destroy(struct cnx_mgr *cm_ctx)
53 {
54 	qdf_spinlock_destroy(&cm_ctx->cm_req_lock);
55 }
56 #else
57 static inline void
cm_req_lock_create(struct cnx_mgr * cm_ctx)58 cm_req_lock_create(struct cnx_mgr *cm_ctx)
59 {
60 	qdf_mutex_create(&cm_ctx->cm_req_lock);
61 }
62 
63 static inline void
cm_req_lock_destroy(struct cnx_mgr * cm_ctx)64 cm_req_lock_destroy(struct cnx_mgr *cm_ctx)
65 {
66 	qdf_mutex_destroy(&cm_ctx->cm_req_lock);
67 }
68 #endif /* WLAN_CM_USE_SPINLOCK */
69 
wlan_cm_init(struct vdev_mlme_obj * vdev_mlme)70 QDF_STATUS wlan_cm_init(struct vdev_mlme_obj *vdev_mlme)
71 {
72 	struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev;
73 	enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev);
74 	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
75 	QDF_STATUS status;
76 
77 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
78 		return QDF_STATUS_SUCCESS;
79 
80 	vdev_mlme->cnx_mgr_ctx = qdf_mem_malloc(sizeof(struct cnx_mgr));
81 	if (!vdev_mlme->cnx_mgr_ctx)
82 		return QDF_STATUS_E_NOMEM;
83 
84 	vdev_mlme->cnx_mgr_ctx->vdev = vdev;
85 	status = mlme_cm_ext_hdl_create(vdev,
86 					&vdev_mlme->cnx_mgr_ctx->ext_cm_ptr);
87 	if (QDF_IS_STATUS_ERROR(status)) {
88 		qdf_mem_free(vdev_mlme->cnx_mgr_ctx);
89 		vdev_mlme->cnx_mgr_ctx = NULL;
90 		return status;
91 	}
92 
93 	status = cm_sm_create(vdev_mlme->cnx_mgr_ctx);
94 	if (QDF_IS_STATUS_ERROR(status)) {
95 		mlme_cm_ext_hdl_destroy(vdev,
96 					vdev_mlme->cnx_mgr_ctx->ext_cm_ptr);
97 		vdev_mlme->cnx_mgr_ctx->ext_cm_ptr = NULL;
98 		qdf_mem_free(vdev_mlme->cnx_mgr_ctx);
99 		vdev_mlme->cnx_mgr_ctx = NULL;
100 		return status;
101 	}
102 	vdev_mlme->cnx_mgr_ctx->max_connect_attempts =
103 					CM_MAX_CONNECT_ATTEMPTS;
104 	vdev_mlme->cnx_mgr_ctx->connect_timeout =
105 					CM_MAX_PER_CANDIDATE_CONNECT_TIMEOUT;
106 	qdf_list_create(&vdev_mlme->cnx_mgr_ctx->req_list, CM_MAX_REQ);
107 	cm_req_lock_create(vdev_mlme->cnx_mgr_ctx);
108 
109 	vdev_mlme->cnx_mgr_ctx->scan_requester_id =
110 		wlan_scan_register_requester(psoc,
111 					     "CM",
112 					     wlan_cm_scan_cb,
113 					     vdev_mlme->cnx_mgr_ctx);
114 	qdf_event_create(&vdev_mlme->cnx_mgr_ctx->disconnect_complete);
115 	cm_req_history_init(vdev_mlme->cnx_mgr_ctx);
116 
117 	return QDF_STATUS_SUCCESS;
118 }
119 
cm_deinit_req_list(struct cnx_mgr * cm_ctx)120 static void cm_deinit_req_list(struct cnx_mgr *cm_ctx)
121 {
122 	uint32_t prefix;
123 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
124 	struct cm_req *cm_req = NULL;
125 
126 	/*
127 	 * flush unhandled req from the list, this should not happen if SM is
128 	 * handled properly, but in cases of active command timeout
129 	 * (which needs be debugged and avoided anyway) if VDEV/PEER SM
130 	 * is not able to handle the req it may send out of sync command and
131 	 * thus resulting in a unhandled request. Thus to avoid memleak flush
132 	 * all unhandled req before destroying the list.
133 	 */
134 	cm_req_lock_acquire(cm_ctx);
135 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
136 	while (cur_node) {
137 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
138 
139 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
140 		prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
141 		qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
142 		mlme_info(CM_PREFIX_FMT "flush prefix %x",
143 			  CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
144 					cm_req->cm_id), prefix);
145 		if (prefix == CONNECT_REQ_PREFIX) {
146 			cm_ctx->connect_count--;
147 			cm_free_connect_req_mem(&cm_req->connect_req);
148 		} else if (prefix == ROAM_REQ_PREFIX) {
149 			cm_free_roam_req_mem(&cm_req->roam_req);
150 		} else if (prefix == DISCONNECT_REQ_PREFIX) {
151 			cm_ctx->disconnect_count--;
152 		}
153 		qdf_mem_free(cm_req);
154 
155 		cur_node = next_node;
156 		next_node = NULL;
157 		cm_req = NULL;
158 	}
159 	cm_req_lock_release(cm_ctx);
160 
161 	cm_req_lock_destroy(cm_ctx);
162 	qdf_list_destroy(&cm_ctx->req_list);
163 }
164 
wlan_cm_deinit(struct vdev_mlme_obj * vdev_mlme)165 QDF_STATUS wlan_cm_deinit(struct vdev_mlme_obj *vdev_mlme)
166 {
167 	struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev;
168 	enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev);
169 	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
170 	wlan_scan_requester scan_requester_id;
171 	struct cnx_mgr *cm_ctx;
172 
173 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
174 		return QDF_STATUS_SUCCESS;
175 
176 	cm_ctx = vdev_mlme->cnx_mgr_ctx;
177 	cm_req_history_deinit(cm_ctx);
178 	qdf_event_destroy(&cm_ctx->disconnect_complete);
179 	scan_requester_id = cm_ctx->scan_requester_id;
180 	wlan_scan_unregister_requester(psoc, scan_requester_id);
181 
182 	cm_deinit_req_list(cm_ctx);
183 	cm_sm_destroy(cm_ctx);
184 	mlme_cm_ext_hdl_destroy(vdev, cm_ctx->ext_cm_ptr);
185 	cm_ctx->ext_cm_ptr = NULL;
186 	qdf_mem_free(cm_ctx);
187 	vdev_mlme->cnx_mgr_ctx = NULL;
188 
189 	return QDF_STATUS_SUCCESS;
190 }
191 
192 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
cm_standby_link_update_mlme_by_bssid(struct wlan_objmgr_vdev * vdev,uint32_t assoc_state,struct wlan_ssid ssid)193 void cm_standby_link_update_mlme_by_bssid(struct wlan_objmgr_vdev *vdev,
194 					  uint32_t assoc_state,
195 					  struct wlan_ssid ssid)
196 {
197 	struct mlo_link_info *link_info;
198 	uint8_t link_info_iter;
199 	struct mlme_info mlme_info;
200 	struct bss_info bss_info;
201 
202 	if (!wlan_vdev_mlme_is_assoc_sta_vdev(vdev))
203 		return;
204 
205 	link_info = mlo_mgr_get_ap_link(vdev);
206 	if (!link_info)
207 		return;
208 
209 	for (link_info_iter = 0; link_info_iter < 3; link_info_iter++) {
210 		if (qdf_is_macaddr_zero(&link_info->ap_link_addr))
211 			break;
212 
213 		if (link_info->vdev_id == WLAN_INVALID_VDEV_ID) {
214 			mlme_info.assoc_state = assoc_state;
215 			qdf_copy_macaddr(&bss_info.bssid,
216 					 &link_info->ap_link_addr);
217 			bss_info.freq = link_info->link_chan_info->ch_freq;
218 			bss_info.ssid.length = ssid.length;
219 			qdf_mem_copy(&bss_info.ssid.ssid, ssid.ssid,
220 				     bss_info.ssid.length);
221 
222 			wlan_scan_update_mlme_by_bssinfo(wlan_vdev_get_pdev(vdev),
223 							 &bss_info, &mlme_info);
224 		}
225 
226 		link_info++;
227 	}
228 }
229 #endif
230