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