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