1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 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 #include "wlan_mlo_mgr_main.h" 18 #include "qdf_types.h" 19 #include "wlan_cmn.h" 20 #include "wlan_mlo_mgr_cmn.h" 21 #include "wlan_mlo_mgr_msgq.h" 22 #include "wlan_mlo_mgr_peer.h" 23 24 #ifndef MLO_MSGQ_SUPPORT 25 QDF_STATUS mlo_msgq_post(enum mlo_msg_type type, 26 struct wlan_mlo_dev_context *ml_dev, 27 void *payload) 28 { 29 struct peer_create_notif_s *peer_create; 30 struct peer_assoc_notify_s *peer_assoc; 31 struct peer_assoc_fail_notify_s *peer_assoc_fail; 32 struct peer_discon_notify_s *peer_disconn; 33 struct peer_deauth_notify_s *peer_deauth; 34 struct peer_auth_process_notif_s *peer_auth; 35 36 switch (type) { 37 case MLO_PEER_CREATE: 38 peer_create = (struct peer_create_notif_s *)payload; 39 40 mlo_mlme_peer_create(peer_create->vdev_link, 41 peer_create->ml_peer, 42 &peer_create->addr, peer_create->frm_buf); 43 qdf_nbuf_free(peer_create->frm_buf); 44 wlan_mlo_peer_release_ref(peer_create->ml_peer); 45 wlan_objmgr_vdev_release_ref(peer_create->vdev_link, 46 WLAN_MLO_MGR_ID); 47 break; 48 49 case MLO_PEER_ASSOC: 50 peer_assoc = (struct peer_assoc_notify_s *)payload; 51 mlo_mlme_peer_assoc(peer_assoc->peer); 52 wlan_objmgr_peer_release_ref(peer_assoc->peer, 53 WLAN_MLO_MGR_ID); 54 break; 55 56 case MLO_PEER_ASSOC_FAIL: 57 peer_assoc_fail = (struct peer_assoc_fail_notify_s *)payload; 58 mlo_mlme_peer_assoc_fail(peer_assoc_fail->peer); 59 wlan_objmgr_peer_release_ref(peer_assoc_fail->peer, 60 WLAN_MLO_MGR_ID); 61 break; 62 63 case MLO_PEER_DISCONNECT: 64 peer_disconn = (struct peer_discon_notify_s *)payload; 65 mlo_mlme_peer_delete(peer_disconn->peer); 66 wlan_objmgr_peer_release_ref(peer_disconn->peer, 67 WLAN_MLO_MGR_ID); 68 break; 69 70 case MLO_PEER_DEAUTH: 71 peer_deauth = (struct peer_deauth_notify_s *)payload; 72 mlo_mlme_peer_deauth(peer_deauth->peer); 73 wlan_objmgr_peer_release_ref(peer_deauth->peer, 74 WLAN_MLO_MGR_ID); 75 break; 76 77 case MLO_PEER_PENDING_AUTH: 78 peer_auth = (struct peer_auth_process_notif_s *)payload; 79 mlo_mlme_peer_process_auth(peer_auth->auth_params); 80 break; 81 82 default: 83 break; 84 } 85 86 return QDF_STATUS_SUCCESS; 87 } 88 89 void mlo_msgq_init(void) 90 { 91 } 92 93 void mlo_msgq_free(void) 94 { 95 } 96 #else 97 static void mlo_msgq_timer_start(void) 98 { 99 struct ctxt_switch_mgr *msgq_ctx; 100 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 101 bool start_timer = true; 102 103 if (!mlo_ctx) 104 return; 105 106 msgq_ctx = mlo_ctx->msgq_ctx; 107 108 qdf_spin_lock_bh(&msgq_ctx->ctxt_lock); 109 if (!msgq_ctx->timer_started) 110 msgq_ctx->timer_started = true; 111 else 112 start_timer = false; 113 qdf_spin_unlock_bh(&msgq_ctx->ctxt_lock); 114 115 if (start_timer) 116 qdf_timer_start(&msgq_ctx->ctxt_mgr_timer, 0); 117 } 118 119 static void mlo_msgq_timer_stop(void) 120 { 121 struct ctxt_switch_mgr *msgq_ctx; 122 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 123 124 if (!mlo_ctx) 125 return; 126 127 msgq_ctx = mlo_ctx->msgq_ctx; 128 129 qdf_timer_stop(&msgq_ctx->ctxt_mgr_timer); 130 131 qdf_spin_lock_bh(&msgq_ctx->ctxt_lock); 132 msgq_ctx->timer_started = false; 133 qdf_spin_unlock_bh(&msgq_ctx->ctxt_lock); 134 } 135 136 QDF_STATUS mlo_msgq_post(enum mlo_msg_type type, 137 struct wlan_mlo_dev_context *ml_dev, 138 void *payload) 139 { 140 struct mlo_ctxt_switch_msg_s *msg; 141 struct peer_create_notif_s *peer_create, *peer_create_l; 142 struct peer_assoc_notify_s *peer_assoc, *peer_assoc_l; 143 struct peer_assoc_fail_notify_s *peer_assoc_fail, *peer_assoc_fail_l; 144 struct peer_discon_notify_s *peer_disconn, *peer_disconn_l; 145 struct peer_deauth_notify_s *peer_deauth, *peer_deauth_l; 146 struct peer_auth_process_notif_s *peer_auth, *peer_auth_l; 147 struct ctxt_switch_mgr *msgq_ctx; 148 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 149 150 if (!mlo_ctx) 151 return QDF_STATUS_E_FAILURE; 152 153 msgq_ctx = mlo_ctx->msgq_ctx; 154 155 if (!msgq_ctx->allow_msg) 156 return QDF_STATUS_E_FAILURE; 157 158 msg = qdf_mem_malloc(sizeof(*msg)); 159 if (!msg) 160 return QDF_STATUS_E_NOMEM; 161 162 msg->type = type; 163 msg->ml_dev = ml_dev; 164 165 switch (type) { 166 case MLO_PEER_CREATE: 167 peer_create = &msg->m.peer_create; 168 peer_create_l = (struct peer_create_notif_s *)payload; 169 peer_create->frm_buf = peer_create_l->frm_buf; 170 peer_create->ml_peer = peer_create_l->ml_peer; 171 peer_create->vdev_link = peer_create_l->vdev_link; 172 qdf_copy_macaddr(&peer_create->addr, &peer_create_l->addr); 173 break; 174 175 case MLO_PEER_ASSOC: 176 peer_assoc = &msg->m.peer_assoc; 177 peer_assoc_l = (struct peer_assoc_notify_s *)payload; 178 peer_assoc->peer = peer_assoc_l->peer; 179 break; 180 181 case MLO_PEER_ASSOC_FAIL: 182 peer_assoc_fail = &msg->m.peer_assoc_fail; 183 peer_assoc_fail_l = (struct peer_assoc_fail_notify_s *)payload; 184 peer_assoc_fail->peer = peer_assoc_fail_l->peer; 185 break; 186 187 case MLO_PEER_DISCONNECT: 188 peer_disconn = &msg->m.peer_disconn; 189 peer_disconn_l = (struct peer_discon_notify_s *)payload; 190 peer_disconn->peer = peer_disconn_l->peer; 191 break; 192 193 case MLO_PEER_DEAUTH: 194 peer_deauth = &msg->m.peer_deauth; 195 peer_deauth_l = (struct peer_deauth_notify_s *)payload; 196 peer_deauth->peer = peer_deauth_l->peer; 197 break; 198 199 case MLO_PEER_PENDING_AUTH: 200 peer_auth = &msg->m.peer_auth; 201 peer_auth_l = (struct peer_auth_process_notif_s *)payload; 202 peer_auth->auth_params = peer_auth_l->auth_params; 203 break; 204 205 default: 206 break; 207 } 208 209 qdf_spin_lock_bh(&msgq_ctx->ctxt_lock); 210 qdf_list_insert_back(&msgq_ctx->msgq_list, &msg->node); 211 qdf_spin_unlock_bh(&msgq_ctx->ctxt_lock); 212 mlo_msgq_timer_start(); 213 214 return QDF_STATUS_SUCCESS; 215 } 216 217 static void mlo_msgq_msg_process_hdlr(struct mlo_ctxt_switch_msg_s *msg) 218 { 219 enum mlo_msg_type type; 220 struct peer_create_notif_s *peer_create; 221 struct peer_assoc_notify_s *peer_assoc; 222 struct peer_assoc_fail_notify_s *peer_assoc_fail; 223 struct peer_discon_notify_s *peer_disconn; 224 struct peer_deauth_notify_s *peer_deauth; 225 struct peer_auth_process_notif_s *peer_auth; 226 227 type = msg->type; 228 switch (type) { 229 case MLO_PEER_CREATE: 230 peer_create = &msg->m.peer_create; 231 mlo_mlme_peer_create(peer_create->vdev_link, 232 peer_create->ml_peer, 233 &peer_create->addr, peer_create->frm_buf); 234 qdf_nbuf_free(peer_create->frm_buf); 235 wlan_mlo_peer_release_ref(peer_create->ml_peer); 236 wlan_objmgr_vdev_release_ref(peer_create->vdev_link, 237 WLAN_MLO_MGR_ID); 238 break; 239 240 case MLO_PEER_ASSOC: 241 peer_assoc = &msg->m.peer_assoc; 242 mlo_mlme_peer_assoc(peer_assoc->peer); 243 wlan_objmgr_peer_release_ref(peer_assoc->peer, 244 WLAN_MLO_MGR_ID); 245 break; 246 247 case MLO_PEER_ASSOC_FAIL: 248 peer_assoc_fail = &msg->m.peer_assoc_fail; 249 mlo_mlme_peer_assoc_fail(peer_assoc_fail->peer); 250 wlan_objmgr_peer_release_ref(peer_assoc_fail->peer, 251 WLAN_MLO_MGR_ID); 252 break; 253 254 case MLO_PEER_DISCONNECT: 255 peer_disconn = &msg->m.peer_disconn; 256 mlo_mlme_peer_delete(peer_disconn->peer); 257 wlan_objmgr_peer_release_ref(peer_disconn->peer, 258 WLAN_MLO_MGR_ID); 259 break; 260 261 case MLO_PEER_DEAUTH: 262 peer_deauth = &msg->m.peer_deauth; 263 mlo_mlme_peer_deauth(peer_deauth->peer); 264 wlan_objmgr_peer_release_ref(peer_deauth->peer, 265 WLAN_MLO_MGR_ID); 266 break; 267 268 case MLO_PEER_PENDING_AUTH: 269 peer_auth = &msg->m.peer_auth; 270 mlo_mlme_peer_process_auth(peer_auth->auth_params); 271 break; 272 273 default: 274 break; 275 } 276 qdf_mem_free(msg); 277 } 278 279 static void mlo_msgq_msg_flush_hdlr(struct mlo_ctxt_switch_msg_s *msg) 280 { 281 enum mlo_msg_type type; 282 struct peer_create_notif_s *peer_create; 283 struct peer_assoc_notify_s *peer_assoc; 284 struct peer_assoc_fail_notify_s *peer_assoc_fail; 285 struct peer_discon_notify_s *peer_disconn; 286 struct peer_deauth_notify_s *peer_deauth; 287 288 type = msg->type; 289 switch (type) { 290 case MLO_PEER_CREATE: 291 peer_create = &msg->m.peer_create; 292 qdf_nbuf_free(peer_create->frm_buf); 293 wlan_mlo_peer_release_ref(peer_create->ml_peer); 294 wlan_objmgr_vdev_release_ref(peer_create->vdev_link, 295 WLAN_MLO_MGR_ID); 296 break; 297 298 case MLO_PEER_ASSOC: 299 peer_assoc = &msg->m.peer_assoc; 300 wlan_objmgr_peer_release_ref(peer_assoc->peer, 301 WLAN_MLO_MGR_ID); 302 break; 303 304 case MLO_PEER_ASSOC_FAIL: 305 peer_assoc_fail = &msg->m.peer_assoc_fail; 306 wlan_objmgr_peer_release_ref(peer_assoc_fail->peer, 307 WLAN_MLO_MGR_ID); 308 break; 309 310 case MLO_PEER_DISCONNECT: 311 peer_disconn = &msg->m.peer_disconn; 312 wlan_objmgr_peer_release_ref(peer_disconn->peer, 313 WLAN_MLO_MGR_ID); 314 break; 315 316 case MLO_PEER_DEAUTH: 317 peer_deauth = &msg->m.peer_deauth; 318 wlan_objmgr_peer_release_ref(peer_deauth->peer, 319 WLAN_MLO_MGR_ID); 320 break; 321 322 case MLO_PEER_PENDING_AUTH: 323 peer_auth = &msg->m.peer_auth; 324 mlo_peer_free_auth_param(peer_auth->auth_params); 325 break; 326 327 default: 328 break; 329 } 330 qdf_mem_free(msg); 331 } 332 333 static void mlo_msgq_msg_flush(void) 334 { 335 struct ctxt_switch_mgr *msgq_ctx; 336 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 337 qdf_list_node_t *msgbuf_node = NULL; 338 struct mlo_ctxt_switch_msg_s *msg; 339 QDF_STATUS status; 340 341 if (!mlo_ctx) 342 return; 343 344 msgq_ctx = mlo_ctx->msgq_ctx; 345 do { 346 msg = NULL; 347 qdf_spin_lock_bh(&msgq_ctx->ctxt_lock); 348 status = qdf_list_peek_front(&msgq_ctx->msgq_list, 349 &msgbuf_node); 350 if (status != QDF_STATUS_E_EMPTY) { 351 qdf_list_remove_node(&msgq_ctx->msgq_list, 352 msgbuf_node); 353 msg = qdf_container_of(msgbuf_node, 354 struct mlo_ctxt_switch_msg_s, 355 node); 356 } 357 qdf_spin_unlock_bh(&msgq_ctx->ctxt_lock); 358 359 if (!msg) 360 break; 361 362 mlo_msgq_msg_flush_hdlr(msg); 363 364 } while (true); 365 } 366 367 static void mlo_msgq_msg_handler(void *arg) 368 { 369 struct ctxt_switch_mgr *msgq_ctx; 370 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 371 qdf_list_node_t *msgbuf_node = NULL; 372 struct mlo_ctxt_switch_msg_s *msg; 373 QDF_STATUS status; 374 375 if (!mlo_ctx) 376 return; 377 378 msgq_ctx = mlo_ctx->msgq_ctx; 379 do { 380 msg = NULL; 381 qdf_spin_lock_bh(&msgq_ctx->ctxt_lock); 382 status = qdf_list_peek_front(&msgq_ctx->msgq_list, 383 &msgbuf_node); 384 if (status != QDF_STATUS_E_EMPTY) { 385 qdf_list_remove_node(&msgq_ctx->msgq_list, 386 msgbuf_node); 387 msg = qdf_container_of(msgbuf_node, 388 struct mlo_ctxt_switch_msg_s, 389 node); 390 } else { 391 msgq_ctx->timer_started = false; 392 } 393 qdf_spin_unlock_bh(&msgq_ctx->ctxt_lock); 394 395 if (!msg) 396 break; 397 398 mlo_msgq_msg_process_hdlr(msg); 399 400 } while (true); 401 } 402 403 void mlo_msgq_init(void) 404 { 405 struct ctxt_switch_mgr *msgq_ctx; 406 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 407 408 msgq_ctx = qdf_mem_malloc(sizeof(*msgq_ctx)); 409 if (!msgq_ctx) { 410 mlo_err(" message queue context allocation failed"); 411 return; 412 } 413 414 qdf_spinlock_create(&msgq_ctx->ctxt_lock); 415 /* Initialize timer with timeout handler */ 416 qdf_timer_init(NULL, &msgq_ctx->ctxt_mgr_timer, 417 mlo_msgq_msg_handler, 418 NULL, QDF_TIMER_TYPE_WAKE_APPS); 419 420 msgq_ctx->timer_started = false; 421 msgq_ctx->allow_msg = true; 422 qdf_list_create(&msgq_ctx->msgq_list, MLO_MAX_MSGQ_SIZE); 423 424 mlo_ctx->msgq_ctx = msgq_ctx; 425 } 426 427 void mlo_msgq_free(void) 428 { 429 struct ctxt_switch_mgr *msgq_ctx; 430 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 431 432 if (!mlo_ctx) 433 return; 434 435 msgq_ctx = mlo_ctx->msgq_ctx; 436 437 msgq_ctx->timer_started = false; 438 msgq_ctx->allow_msg = false; 439 mlo_msgq_msg_flush(); 440 qdf_list_destroy(&msgq_ctx->msgq_list); 441 qdf_timer_free(&msgq_ctx->ctxt_mgr_timer); 442 qdf_spinlock_destroy(&msgq_ctx->ctxt_lock); 443 qdf_mem_free(msgq_ctx); 444 } 445 #endif 446