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