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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 return QDF_STATUS_SUCCESS; 463 } 464 465 QDF_STATUS mlo_dev_mlpeer_list_deinit(struct wlan_mlo_dev_context *ml_dev) 466 { 467 uint16_t i; 468 struct wlan_mlo_peer_list *mlo_peer_list; 469 470 /* deinit the lock */ 471 mlo_peer_list = &ml_dev->mlo_peer_list; 472 ml_peerlist_lock_destroy(mlo_peer_list); 473 for (i = 0; i < WLAN_PEER_HASHSIZE; i++) 474 qdf_list_destroy(&mlo_peer_list->peer_hash[i]); 475 476 return QDF_STATUS_SUCCESS; 477 } 478