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 /* 18 * DOC: contains MLO manager init/deinit api's 19 */ 20 #include "wlan_cmn.h" 21 #include <wlan_objmgr_cmn.h> 22 #include <wlan_objmgr_global_obj.h> 23 #include "wlan_mlo_mgr_cmn.h" 24 #include "wlan_mlo_mgr_main.h" 25 #include <wlan_mlo_mgr_ap.h> 26 #include <wlan_mlo_mgr_peer.h> 27 28 static void mlo_global_ctx_deinit(void) 29 { 30 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); 31 32 if (!mlo_mgr_ctx) 33 return; 34 35 if (qdf_list_empty(&mlo_mgr_ctx->ml_dev_list)) 36 mlo_err("ML dev list is not empty"); 37 38 ml_peerid_lock_destroy(mlo_mgr_ctx); 39 ml_link_lock_destroy(mlo_mgr_ctx); 40 ml_aid_lock_destroy(mlo_mgr_ctx); 41 qdf_list_destroy(&mlo_mgr_ctx->ml_dev_list); 42 43 qdf_mem_free(mlo_mgr_ctx); 44 wlan_objmgr_set_mlo_ctx(NULL); 45 } 46 47 static void mlo_global_ctx_init(void) 48 { 49 struct mlo_mgr_context *mlo_mgr_ctx; 50 51 /* If it is already created, ignore */ 52 if (wlan_objmgr_get_mlo_ctx()) { 53 mlo_err("Global object is already created"); 54 return; 55 } 56 57 /* Allocation of memory for Global object */ 58 mlo_mgr_ctx = (struct mlo_mgr_context *) 59 qdf_mem_malloc(sizeof(*mlo_mgr_ctx)); 60 if (!mlo_mgr_ctx) 61 return; 62 63 wlan_objmgr_set_mlo_ctx(mlo_mgr_ctx); 64 65 qdf_list_create(&mlo_mgr_ctx->ml_dev_list, WLAN_UMAC_MLO_MAX_DEV); 66 mlo_mgr_ctx->max_mlo_peer_id = MAX_MLO_PEER_ID; 67 ml_peerid_lock_create(mlo_mgr_ctx); 68 ml_link_lock_create(mlo_mgr_ctx); 69 ml_aid_lock_create(mlo_mgr_ctx); 70 } 71 72 QDF_STATUS wlan_mlo_mgr_init(void) 73 { 74 QDF_STATUS status; 75 76 mlo_global_ctx_init(); 77 78 status = wlan_objmgr_register_vdev_create_handler( 79 WLAN_UMAC_COMP_MLO_MGR, 80 wlan_mlo_mgr_vdev_created_notification, NULL); 81 if (QDF_IS_STATUS_ERROR(status)) { 82 mlo_err("Failed to register vdev create handler"); 83 return QDF_STATUS_E_FAILURE; 84 } 85 86 status = wlan_objmgr_register_vdev_destroy_handler(WLAN_UMAC_COMP_MLO_MGR, 87 wlan_mlo_mgr_vdev_destroyed_notification, NULL); 88 if (QDF_IS_STATUS_SUCCESS(status)) { 89 mlo_debug("MLO vdev create and delete handler registered with objmgr"); 90 return QDF_STATUS_SUCCESS; 91 } 92 wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_MLO_MGR, 93 wlan_mlo_mgr_vdev_created_notification, NULL); 94 95 return status; 96 } 97 98 QDF_STATUS wlan_mlo_mgr_deinit(void) 99 { 100 QDF_STATUS status; 101 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); 102 103 if (!mlo_mgr_ctx) { 104 mlo_err("MLO global object is not allocated"); 105 return QDF_STATUS_E_FAILURE; 106 } 107 108 mlo_global_ctx_deinit(); 109 110 status = wlan_objmgr_unregister_vdev_create_handler( 111 WLAN_UMAC_COMP_MLO_MGR, 112 wlan_mlo_mgr_vdev_created_notification, NULL); 113 if (status != QDF_STATUS_SUCCESS) 114 mlo_err("Failed to unregister vdev create handler"); 115 116 status = wlan_objmgr_unregister_vdev_destroy_handler( 117 WLAN_UMAC_COMP_MLO_MGR, 118 wlan_mlo_mgr_vdev_destroyed_notification, NULL); 119 if (status != QDF_STATUS_SUCCESS) 120 mlo_err("Failed to unregister vdev delete handler"); 121 122 return status; 123 } 124 125 static inline struct wlan_mlo_dev_context *mlo_list_peek_head( 126 qdf_list_t *ml_list) 127 { 128 struct wlan_mlo_dev_context *mld_ctx; 129 qdf_list_node_t *ml_node = NULL; 130 131 /* This API is invoked with lock acquired, do not add log prints */ 132 if (qdf_list_peek_front(ml_list, &ml_node) != QDF_STATUS_SUCCESS) 133 return NULL; 134 135 mld_ctx = qdf_container_of(ml_node, struct wlan_mlo_dev_context, 136 node); 137 138 return mld_ctx; 139 } 140 141 static inline 142 struct wlan_mlo_dev_context *mlo_get_next_mld_ctx(qdf_list_t *ml_list, 143 struct wlan_mlo_dev_context *mld_cur) 144 { 145 struct wlan_mlo_dev_context *mld_next; 146 qdf_list_node_t *node = &mld_cur->node; 147 qdf_list_node_t *next_node = NULL; 148 149 /* This API is invoked with lock acquired, do not add log prints */ 150 if (!node) 151 return NULL; 152 153 if (qdf_list_peek_next(ml_list, node, &next_node) != 154 QDF_STATUS_SUCCESS) 155 return NULL; 156 157 mld_next = qdf_container_of(next_node, struct wlan_mlo_dev_context, 158 node); 159 return mld_next; 160 } 161 162 static inline struct wlan_mlo_dev_context 163 *wlan_mlo_get_mld_ctx_by_mldaddr(struct qdf_mac_addr *mldaddr) 164 { 165 struct wlan_mlo_dev_context *mld_cur; 166 struct wlan_mlo_dev_context *mld_next; 167 qdf_list_t *ml_list; 168 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); 169 170 if (!mlo_mgr_ctx) 171 return NULL; 172 173 ml_link_lock_acquire(mlo_mgr_ctx); 174 ml_list = &mlo_mgr_ctx->ml_dev_list; 175 /* Get first mld context */ 176 mld_cur = mlo_list_peek_head(ml_list); 177 /** 178 * Iterate through ml list, till ml mldaddr matches with 179 * entry of list 180 */ 181 while (mld_cur) { 182 if (QDF_IS_STATUS_SUCCESS(WLAN_ADDR_EQ(&mld_cur->mld_addr, 183 mldaddr))) { 184 ml_link_lock_release(mlo_mgr_ctx); 185 return mld_cur; 186 } 187 /* get next mld node */ 188 mld_next = mlo_get_next_mld_ctx(ml_list, mld_cur); 189 mld_cur = mld_next; 190 } 191 ml_link_lock_release(mlo_mgr_ctx); 192 193 return NULL; 194 } 195 196 static QDF_STATUS mlo_ap_ctx_deinit(struct wlan_mlo_dev_context *ml_dev) 197 { 198 wlan_mlo_vdev_aid_mgr_deinit(ml_dev); 199 qdf_mem_free(ml_dev->ap_ctx); 200 ml_dev->ap_ctx = NULL; 201 202 return QDF_STATUS_SUCCESS; 203 } 204 205 static QDF_STATUS mlo_ap_ctx_init(struct wlan_mlo_dev_context *ml_dev) 206 { 207 struct wlan_mlo_ap *ap_ctx; 208 209 ap_ctx = qdf_mem_malloc(sizeof(*ap_ctx)); 210 if (!ap_ctx) { 211 mlo_err("MLO AP ctx alloc failure"); 212 return QDF_STATUS_E_NOMEM; 213 } 214 215 ml_dev->ap_ctx = ap_ctx; 216 if (wlan_mlo_vdev_aid_mgr_init(ml_dev) != QDF_STATUS_SUCCESS) { 217 mlo_ap_ctx_deinit(ml_dev); 218 return QDF_STATUS_E_NOMEM; 219 } 220 221 return QDF_STATUS_SUCCESS; 222 } 223 224 static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev) 225 { 226 struct wlan_mlo_dev_context *ml_dev; 227 QDF_STATUS status = QDF_STATUS_SUCCESS; 228 struct qdf_mac_addr *mld_addr; 229 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 230 uint8_t id = 0; 231 232 mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); 233 ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr); 234 if (ml_dev) { 235 mlo_dev_lock_acquire(ml_dev); 236 while (id < WLAN_UMAC_MLO_MAX_VDEVS) { 237 if (ml_dev->wlan_vdev_list[id]) { 238 id++; 239 continue; 240 } 241 ml_dev->wlan_vdev_list[id] = vdev; 242 ml_dev->wlan_vdev_count++; 243 vdev->mlo_dev_ctx = ml_dev; 244 245 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) 246 wlan_mlo_vdev_alloc_aid_mgr(ml_dev, vdev); 247 248 break; 249 } 250 mlo_dev_lock_release(ml_dev); 251 return QDF_STATUS_SUCCESS; 252 } 253 254 /* Create a new ML dev context */ 255 ml_dev = qdf_mem_malloc(sizeof(*ml_dev)); 256 if (!ml_dev) { 257 mlo_err("Failed to allocate memory for ML dev"); 258 return QDF_STATUS_E_NOMEM; 259 } 260 261 qdf_copy_macaddr(&ml_dev->mld_addr, mld_addr); 262 ml_dev->wlan_vdev_list[0] = vdev; 263 ml_dev->wlan_vdev_count++; 264 vdev->mlo_dev_ctx = ml_dev; 265 266 mlo_dev_lock_create(ml_dev); 267 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) { 268 ml_dev->sta_ctx = qdf_mem_malloc(sizeof(struct wlan_mlo_sta)); 269 if (!ml_dev->sta_ctx) { 270 mlo_dev_lock_destroy(ml_dev); 271 qdf_mem_free(ml_dev); 272 return QDF_STATUS_E_NOMEM; 273 } 274 } else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) { 275 if (mlo_ap_ctx_init(ml_dev) != QDF_STATUS_SUCCESS) { 276 mlo_dev_lock_destroy(ml_dev); 277 qdf_mem_free(ml_dev); 278 mlo_err("Failed to allocate memory for ap ctx"); 279 return QDF_STATUS_E_NOMEM; 280 } 281 } 282 283 mlo_dev_mlpeer_list_init(ml_dev); 284 285 ml_link_lock_acquire(g_mlo_ctx); 286 if (qdf_list_size(&g_mlo_ctx->ml_dev_list) < WLAN_UMAC_MLO_MAX_DEV) 287 qdf_list_insert_back(&g_mlo_ctx->ml_dev_list, &ml_dev->node); 288 ml_link_lock_release(g_mlo_ctx); 289 290 return status; 291 } 292 293 static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev) 294 { 295 struct wlan_mlo_dev_context *ml_dev; 296 QDF_STATUS status = QDF_STATUS_SUCCESS; 297 struct qdf_mac_addr *mld_addr; 298 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 299 uint8_t id = 0; 300 301 mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); 302 ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr); 303 if (!ml_dev) { 304 mlo_err("Failed to get MLD dev context"); 305 return QDF_STATUS_SUCCESS; 306 } else { 307 mlo_debug("deleting vdev from MLD device ctx"); 308 mlo_dev_lock_acquire(ml_dev); 309 while (id < WLAN_UMAC_MLO_MAX_VDEVS) { 310 if (ml_dev->wlan_vdev_list[id] == vdev) { 311 if (wlan_vdev_mlme_get_opmode(vdev) == 312 QDF_SAP_MODE) 313 wlan_mlo_vdev_free_aid_mgr(ml_dev, 314 vdev); 315 ml_dev->wlan_vdev_list[id] = NULL; 316 ml_dev->wlan_vdev_count--; 317 vdev->mlo_dev_ctx = NULL; 318 break; 319 } 320 id++; 321 } 322 mlo_dev_lock_release(ml_dev); 323 } 324 325 ml_link_lock_acquire(g_mlo_ctx); 326 if (!ml_dev->wlan_vdev_count) { 327 if (ml_dev->ap_ctx) 328 mlo_ap_ctx_deinit(ml_dev); 329 330 mlo_dev_mlpeer_list_deinit(ml_dev); 331 qdf_list_remove_node(&g_mlo_ctx->ml_dev_list, 332 &ml_dev->node); 333 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) { 334 if (ml_dev->sta_ctx->connect_req) 335 qdf_mem_free(ml_dev->sta_ctx->connect_req); 336 337 if (ml_dev->sta_ctx->assoc_rsp.ptr) 338 qdf_mem_free(ml_dev->sta_ctx->assoc_rsp.ptr); 339 340 qdf_mem_free(ml_dev->sta_ctx); 341 } 342 else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) 343 qdf_mem_free(ml_dev->ap_ctx); 344 345 mlo_dev_lock_destroy(ml_dev); 346 qdf_mem_free(ml_dev); 347 } 348 ml_link_lock_release(g_mlo_ctx); 349 return status; 350 } 351 352 QDF_STATUS wlan_mlo_mgr_vdev_created_notification(struct wlan_objmgr_vdev *vdev, 353 void *arg_list) 354 { 355 QDF_STATUS status = QDF_STATUS_SUCCESS; 356 struct qdf_mac_addr *mld_addr; 357 358 mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); 359 if (qdf_is_macaddr_zero(mld_addr)) { 360 /* It's not a ML interface*/ 361 return QDF_STATUS_SUCCESS; 362 } 363 mlo_debug("MLD addr" QDF_MAC_ADDR_FMT, 364 QDF_MAC_ADDR_REF(mld_addr->bytes)); 365 status = mlo_dev_ctx_init(vdev); 366 367 return status; 368 } 369 370 QDF_STATUS wlan_mlo_mgr_vdev_destroyed_notification(struct wlan_objmgr_vdev *vdev, 371 void *arg_list) 372 { 373 QDF_STATUS status = QDF_STATUS_SUCCESS; 374 struct qdf_mac_addr *mld_addr; 375 376 mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); 377 if (qdf_is_macaddr_zero(mld_addr)) { 378 /* It's not a ML interface*/ 379 return QDF_STATUS_SUCCESS; 380 } 381 mlo_debug("MLD addr" QDF_MAC_ADDR_FMT, 382 QDF_MAC_ADDR_REF(mld_addr->bytes)); 383 384 status = mlo_dev_ctx_deinit(vdev); 385 386 return status; 387 } 388