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