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