xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_main.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 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: contains MLO manager init/deinit api's
19  */
20 #include "wlan_cmn.h"
21 #include <wlan_objmgr_cmn.h>
22 #include <wlan_objmgr_global_obj.h>
23 #include "wlan_mlo_mgr_cmn.h"
24 #include "wlan_mlo_mgr_main.h"
25 #include <wlan_mlo_mgr_ap.h>
26 #include <wlan_mlo_mgr_peer.h>
27 
28 static void mlo_global_ctx_deinit(void)
29 {
30 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
31 
32 	if (!mlo_mgr_ctx)
33 		return;
34 
35 	if (qdf_list_empty(&mlo_mgr_ctx->ml_dev_list))
36 		mlo_err("ML dev list is not empty");
37 
38 	ml_peerid_lock_destroy(mlo_mgr_ctx);
39 	ml_link_lock_destroy(mlo_mgr_ctx);
40 	ml_aid_lock_destroy(mlo_mgr_ctx);
41 	qdf_list_destroy(&mlo_mgr_ctx->ml_dev_list);
42 
43 	qdf_mem_free(mlo_mgr_ctx);
44 	wlan_objmgr_set_mlo_ctx(NULL);
45 }
46 
47 static void mlo_global_ctx_init(void)
48 {
49 	struct mlo_mgr_context *mlo_mgr_ctx;
50 
51 	/* If it is already created, ignore */
52 	if (wlan_objmgr_get_mlo_ctx()) {
53 		mlo_err("Global object is already created");
54 		return;
55 	}
56 
57 	/* Allocation of memory for Global object */
58 	mlo_mgr_ctx = (struct mlo_mgr_context *)
59 			qdf_mem_malloc(sizeof(*mlo_mgr_ctx));
60 	if (!mlo_mgr_ctx)
61 		return;
62 
63 	wlan_objmgr_set_mlo_ctx(mlo_mgr_ctx);
64 
65 	qdf_list_create(&mlo_mgr_ctx->ml_dev_list, WLAN_UMAC_MLO_MAX_DEV);
66 	mlo_mgr_ctx->max_mlo_peer_id = MAX_MLO_PEER_ID;
67 	ml_peerid_lock_create(mlo_mgr_ctx);
68 	ml_link_lock_create(mlo_mgr_ctx);
69 	ml_aid_lock_create(mlo_mgr_ctx);
70 }
71 
72 QDF_STATUS wlan_mlo_mgr_init(void)
73 {
74 	QDF_STATUS status;
75 
76 	mlo_global_ctx_init();
77 
78 	status = wlan_objmgr_register_vdev_create_handler(
79 		WLAN_UMAC_COMP_MLO_MGR,
80 		wlan_mlo_mgr_vdev_created_notification, NULL);
81 	if (QDF_IS_STATUS_ERROR(status)) {
82 		mlo_err("Failed to register vdev create handler");
83 		return QDF_STATUS_E_FAILURE;
84 	}
85 
86 	status = wlan_objmgr_register_vdev_destroy_handler(WLAN_UMAC_COMP_MLO_MGR,
87 		wlan_mlo_mgr_vdev_destroyed_notification, NULL);
88 	if (QDF_IS_STATUS_SUCCESS(status)) {
89 		mlo_debug("MLO vdev create and delete handler registered with objmgr");
90 		return QDF_STATUS_SUCCESS;
91 	}
92 	wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_MLO_MGR,
93 				wlan_mlo_mgr_vdev_created_notification, NULL);
94 
95 	return status;
96 }
97 
98 QDF_STATUS wlan_mlo_mgr_deinit(void)
99 {
100 	QDF_STATUS status;
101 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
102 
103 	if (!mlo_mgr_ctx) {
104 		mlo_err("MLO global object is not allocated");
105 		return QDF_STATUS_E_FAILURE;
106 	}
107 
108 	mlo_global_ctx_deinit();
109 
110 	status = wlan_objmgr_unregister_vdev_create_handler(
111 		WLAN_UMAC_COMP_MLO_MGR,
112 		wlan_mlo_mgr_vdev_created_notification, NULL);
113 	if (status != QDF_STATUS_SUCCESS)
114 		mlo_err("Failed to unregister vdev create handler");
115 
116 	status = wlan_objmgr_unregister_vdev_destroy_handler(
117 			WLAN_UMAC_COMP_MLO_MGR,
118 			wlan_mlo_mgr_vdev_destroyed_notification, NULL);
119 	if (status != QDF_STATUS_SUCCESS)
120 		mlo_err("Failed to unregister vdev delete handler");
121 
122 	return status;
123 }
124 
125 static inline struct wlan_mlo_dev_context *mlo_list_peek_head(
126 					qdf_list_t *ml_list)
127 {
128 	struct wlan_mlo_dev_context *mld_ctx;
129 	qdf_list_node_t *ml_node = NULL;
130 
131 	/* This API is invoked with lock acquired, do not add log prints */
132 	if (qdf_list_peek_front(ml_list, &ml_node) != QDF_STATUS_SUCCESS)
133 		return NULL;
134 
135 	mld_ctx = qdf_container_of(ml_node, struct wlan_mlo_dev_context,
136 				   node);
137 
138 	return mld_ctx;
139 }
140 
141 static inline
142 struct wlan_mlo_dev_context *mlo_get_next_mld_ctx(qdf_list_t *ml_list,
143 					struct wlan_mlo_dev_context *mld_cur)
144 {
145 	struct wlan_mlo_dev_context *mld_next;
146 	qdf_list_node_t *node = &mld_cur->node;
147 	qdf_list_node_t *next_node = NULL;
148 
149 	/* This API is invoked with lock acquired, do not add log prints */
150 	if (!node)
151 		return NULL;
152 
153 	if (qdf_list_peek_next(ml_list, node, &next_node) !=
154 						QDF_STATUS_SUCCESS)
155 		return NULL;
156 
157 	mld_next = qdf_container_of(next_node, struct wlan_mlo_dev_context,
158 				    node);
159 	return mld_next;
160 }
161 
162 static inline struct wlan_mlo_dev_context
163 *wlan_mlo_get_mld_ctx_by_mldaddr(struct qdf_mac_addr *mldaddr)
164 {
165 	struct wlan_mlo_dev_context *mld_cur;
166 	struct wlan_mlo_dev_context *mld_next;
167 	qdf_list_t *ml_list;
168 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
169 
170 	if (!mlo_mgr_ctx)
171 		return NULL;
172 
173 	ml_link_lock_acquire(mlo_mgr_ctx);
174 	ml_list = &mlo_mgr_ctx->ml_dev_list;
175 	/* Get first mld context */
176 	mld_cur = mlo_list_peek_head(ml_list);
177 	/**
178 	 * Iterate through ml list, till ml mldaddr matches with
179 	 * entry of list
180 	 */
181 	while (mld_cur) {
182 		if (QDF_IS_STATUS_SUCCESS(WLAN_ADDR_EQ(&mld_cur->mld_addr,
183 					  mldaddr))) {
184 			ml_link_lock_release(mlo_mgr_ctx);
185 			return mld_cur;
186 		}
187 		/* get next mld node */
188 		mld_next = mlo_get_next_mld_ctx(ml_list, mld_cur);
189 		mld_cur = mld_next;
190 	}
191 	ml_link_lock_release(mlo_mgr_ctx);
192 
193 	return NULL;
194 }
195 
196 static QDF_STATUS mlo_ap_ctx_deinit(struct wlan_mlo_dev_context *ml_dev)
197 {
198 	wlan_mlo_vdev_aid_mgr_deinit(ml_dev);
199 	qdf_mem_free(ml_dev->ap_ctx);
200 	ml_dev->ap_ctx = NULL;
201 
202 	return QDF_STATUS_SUCCESS;
203 }
204 
205 static QDF_STATUS mlo_ap_ctx_init(struct wlan_mlo_dev_context *ml_dev)
206 {
207 	struct wlan_mlo_ap *ap_ctx;
208 
209 	ap_ctx = qdf_mem_malloc(sizeof(*ap_ctx));
210 	if (!ap_ctx) {
211 		mlo_err("MLO AP ctx alloc failure");
212 		return QDF_STATUS_E_NOMEM;
213 	}
214 
215 	ml_dev->ap_ctx = ap_ctx;
216 	if (wlan_mlo_vdev_aid_mgr_init(ml_dev) != QDF_STATUS_SUCCESS) {
217 		mlo_ap_ctx_deinit(ml_dev);
218 		return QDF_STATUS_E_NOMEM;
219 	}
220 
221 	return QDF_STATUS_SUCCESS;
222 }
223 
224 static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
225 {
226 	struct wlan_mlo_dev_context *ml_dev;
227 	QDF_STATUS status = QDF_STATUS_SUCCESS;
228 	struct qdf_mac_addr *mld_addr;
229 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
230 	uint8_t id = 0;
231 
232 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
233 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
234 	if (ml_dev) {
235 		mlo_dev_lock_acquire(ml_dev);
236 		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
237 			if (ml_dev->wlan_vdev_list[id]) {
238 				id++;
239 				continue;
240 			}
241 			ml_dev->wlan_vdev_list[id] = vdev;
242 			ml_dev->wlan_vdev_count++;
243 			vdev->mlo_dev_ctx = ml_dev;
244 
245 			if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
246 				wlan_mlo_vdev_alloc_aid_mgr(ml_dev, vdev);
247 
248 			break;
249 		}
250 		mlo_dev_lock_release(ml_dev);
251 		return QDF_STATUS_SUCCESS;
252 	}
253 
254 	/* Create a new ML dev context */
255 	ml_dev = qdf_mem_malloc(sizeof(*ml_dev));
256 	if (!ml_dev) {
257 		mlo_err("Failed to allocate memory for ML dev");
258 		return QDF_STATUS_E_NOMEM;
259 	}
260 
261 	qdf_copy_macaddr(&ml_dev->mld_addr, mld_addr);
262 	ml_dev->wlan_vdev_list[0] = vdev;
263 	ml_dev->wlan_vdev_count++;
264 	vdev->mlo_dev_ctx = ml_dev;
265 
266 	mlo_dev_lock_create(ml_dev);
267 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
268 		ml_dev->sta_ctx = qdf_mem_malloc(sizeof(struct wlan_mlo_sta));
269 		if (!ml_dev->sta_ctx) {
270 			mlo_dev_lock_destroy(ml_dev);
271 			qdf_mem_free(ml_dev);
272 			return QDF_STATUS_E_NOMEM;
273 		}
274 	} else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
275 		if (mlo_ap_ctx_init(ml_dev) != QDF_STATUS_SUCCESS) {
276 			mlo_dev_lock_destroy(ml_dev);
277 			qdf_mem_free(ml_dev);
278 			mlo_err("Failed to allocate memory for ap ctx");
279 			return QDF_STATUS_E_NOMEM;
280 		}
281 	}
282 
283 	mlo_dev_mlpeer_list_init(ml_dev);
284 
285 	ml_link_lock_acquire(g_mlo_ctx);
286 	if (qdf_list_size(&g_mlo_ctx->ml_dev_list) < WLAN_UMAC_MLO_MAX_DEV)
287 		qdf_list_insert_back(&g_mlo_ctx->ml_dev_list, &ml_dev->node);
288 	ml_link_lock_release(g_mlo_ctx);
289 
290 	return status;
291 }
292 
293 static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
294 {
295 	struct wlan_mlo_dev_context *ml_dev;
296 	QDF_STATUS status = QDF_STATUS_SUCCESS;
297 	struct qdf_mac_addr *mld_addr;
298 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
299 	uint8_t id = 0;
300 
301 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
302 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
303 	if (!ml_dev) {
304 		mlo_err("Failed to get MLD dev context");
305 		return QDF_STATUS_SUCCESS;
306 	} else {
307 		mlo_debug("deleting vdev from MLD device ctx");
308 		mlo_dev_lock_acquire(ml_dev);
309 		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
310 			if (ml_dev->wlan_vdev_list[id] == vdev) {
311 				if (wlan_vdev_mlme_get_opmode(vdev) ==
312 								QDF_SAP_MODE)
313 					wlan_mlo_vdev_free_aid_mgr(ml_dev,
314 								   vdev);
315 				ml_dev->wlan_vdev_list[id] = NULL;
316 				ml_dev->wlan_vdev_count--;
317 				vdev->mlo_dev_ctx = NULL;
318 				break;
319 			}
320 			id++;
321 		}
322 		mlo_dev_lock_release(ml_dev);
323 	}
324 
325 	ml_link_lock_acquire(g_mlo_ctx);
326 	if (!ml_dev->wlan_vdev_count) {
327 		if (ml_dev->ap_ctx)
328 			mlo_ap_ctx_deinit(ml_dev);
329 
330 		mlo_dev_mlpeer_list_deinit(ml_dev);
331 		qdf_list_remove_node(&g_mlo_ctx->ml_dev_list,
332 				     &ml_dev->node);
333 		if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
334 			if (ml_dev->sta_ctx->connect_req)
335 				qdf_mem_free(ml_dev->sta_ctx->connect_req);
336 
337 			if (ml_dev->sta_ctx->assoc_rsp.ptr)
338 				qdf_mem_free(ml_dev->sta_ctx->assoc_rsp.ptr);
339 
340 			qdf_mem_free(ml_dev->sta_ctx);
341 		}
342 		else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
343 			qdf_mem_free(ml_dev->ap_ctx);
344 
345 		mlo_dev_lock_destroy(ml_dev);
346 		qdf_mem_free(ml_dev);
347 	}
348 	ml_link_lock_release(g_mlo_ctx);
349 	return status;
350 }
351 
352 QDF_STATUS wlan_mlo_mgr_vdev_created_notification(struct wlan_objmgr_vdev *vdev,
353 						  void *arg_list)
354 {
355 	QDF_STATUS status = QDF_STATUS_SUCCESS;
356 	struct qdf_mac_addr *mld_addr;
357 
358 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
359 	if (qdf_is_macaddr_zero(mld_addr)) {
360 		/* It's not a ML interface*/
361 		return QDF_STATUS_SUCCESS;
362 	}
363 	mlo_debug("MLD addr" QDF_MAC_ADDR_FMT,
364 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
365 	status = mlo_dev_ctx_init(vdev);
366 
367 	return status;
368 }
369 
370 QDF_STATUS wlan_mlo_mgr_vdev_destroyed_notification(struct wlan_objmgr_vdev *vdev,
371 						    void *arg_list)
372 {
373 	QDF_STATUS status = QDF_STATUS_SUCCESS;
374 	struct qdf_mac_addr *mld_addr;
375 
376 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
377 	if (qdf_is_macaddr_zero(mld_addr)) {
378 		/* It's not a ML interface*/
379 		return QDF_STATUS_SUCCESS;
380 	}
381 	mlo_debug("MLD addr" QDF_MAC_ADDR_FMT,
382 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
383 
384 	status = mlo_dev_ctx_deinit(vdev);
385 
386 	return status;
387 }
388