1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-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 #include <wlan_mlo_mgr_cmn.h>
19 #include <wlan_mlo_mgr_public_structs.h>
20 #include "wlan_mlo_mgr_main.h"
21 #include "qdf_module.h"
22 #include "qdf_types.h"
23 #include "wlan_cmn.h"
24 #include "wlan_mlo_mgr_peer.h"
25 
26 struct aid_search {
27 	struct wlan_mlo_peer_context *ml_peer;
28 	uint16_t aid;
29 };
30 
31 struct mlpeerid_search {
32 	struct wlan_mlo_peer_context *ml_peer;
33 	uint16_t ml_peerid;
34 };
35 
36 struct mac_addr_search {
37 	struct wlan_mlo_peer_context *ml_peer;
38 	struct qdf_mac_addr mac_addr;
39 };
40 
wlan_mlo_peer_list_peek_head(qdf_list_t * peer_list)41 static inline struct wlan_mlo_peer_context *wlan_mlo_peer_list_peek_head(
42 					qdf_list_t *peer_list)
43 {
44 	struct wlan_mlo_peer_context *ml_peer;
45 	qdf_list_node_t *peer_node = NULL;
46 
47 	/* This API is invoked with lock acquired, do not add log prints */
48 	if (qdf_list_peek_front(peer_list, &peer_node) != QDF_STATUS_SUCCESS)
49 		return NULL;
50 
51 	ml_peer = qdf_container_of(peer_node,
52 				   struct wlan_mlo_peer_context, peer_node);
53 	return ml_peer;
54 }
55 
wlan_mlo_peer_get_next_mlpeer(qdf_list_t * peer_list,struct wlan_mlo_peer_context * ml_peer)56 static inline struct wlan_mlo_peer_context *wlan_mlo_peer_get_next_mlpeer(
57 					qdf_list_t *peer_list,
58 					struct wlan_mlo_peer_context *ml_peer)
59 {
60 	struct wlan_mlo_peer_context *next_peer;
61 	qdf_list_node_t *node = &ml_peer->peer_node;
62 	qdf_list_node_t *next_node = NULL;
63 
64 	/* This API is invoked with lock acquired, do not add log prints */
65 	if (!node)
66 		return NULL;
67 
68 	if (qdf_list_peek_next(peer_list, node, &next_node) !=
69 				QDF_STATUS_SUCCESS)
70 		return NULL;
71 
72 	next_peer = qdf_container_of(next_node,
73 				     struct wlan_mlo_peer_context, peer_node);
74 
75 	return next_peer;
76 }
77 
mlo_get_mlpeer(struct wlan_mlo_dev_context * ml_dev,const struct qdf_mac_addr * ml_addr)78 struct wlan_mlo_peer_context *mlo_get_mlpeer(
79 				struct wlan_mlo_dev_context *ml_dev,
80 				const struct qdf_mac_addr *ml_addr)
81 {
82 	uint8_t hash_index;
83 	struct wlan_mlo_peer_list *mlo_peer_list;
84 	struct wlan_mlo_peer_context *ml_peer;
85 	struct wlan_mlo_peer_context *next_ml_peer;
86 	qdf_list_t *peer_hash_list;
87 
88 	mlo_peer_list = &ml_dev->mlo_peer_list;
89 	hash_index = WLAN_PEER_HASH(ml_addr->bytes);
90 
91 	peer_hash_list = &mlo_peer_list->peer_hash[hash_index];
92 	/* Get first vdev */
93 	ml_peer = wlan_mlo_peer_list_peek_head(peer_hash_list);
94 	/**
95 	 * Iterate through pdev's vdev list, till vdev id matches with
96 	 * entry of vdev list
97 	 */
98 	while (ml_peer) {
99 		if (qdf_is_macaddr_equal(&ml_peer->peer_mld_addr, ml_addr))
100 			return ml_peer;
101 
102 		/* get next vdev */
103 		next_ml_peer = wlan_mlo_peer_get_next_mlpeer(peer_hash_list,
104 							     ml_peer);
105 		ml_peer = next_ml_peer;
106 	}
107 
108 	return NULL;
109 }
110 
wlan_mlo_iterate_ml_peerlist(struct wlan_mlo_dev_context * ml_dev,wlan_mlo_op_handler handler,void * arg)111 QDF_STATUS wlan_mlo_iterate_ml_peerlist(struct wlan_mlo_dev_context *ml_dev,
112 					wlan_mlo_op_handler handler,
113 					void *arg)
114 {
115 	uint8_t hash_index;
116 	struct wlan_mlo_peer_list *peerlist;
117 	struct wlan_mlo_peer_context *ml_peer;
118 	struct wlan_mlo_peer_context *next;
119 	qdf_list_t *peer_hash_list;
120 	QDF_STATUS status;
121 
122 	peerlist = &ml_dev->mlo_peer_list;
123 	ml_peerlist_lock_acquire(peerlist);
124 
125 	for (hash_index = 0; hash_index < WLAN_PEER_HASHSIZE; hash_index++) {
126 		peer_hash_list = &peerlist->peer_hash[hash_index];
127 		/* Get first vdev */
128 		ml_peer = wlan_mlo_peer_list_peek_head(peer_hash_list);
129 		/**
130 		 * Iterate through pdev's vdev list, till vdev id matches with
131 		 * entry of vdev list
132 		 */
133 		while (ml_peer) {
134 			status = handler(ml_dev, ml_peer, arg);
135 			if (status == QDF_STATUS_SUCCESS) {
136 				ml_peerlist_lock_release(peerlist);
137 				return QDF_STATUS_SUCCESS;
138 			}
139 			/* get next ml peer */
140 			next = wlan_mlo_peer_get_next_mlpeer(peer_hash_list,
141 							     ml_peer);
142 			ml_peer = next;
143 		}
144 	}
145 	ml_peerlist_lock_release(peerlist);
146 
147 	return QDF_STATUS_E_NOENT;
148 }
149 
150 static QDF_STATUS
wlan_find_mlpeer_link_mac_addr(struct wlan_mlo_dev_context * ml_dev,void * iter_ml_peer,void * arg)151 wlan_find_mlpeer_link_mac_addr(struct wlan_mlo_dev_context *ml_dev,
152 			       void *iter_ml_peer,
153 			       void *arg)
154 {
155 	struct mac_addr_search *link_mac_arg = (struct mac_addr_search *)arg;
156 	struct wlan_mlo_link_peer_entry *link_peer;
157 	struct wlan_mlo_peer_context *ml_peer;
158 	uint8_t i;
159 
160 	ml_peer = (struct wlan_mlo_peer_context *)iter_ml_peer;
161 	mlo_debug("MLD ID %d ML Peer mac " QDF_MAC_ADDR_FMT,
162 		  ml_dev->mld_id,
163 		  QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes));
164 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
165 		link_peer = &ml_peer->peer_list[i];
166 
167 		mlo_debug("MLD ID %d, index %d ML Peer exists with mac " QDF_MAC_ADDR_FMT,
168 			  i, ml_dev->mld_id,
169 			  QDF_MAC_ADDR_REF(link_peer->link_addr.bytes));
170 		if (qdf_is_macaddr_equal(&link_mac_arg->mac_addr,
171 					 &link_peer->link_addr)) {
172 			link_mac_arg->ml_peer = ml_peer;
173 			return QDF_STATUS_SUCCESS;
174 		}
175 	}
176 
177 	return QDF_STATUS_E_NOENT;
178 }
179 
180 static QDF_STATUS
wlan_find_mlpeer_mld_mac_addr(struct wlan_mlo_dev_context * ml_dev,void * iter_ml_peer,void * arg)181 wlan_find_mlpeer_mld_mac_addr(struct wlan_mlo_dev_context *ml_dev,
182 			      void *iter_ml_peer,
183 			      void *arg)
184 {
185 	struct mac_addr_search *mld_mac_arg = (struct mac_addr_search *)arg;
186 	struct wlan_mlo_peer_context *ml_peer;
187 
188 	ml_peer = (struct wlan_mlo_peer_context *)iter_ml_peer;
189 	mlo_debug("MLD ID %d ML Peer mac " QDF_MAC_ADDR_FMT,
190 		  ml_dev->mld_id,
191 		  QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes));
192 
193 	if (qdf_is_macaddr_equal(&mld_mac_arg->mac_addr,
194 				 &ml_peer->peer_mld_addr)) {
195 		mld_mac_arg->ml_peer = ml_peer;
196 		return QDF_STATUS_SUCCESS;
197 	}
198 
199 	return QDF_STATUS_E_NOENT;
200 }
201 
wlan_find_mlpeer_aid(struct wlan_mlo_dev_context * ml_dev,void * iter_ml_peer,void * arg)202 static QDF_STATUS wlan_find_mlpeer_aid(struct wlan_mlo_dev_context *ml_dev,
203 				       void *iter_ml_peer,
204 				       void *arg)
205 {
206 	struct aid_search *aid_arg = (struct aid_search *)arg;
207 	struct wlan_mlo_peer_context *ml_peer;
208 
209 	ml_peer = (struct wlan_mlo_peer_context *)iter_ml_peer;
210 
211 	if (aid_arg->aid == ml_peer->assoc_id) {
212 		aid_arg->ml_peer = ml_peer;
213 		return QDF_STATUS_SUCCESS;
214 	}
215 
216 	return QDF_STATUS_E_NOENT;
217 }
218 
219 static QDF_STATUS
wlan_find_mlpeer_ml_peerid(struct wlan_mlo_dev_context * ml_dev,void * iter_ml_peer,void * arg)220 wlan_find_mlpeer_ml_peerid(struct wlan_mlo_dev_context *ml_dev,
221 			   void *iter_ml_peer,
222 			   void *arg)
223 {
224 	struct mlpeerid_search *mlpeer_id_arg = (struct mlpeerid_search *)arg;
225 	struct wlan_mlo_peer_context *ml_peer;
226 
227 	ml_peer = (struct wlan_mlo_peer_context *)iter_ml_peer;
228 
229 	if (mlpeer_id_arg->ml_peerid == ml_peer->mlo_peer_id) {
230 		mlpeer_id_arg->ml_peer = ml_peer;
231 		return QDF_STATUS_SUCCESS;
232 	}
233 
234 	return QDF_STATUS_E_NOENT;
235 }
236 
wlan_mlo_get_mlpeer_by_linkmac(struct wlan_mlo_dev_context * ml_dev,struct qdf_mac_addr * link_mac)237 struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_linkmac(
238 				struct wlan_mlo_dev_context *ml_dev,
239 				struct qdf_mac_addr *link_mac)
240 {
241 	struct mac_addr_search link_mac_arg;
242 	QDF_STATUS status;
243 
244 	mlo_debug("MLD ID %d ML Peer search with link mac " QDF_MAC_ADDR_FMT,
245 		  ml_dev->mld_id, QDF_MAC_ADDR_REF(link_mac->bytes));
246 	qdf_copy_macaddr(&link_mac_arg.mac_addr, link_mac);
247 	status = wlan_mlo_iterate_ml_peerlist(ml_dev,
248 					      wlan_find_mlpeer_link_mac_addr,
249 					      &link_mac_arg);
250 	if (status == QDF_STATUS_SUCCESS)
251 		return link_mac_arg.ml_peer;
252 
253 	/* TODO: Take ref */
254 
255 	return NULL;
256 }
257 
258 qdf_export_symbol(wlan_mlo_get_mlpeer_by_linkmac);
259 
wlan_mlo_get_mlpeer_by_aid(struct wlan_mlo_dev_context * ml_dev,uint16_t assoc_id)260 struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_aid(
261 				struct wlan_mlo_dev_context *ml_dev,
262 				uint16_t assoc_id)
263 {
264 	struct aid_search aid_arg;
265 	QDF_STATUS status;
266 
267 	aid_arg.aid = assoc_id;
268 	status = wlan_mlo_iterate_ml_peerlist(ml_dev,
269 					      wlan_find_mlpeer_aid,
270 					      &aid_arg);
271 	if (status == QDF_STATUS_SUCCESS)
272 		return aid_arg.ml_peer;
273 
274 	/* TODO: Take ref */
275 
276 	return NULL;
277 }
278 
wlan_mlo_get_mlpeer_by_mld_mac(struct wlan_mlo_dev_context * ml_dev,struct qdf_mac_addr * mld_mac)279 struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_mld_mac(
280 				struct wlan_mlo_dev_context *ml_dev,
281 				struct qdf_mac_addr *mld_mac)
282 {
283 	struct mac_addr_search mld_mac_arg;
284 	QDF_STATUS status;
285 
286 	mlo_debug("MLD ID %d ML Peer search with mld mac " QDF_MAC_ADDR_FMT,
287 		  ml_dev->mld_id, QDF_MAC_ADDR_REF(mld_mac->bytes));
288 	qdf_copy_macaddr(&mld_mac_arg.mac_addr, mld_mac);
289 	status = wlan_mlo_iterate_ml_peerlist(ml_dev,
290 					      wlan_find_mlpeer_mld_mac_addr,
291 					      &mld_mac_arg);
292 	if (QDF_IS_STATUS_SUCCESS(status))
293 		return mld_mac_arg.ml_peer;
294 
295 	/* TODO: Take ref */
296 
297 	return NULL;
298 }
299 
300 qdf_export_symbol(wlan_mlo_get_mlpeer_by_mld_mac);
301 
302 struct wlan_mlo_peer_context
wlan_mlo_get_mlpeer_by_peer_mladdr(struct qdf_mac_addr * mldaddr,struct wlan_mlo_dev_context ** mldev)303 *wlan_mlo_get_mlpeer_by_peer_mladdr(struct qdf_mac_addr *mldaddr,
304 				struct wlan_mlo_dev_context **mldev)
305 {
306 	struct wlan_mlo_dev_context *mld_cur;
307 	struct wlan_mlo_dev_context *mld_next;
308 	struct wlan_mlo_peer_context *ml_peer;
309 	qdf_list_t *ml_list;
310 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
311 
312 	if (!mlo_mgr_ctx)
313 		return NULL;
314 
315 	ml_link_lock_acquire(mlo_mgr_ctx);
316 	ml_list = &mlo_mgr_ctx->ml_dev_list;
317 	mld_cur = wlan_mlo_list_peek_head(ml_list);
318 
319 	while (mld_cur) {
320 		ml_peer = mlo_get_mlpeer(mld_cur, mldaddr);
321 		if (ml_peer != NULL) {
322 			*mldev = mld_cur;
323 			ml_link_lock_release(mlo_mgr_ctx);
324 			return ml_peer;
325 		}
326 		mld_next = wlan_mlo_get_next_mld_ctx(ml_list, mld_cur);
327 		mld_cur = mld_next;
328 	}
329 	ml_link_lock_release(mlo_mgr_ctx);
330 
331 	return NULL;
332 }
333 
wlan_mlo_get_mlpeer_by_ml_peerid(struct wlan_mlo_dev_context * ml_dev,uint16_t ml_peerid)334 struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_ml_peerid(
335 				struct wlan_mlo_dev_context *ml_dev,
336 				uint16_t ml_peerid)
337 {
338 	struct mlpeerid_search peerid_arg;
339 	QDF_STATUS status;
340 
341 	peerid_arg.ml_peerid = ml_peerid;
342 	status = wlan_mlo_iterate_ml_peerlist(ml_dev,
343 					      wlan_find_mlpeer_ml_peerid,
344 					      &peerid_arg);
345 	if (status == QDF_STATUS_SUCCESS)
346 		return peerid_arg.ml_peer;
347 
348 	/* TODO: Take ref */
349 
350 	return NULL;
351 }
352 
353 qdf_export_symbol(wlan_mlo_get_mlpeer_by_ml_peerid);
354 
wlan_mlo_get_mlpeer(struct wlan_mlo_dev_context * ml_dev,struct qdf_mac_addr * ml_addr)355 struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer(
356 				struct wlan_mlo_dev_context *ml_dev,
357 				struct qdf_mac_addr *ml_addr)
358 {
359 	struct wlan_mlo_peer_context *ml_peer;
360 	struct wlan_mlo_peer_list *mlo_peer_list;
361 
362 	mlo_debug("MLD ID %d ML Peer search mac " QDF_MAC_ADDR_FMT,
363 		  ml_dev->mld_id, QDF_MAC_ADDR_REF(ml_addr->bytes));
364 	mlo_peer_list = &ml_dev->mlo_peer_list;
365 	ml_peerlist_lock_acquire(mlo_peer_list);
366 	ml_peer = mlo_get_mlpeer(ml_dev, ml_addr);
367 	if (!ml_peer) {
368 		ml_peerlist_lock_release(mlo_peer_list);
369 		return NULL;
370 	}
371 	/* TODO: Take ref */
372 
373 	ml_peerlist_lock_release(mlo_peer_list);
374 	return ml_peer;
375 }
376 
wlan_mlo_peerlist_add_tail(qdf_list_t * obj_list,struct wlan_mlo_peer_context * obj)377 static void wlan_mlo_peerlist_add_tail(qdf_list_t *obj_list,
378 				       struct wlan_mlo_peer_context *obj)
379 {
380 	qdf_list_insert_back(obj_list, &obj->peer_node);
381 }
382 
wlan_mlo_peerlist_remove_mlpeer(qdf_list_t * obj_list,struct wlan_mlo_peer_context * ml_peer)383 static QDF_STATUS wlan_mlo_peerlist_remove_mlpeer(
384 				qdf_list_t *obj_list,
385 				struct wlan_mlo_peer_context *ml_peer)
386 {
387 	qdf_list_node_t *peer_node = NULL;
388 
389 	if (!ml_peer)
390 		return QDF_STATUS_E_FAILURE;
391 	/* get vdev list node element */
392 	peer_node = &ml_peer->peer_node;
393 	/* list is empty, return failure */
394 	if (qdf_list_remove_node(obj_list, peer_node) != QDF_STATUS_SUCCESS)
395 		return QDF_STATUS_E_FAILURE;
396 
397 	return QDF_STATUS_SUCCESS;
398 }
399 
mlo_dev_mlpeer_attach(struct wlan_mlo_dev_context * ml_dev,struct wlan_mlo_peer_context * ml_peer)400 QDF_STATUS mlo_dev_mlpeer_attach(struct wlan_mlo_dev_context *ml_dev,
401 				 struct wlan_mlo_peer_context *ml_peer)
402 {
403 	uint8_t hash_index;
404 	struct wlan_mlo_peer_list *mlo_peer_list;
405 
406 	mlo_peer_list = &ml_dev->mlo_peer_list;
407 	ml_peerlist_lock_acquire(mlo_peer_list);
408 	if (mlo_get_mlpeer(ml_dev, &ml_peer->peer_mld_addr)) {
409 		ml_peerlist_lock_release(mlo_peer_list);
410 		mlo_err("MLD ID %d ML Peer exists with mac " QDF_MAC_ADDR_FMT,
411 			ml_dev->mld_id,
412 			QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes));
413 		return QDF_STATUS_E_EXISTS;
414 	}
415 
416 	hash_index = WLAN_PEER_HASH(ml_peer->peer_mld_addr.bytes);
417 	wlan_mlo_peerlist_add_tail(&mlo_peer_list->peer_hash[hash_index],
418 				   ml_peer);
419 	ml_peerlist_lock_release(mlo_peer_list);
420 
421 	mlo_debug("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " is attached",
422 		  ml_dev->mld_id,
423 		  QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes));
424 
425 	return QDF_STATUS_SUCCESS;
426 }
427 
mlo_dev_mlpeer_detach(struct wlan_mlo_dev_context * ml_dev,struct wlan_mlo_peer_context * ml_peer)428 QDF_STATUS mlo_dev_mlpeer_detach(struct wlan_mlo_dev_context *ml_dev,
429 				 struct wlan_mlo_peer_context *ml_peer)
430 {
431 	uint8_t hash_index;
432 	QDF_STATUS status;
433 	struct wlan_mlo_peer_list *mlo_peer_list;
434 
435 	mlo_peer_list = &ml_dev->mlo_peer_list;
436 	ml_peerlist_lock_acquire(mlo_peer_list);
437 	hash_index = WLAN_PEER_HASH(ml_peer->peer_mld_addr.bytes);
438 	status = wlan_mlo_peerlist_remove_mlpeer(
439 					&mlo_peer_list->peer_hash[hash_index],
440 					ml_peer);
441 	ml_peerlist_lock_release(mlo_peer_list);
442 
443 	mlo_debug("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " is detached",
444 		  ml_dev->mld_id,
445 		  QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes));
446 
447 	return status;
448 }
449 
mlo_dev_mlpeer_list_init(struct wlan_mlo_dev_context * ml_dev)450 QDF_STATUS mlo_dev_mlpeer_list_init(struct wlan_mlo_dev_context *ml_dev)
451 {
452 	struct wlan_mlo_peer_list *mlo_peer_list;
453 	uint16_t i;
454 
455 	mlo_peer_list = &ml_dev->mlo_peer_list;
456 	ml_peerlist_lock_create(mlo_peer_list);
457 	for (i = 0; i < WLAN_PEER_HASHSIZE; i++)
458 		qdf_list_create(&mlo_peer_list->peer_hash[i],
459 				WLAN_UMAC_PSOC_MAX_PEERS +
460 				WLAN_MAX_PSOC_TEMP_PEERS);
461 
462 	if (ml_dev->ap_ctx) {
463 		qdf_spinlock_create(&ml_dev->ap_ctx->assoc_list.list_lock);
464 		qdf_list_create(&ml_dev->ap_ctx->assoc_list.peer_list,
465 				WLAN_UMAC_PSOC_MAX_PEERS);
466 	}
467 
468 	return QDF_STATUS_SUCCESS;
469 }
470 
mlo_dev_mlpeer_list_deinit(struct wlan_mlo_dev_context * ml_dev)471 QDF_STATUS mlo_dev_mlpeer_list_deinit(struct wlan_mlo_dev_context *ml_dev)
472 {
473 	uint16_t i;
474 	struct wlan_mlo_peer_list *mlo_peer_list;
475 
476 	if (ml_dev->ap_ctx) {
477 		qdf_list_destroy(&ml_dev->ap_ctx->assoc_list.peer_list);
478 		qdf_spinlock_destroy(&ml_dev->ap_ctx->assoc_list.list_lock);
479 	}
480 
481 	mlo_peer_list = &ml_dev->mlo_peer_list;
482 	for (i = 0; i < WLAN_PEER_HASHSIZE; i++)
483 		qdf_list_destroy(&mlo_peer_list->peer_hash[i]);
484 
485 	ml_peerlist_lock_destroy(mlo_peer_list);
486 	return QDF_STATUS_SUCCESS;
487 }
488