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 18 #include "wlan_mlo_mgr_main.h" 19 #include "qdf_module.h" 20 #include "qdf_types.h" 21 #include "wlan_cmn.h" 22 #include "wlan_mlo_mgr_msgq.h" 23 #include "wlan_objmgr_peer_obj.h" 24 #include "wlan_mlo_mgr_peer.h" 25 #include "wlan_mlo_mgr_ap.h" 26 #include "wlan_crypto_global_api.h" 27 28 static void mlo_partner_peer_create_post(struct wlan_mlo_dev_context *ml_dev, 29 struct wlan_objmgr_vdev *vdev_link, 30 struct wlan_mlo_peer_context *ml_peer, 31 qdf_nbuf_t frm_buf, 32 struct mlo_partner_info *ml_info) 33 { 34 struct peer_create_notif_s peer_create; 35 QDF_STATUS status; 36 uint8_t i; 37 uint8_t link_id; 38 39 if (wlan_objmgr_vdev_try_get_ref(vdev_link, WLAN_MLO_MGR_ID) == 40 QDF_STATUS_SUCCESS) { 41 peer_create.vdev_link = vdev_link; 42 } else { 43 mlo_err("VDEV is not in created state"); 44 return; 45 } 46 47 wlan_mlo_peer_get_ref(ml_peer); 48 peer_create.ml_peer = ml_peer; 49 link_id = wlan_vdev_get_link_id(vdev_link); 50 for (i = 0; i < ml_info->num_partner_links; i++) { 51 if (link_id != ml_info->partner_link_info[i].link_id) 52 continue; 53 54 qdf_copy_macaddr(&peer_create.addr, 55 &ml_info->partner_link_info[i].link_addr); 56 break; 57 } 58 59 status = mlo_peer_create_get_frm_buf(ml_peer, &peer_create, frm_buf); 60 61 if (QDF_IS_STATUS_ERROR(status)) { 62 wlan_mlo_peer_release_ref(ml_peer); 63 wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID); 64 mlo_err("nbuf clone is failed"); 65 return; 66 } 67 68 status = mlo_msgq_post(MLO_PEER_CREATE, ml_dev, &peer_create); 69 if (status != QDF_STATUS_SUCCESS) { 70 qdf_nbuf_free(frm_buf); 71 wlan_mlo_peer_release_ref(ml_peer); 72 wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID); 73 } 74 } 75 76 static void mlo_link_peer_assoc_notify(struct wlan_mlo_dev_context *ml_dev, 77 struct wlan_objmgr_peer *peer) 78 { 79 struct peer_assoc_notify_s peer_assoc; 80 QDF_STATUS status; 81 82 peer_assoc.peer = peer; 83 status = mlo_msgq_post(MLO_PEER_ASSOC, ml_dev, &peer_assoc); 84 if (status != QDF_STATUS_SUCCESS) 85 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 86 } 87 88 static void mlo_link_peer_send_assoc_fail(struct wlan_mlo_dev_context *ml_dev, 89 struct wlan_objmgr_peer *peer) 90 { 91 struct peer_assoc_fail_notify_s peer_assoc_fail; 92 QDF_STATUS status; 93 94 peer_assoc_fail.peer = peer; 95 status = mlo_msgq_post(MLO_PEER_ASSOC_FAIL, ml_dev, &peer_assoc_fail); 96 if (status != QDF_STATUS_SUCCESS) 97 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 98 } 99 100 static void mlo_link_peer_disconnect_notify(struct wlan_mlo_dev_context *ml_dev, 101 struct wlan_objmgr_peer *peer) 102 { 103 struct peer_discon_notify_s peer_disconn; 104 QDF_STATUS status; 105 struct wlan_objmgr_vdev *vdev; 106 enum QDF_OPMODE opmode; 107 108 vdev = wlan_peer_get_vdev(peer); 109 opmode = wlan_vdev_mlme_get_opmode(vdev); 110 111 if (opmode == QDF_SAP_MODE) { 112 peer_disconn.peer = peer; 113 status = mlo_msgq_post(MLO_PEER_DISCONNECT, ml_dev, 114 &peer_disconn); 115 if (status != QDF_STATUS_SUCCESS) 116 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 117 } else { 118 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 119 } 120 } 121 122 static void mlo_link_peer_deauth_init(struct wlan_mlo_dev_context *ml_dev, 123 struct wlan_objmgr_peer *peer) 124 { 125 struct peer_deauth_notify_s peer_deauth; 126 QDF_STATUS status; 127 128 peer_deauth.peer = peer; 129 status = mlo_msgq_post(MLO_PEER_DEAUTH, ml_dev, &peer_deauth); 130 if (status != QDF_STATUS_SUCCESS) 131 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 132 } 133 134 #ifdef UMAC_MLO_AUTH_DEFER 135 static void mlo_peer_process_pending_auth(struct wlan_mlo_dev_context *ml_dev, 136 struct wlan_mlo_peer_context *ml_peer) 137 { 138 struct peer_auth_process_notif_s peer_auth; 139 struct mlpeer_auth_params *recv_auth; 140 uint8_t i; 141 QDF_STATUS status; 142 143 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 144 mlo_peer_lock_acquire(ml_peer); 145 recv_auth = ml_peer->pending_auth[i]; 146 if (!recv_auth) { 147 mlo_peer_lock_release(ml_peer); 148 continue; 149 } 150 peer_auth.auth_params = recv_auth; 151 ml_peer->pending_auth[i] = NULL; 152 153 mlo_peer_lock_release(ml_peer); 154 155 status = mlo_msgq_post(MLO_PEER_PENDING_AUTH, ml_dev, 156 &peer_auth); 157 if (QDF_IS_STATUS_ERROR(status)) 158 mlo_peer_free_auth_param(peer_auth.auth_params); 159 } 160 } 161 #else 162 static void mlo_peer_process_pending_auth(struct wlan_mlo_dev_context *ml_dev, 163 struct wlan_mlo_peer_context *ml_peer) 164 { 165 } 166 #endif 167 168 QDF_STATUS 169 wlan_mlo_peer_is_disconnect_progress(struct wlan_mlo_peer_context *ml_peer) 170 { 171 QDF_STATUS status; 172 173 if (!ml_peer) 174 return QDF_STATUS_E_FAILURE; 175 176 mlo_peer_lock_acquire(ml_peer); 177 178 if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) 179 status = QDF_STATUS_SUCCESS; 180 else 181 status = QDF_STATUS_E_FAILURE; 182 183 mlo_peer_lock_release(ml_peer); 184 185 return status; 186 } 187 188 QDF_STATUS wlan_mlo_peer_is_assoc_done(struct wlan_mlo_peer_context *ml_peer) 189 { 190 QDF_STATUS status; 191 192 if (!ml_peer) 193 return QDF_STATUS_E_FAILURE; 194 195 mlo_peer_lock_acquire(ml_peer); 196 197 if (ml_peer->mlpeer_state == ML_PEER_ASSOC_DONE) 198 status = QDF_STATUS_SUCCESS; 199 else 200 status = QDF_STATUS_E_FAILURE; 201 202 mlo_peer_lock_release(ml_peer); 203 204 return status; 205 } 206 207 struct wlan_objmgr_peer *wlan_mlo_peer_get_assoc_peer( 208 struct wlan_mlo_peer_context *ml_peer) 209 { 210 struct wlan_mlo_link_peer_entry *peer_entry; 211 struct wlan_objmgr_peer *assoc_peer = NULL; 212 213 if (!ml_peer) 214 return NULL; 215 216 mlo_peer_lock_acquire(ml_peer); 217 218 peer_entry = &ml_peer->peer_list[0]; 219 220 if (peer_entry->link_peer) 221 assoc_peer = peer_entry->link_peer; 222 223 mlo_peer_lock_release(ml_peer); 224 225 return assoc_peer; 226 } 227 228 bool mlo_peer_is_assoc_peer(struct wlan_mlo_peer_context *ml_peer, 229 struct wlan_objmgr_peer *peer) 230 { 231 struct wlan_mlo_link_peer_entry *peer_entry; 232 bool is_assoc_peer = false; 233 234 if (!ml_peer || !peer) 235 return is_assoc_peer; 236 237 peer_entry = &ml_peer->peer_list[0]; 238 239 if (peer_entry->link_peer != peer) 240 is_assoc_peer = true; 241 242 return is_assoc_peer; 243 } 244 245 bool wlan_mlo_peer_is_assoc_peer(struct wlan_mlo_peer_context *ml_peer, 246 struct wlan_objmgr_peer *peer) 247 { 248 bool is_assoc_peer = false; 249 250 if (!ml_peer || !peer) 251 return is_assoc_peer; 252 253 mlo_peer_lock_acquire(ml_peer); 254 255 is_assoc_peer = mlo_peer_is_assoc_peer(ml_peer, peer); 256 257 mlo_peer_lock_release(ml_peer); 258 259 return is_assoc_peer; 260 } 261 262 void wlan_mlo_partner_peer_assoc_post(struct wlan_objmgr_peer *assoc_peer) 263 { 264 struct wlan_mlo_dev_context *ml_dev; 265 struct wlan_mlo_peer_context *ml_peer; 266 struct wlan_objmgr_peer *link_peer; 267 struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS]; 268 struct wlan_mlo_link_peer_entry *peer_entry; 269 uint16_t i; 270 271 ml_peer = assoc_peer->mlo_peer_ctx; 272 if (!ml_peer) 273 return; 274 275 mlo_peer_lock_acquire(ml_peer); 276 277 if (ml_peer->mlpeer_state != ML_PEER_CREATED) { 278 mlo_peer_lock_release(ml_peer); 279 return; 280 } 281 282 ml_peer->mlpeer_state = ML_PEER_ASSOC_DONE; 283 ml_dev = ml_peer->ml_dev; 284 285 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 286 link_peers[i] = NULL; 287 peer_entry = &ml_peer->peer_list[i]; 288 289 if (!peer_entry->link_peer) 290 continue; 291 292 if (peer_entry->link_peer == assoc_peer) 293 continue; 294 295 link_peer = peer_entry->link_peer; 296 297 if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) != 298 QDF_STATUS_SUCCESS) 299 continue; 300 301 link_peers[i] = link_peer; 302 } 303 mlo_peer_lock_release(ml_peer); 304 305 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 306 if (!link_peers[i]) 307 continue; 308 309 /* Prepare and queue message */ 310 mlo_link_peer_assoc_notify(ml_dev, link_peers[i]); 311 } 312 } 313 314 void 315 wlan_mlo_peer_deauth_init(struct wlan_mlo_peer_context *ml_peer) 316 { 317 struct wlan_mlo_dev_context *ml_dev; 318 struct wlan_objmgr_peer *link_peer; 319 struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS]; 320 struct wlan_mlo_link_peer_entry *peer_entry; 321 uint16_t i; 322 323 if (!ml_peer) 324 return; 325 326 mlo_peer_lock_acquire(ml_peer); 327 328 if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) { 329 mlo_peer_lock_release(ml_peer); 330 return; 331 } 332 333 ml_dev = ml_peer->ml_dev; 334 335 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 336 link_peers[i] = NULL; 337 peer_entry = &ml_peer->peer_list[i]; 338 if (!peer_entry->link_peer) 339 continue; 340 341 link_peer = peer_entry->link_peer; 342 /* Skip Deauth if PMF is enabled for the station */ 343 if ((i == 0) && 344 (wlan_crypto_is_pmf_enabled(wlan_peer_get_vdev(link_peer), 345 link_peer))) { 346 mlo_peer_lock_release(ml_peer); 347 return; 348 } 349 350 if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) != 351 QDF_STATUS_SUCCESS) 352 continue; 353 354 link_peers[i] = link_peer; 355 } 356 357 ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED; 358 359 mlo_peer_lock_release(ml_peer); 360 361 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 362 if (!link_peers[i]) 363 continue; 364 365 /* Prepare and queue message */ 366 if (i == 0) 367 mlo_link_peer_deauth_init(ml_dev, link_peers[i]); 368 else 369 mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]); 370 } 371 372 return; 373 } 374 375 void 376 wlan_mlo_partner_peer_create_failed_notify( 377 struct wlan_mlo_peer_context *ml_peer) 378 { 379 struct wlan_mlo_dev_context *ml_dev; 380 struct wlan_objmgr_peer *link_peer; 381 struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS]; 382 struct wlan_mlo_link_peer_entry *peer_entry; 383 uint16_t i; 384 385 if (!ml_peer) 386 return; 387 388 mlo_peer_lock_acquire(ml_peer); 389 390 if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) { 391 mlo_peer_lock_release(ml_peer); 392 return; 393 } 394 395 ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED; 396 ml_dev = ml_peer->ml_dev; 397 398 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 399 link_peers[i] = NULL; 400 peer_entry = &ml_peer->peer_list[i]; 401 if (!peer_entry->link_peer) 402 continue; 403 404 link_peer = peer_entry->link_peer; 405 if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) != 406 QDF_STATUS_SUCCESS) 407 continue; 408 409 link_peers[i] = link_peer; 410 } 411 mlo_peer_lock_release(ml_peer); 412 413 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 414 if (!link_peers[i]) 415 continue; 416 417 /* Prepare and queue message */ 418 if (i == 0) 419 mlo_link_peer_send_assoc_fail(ml_dev, link_peers[i]); 420 else 421 mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]); 422 } 423 } 424 425 void wlan_mlo_partner_peer_disconnect_notify(struct wlan_objmgr_peer *src_peer) 426 { 427 struct wlan_mlo_dev_context *ml_dev; 428 struct wlan_mlo_peer_context *ml_peer; 429 struct wlan_objmgr_peer *link_peer; 430 struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS]; 431 struct wlan_mlo_link_peer_entry *peer_entry; 432 struct wlan_objmgr_vdev *vdev = NULL; 433 uint16_t i; 434 435 ml_peer = src_peer->mlo_peer_ctx; 436 if (!ml_peer) 437 return; 438 439 mlo_peer_lock_acquire(ml_peer); 440 441 if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) { 442 mlo_peer_lock_release(ml_peer); 443 return; 444 } 445 446 ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED; 447 448 vdev = wlan_peer_get_vdev(src_peer); 449 if (!vdev || wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) { 450 mlo_peer_lock_release(ml_peer); 451 return; 452 } 453 454 ml_dev = ml_peer->ml_dev; 455 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 456 link_peers[i] = NULL; 457 peer_entry = &ml_peer->peer_list[i]; 458 if (!peer_entry->link_peer) { 459 mlo_debug("link peer is null"); 460 continue; 461 } 462 463 if (peer_entry->link_peer == src_peer) 464 continue; 465 466 link_peer = peer_entry->link_peer; 467 if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) != 468 QDF_STATUS_SUCCESS) 469 continue; 470 471 link_peers[i] = link_peer; 472 } 473 mlo_peer_lock_release(ml_peer); 474 475 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 476 if (!link_peers[i]) 477 continue; 478 479 /* Prepare and queue message */ 480 mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]); 481 } 482 } 483 484 static void mlo_peer_populate_link_peer( 485 struct wlan_mlo_peer_context *ml_peer, 486 struct wlan_objmgr_peer *link_peer) 487 { 488 mlo_peer_lock_acquire(ml_peer); 489 wlan_mlo_peer_get_ref(ml_peer); 490 link_peer->mlo_peer_ctx = ml_peer; 491 mlo_peer_lock_release(ml_peer); 492 } 493 494 static void mlo_reset_link_peer( 495 struct wlan_mlo_peer_context *ml_peer, 496 struct wlan_objmgr_peer *link_peer) 497 { 498 mlo_peer_lock_acquire(ml_peer); 499 link_peer->mlo_peer_ctx = NULL; 500 wlan_peer_clear_mlo(link_peer); 501 mlo_peer_lock_release(ml_peer); 502 } 503 504 static void mlo_peer_free(struct wlan_mlo_peer_context *ml_peer) 505 { 506 struct wlan_mlo_dev_context *ml_dev; 507 508 ml_dev = ml_peer->ml_dev; 509 if (!ml_dev) { 510 mlo_err("ML DEV is NULL"); 511 return; 512 } 513 514 mlo_peer_lock_destroy(ml_peer); 515 mlo_ap_ml_peerid_free(ml_peer->mlo_peer_id); 516 mlo_peer_free_aid(ml_dev, ml_peer); 517 mlo_peer_free_primary_umac(ml_dev, ml_peer); 518 qdf_mem_free(ml_peer); 519 } 520 521 void mlo_peer_cleanup(struct wlan_mlo_peer_context *ml_peer) 522 { 523 struct wlan_mlo_dev_context *ml_dev; 524 525 if (!ml_peer) { 526 mlo_err("ML PEER is NULL"); 527 return; 528 } 529 ml_dev = ml_peer->ml_dev; 530 if (!ml_dev) { 531 mlo_err("ML DEV is NULL"); 532 return; 533 } 534 535 mlo_dev_mlpeer_detach(ml_dev, ml_peer); 536 /* If any Auth req is received during ML peer delete */ 537 mlo_peer_process_pending_auth(ml_dev, ml_peer); 538 mlo_peer_free(ml_peer); 539 } 540 541 static QDF_STATUS mlo_peer_attach_link_peer( 542 struct wlan_mlo_peer_context *ml_peer, 543 struct wlan_objmgr_peer *link_peer, 544 qdf_nbuf_t frm_buf) 545 { 546 struct wlan_mlo_link_peer_entry *peer_entry; 547 QDF_STATUS status = QDF_STATUS_E_RESOURCES; 548 struct wlan_objmgr_pdev *pdev; 549 struct wlan_objmgr_vdev *vdev; 550 uint16_t i; 551 552 if (!link_peer) 553 return QDF_STATUS_E_FAILURE; 554 555 vdev = wlan_peer_get_vdev(link_peer); 556 if (!vdev) 557 return QDF_STATUS_E_FAILURE; 558 559 mlo_peer_lock_acquire(ml_peer); 560 561 if (ml_peer->mlpeer_state != ML_PEER_CREATED) { 562 mlo_peer_lock_release(ml_peer); 563 mlo_err("ML Peer " QDF_MAC_ADDR_FMT " is not in created state (state %d)", 564 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 565 ml_peer->mlpeer_state); 566 return status; 567 } 568 569 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 570 peer_entry = &ml_peer->peer_list[i]; 571 if (peer_entry->link_peer) 572 continue; 573 574 if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) != 575 QDF_STATUS_SUCCESS) { 576 mlo_err("ML Peer " QDF_MAC_ADDR_FMT ", link peer " QDF_MAC_ADDR_FMT " is not in valid state", 577 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 578 QDF_MAC_ADDR_REF 579 (wlan_peer_get_macaddr(link_peer))); 580 break; 581 } 582 peer_entry->link_peer = link_peer; 583 qdf_copy_macaddr(&peer_entry->link_addr, 584 (struct qdf_mac_addr *)&link_peer->macaddr[0]); 585 586 peer_entry->link_ix = wlan_vdev_get_link_id(vdev); 587 pdev = wlan_vdev_get_pdev(wlan_peer_get_vdev(link_peer)); 588 peer_entry->hw_link_id = wlan_mlo_get_pdev_hw_link_id(pdev); 589 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 590 if (frm_buf) 591 peer_entry->assoc_rsp_buf = frm_buf; 592 else 593 peer_entry->assoc_rsp_buf = NULL; 594 595 status = QDF_STATUS_SUCCESS; 596 break; 597 } 598 if (QDF_IS_STATUS_SUCCESS(status)) 599 ml_peer->link_peer_cnt++; 600 601 mlo_peer_lock_release(ml_peer); 602 603 return status; 604 } 605 606 qdf_nbuf_t mlo_peer_get_link_peer_assoc_resp_buf( 607 struct wlan_mlo_peer_context *ml_peer, 608 uint8_t link_ix) 609 { 610 struct wlan_mlo_link_peer_entry *peer_entry; 611 qdf_nbuf_t frm_buf = NULL; 612 uint8_t i; 613 614 if (!ml_peer) 615 return NULL; 616 617 if (link_ix > MAX_MLO_LINK_PEERS) 618 return NULL; 619 620 mlo_peer_lock_acquire(ml_peer); 621 if ((ml_peer->mlpeer_state != ML_PEER_CREATED) && 622 (ml_peer->mlpeer_state != ML_PEER_ASSOC_DONE)) { 623 mlo_peer_lock_release(ml_peer); 624 return NULL; 625 } 626 627 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 628 peer_entry = &ml_peer->peer_list[i]; 629 630 if (!peer_entry->link_peer) 631 continue; 632 633 if (peer_entry->link_ix == link_ix) { 634 frm_buf = qdf_nbuf_clone(peer_entry->assoc_rsp_buf); 635 break; 636 } 637 } 638 mlo_peer_lock_release(ml_peer); 639 640 return frm_buf; 641 } 642 643 void wlan_mlo_peer_free_all_link_assoc_resp_buf( 644 struct wlan_objmgr_peer *link_peer) 645 { 646 struct wlan_mlo_link_peer_entry *peer_entry; 647 struct wlan_mlo_peer_context *ml_peer; 648 uint8_t i; 649 650 ml_peer = link_peer->mlo_peer_ctx; 651 if (!ml_peer) 652 return; 653 654 mlo_peer_lock_acquire(ml_peer); 655 656 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 657 peer_entry = &ml_peer->peer_list[i]; 658 659 if (peer_entry->assoc_rsp_buf) { 660 qdf_nbuf_free(peer_entry->assoc_rsp_buf); 661 peer_entry->assoc_rsp_buf = NULL; 662 } 663 } 664 mlo_peer_lock_release(ml_peer); 665 } 666 667 static QDF_STATUS mlo_peer_detach_link_peer( 668 struct wlan_mlo_peer_context *ml_peer, 669 struct wlan_objmgr_peer *link_peer) 670 { 671 struct wlan_mlo_link_peer_entry *peer_entry; 672 QDF_STATUS status = QDF_STATUS_E_RESOURCES; 673 uint16_t i; 674 675 mlo_peer_lock_acquire(ml_peer); 676 677 if (ml_peer->mlpeer_state != ML_PEER_DISCONN_INITIATED) { 678 mlo_peer_lock_release(ml_peer); 679 return status; 680 } 681 682 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 683 peer_entry = &ml_peer->peer_list[i]; 684 if (!peer_entry->link_peer) 685 continue; 686 687 if (peer_entry->link_peer != link_peer) 688 continue; 689 690 if (peer_entry->assoc_rsp_buf) { 691 qdf_nbuf_free(peer_entry->assoc_rsp_buf); 692 peer_entry->assoc_rsp_buf = NULL; 693 } 694 695 wlan_objmgr_peer_release_ref(link_peer, WLAN_MLO_MGR_ID); 696 peer_entry->link_peer = NULL; 697 ml_peer->link_peer_cnt--; 698 status = QDF_STATUS_SUCCESS; 699 break; 700 } 701 mlo_peer_lock_release(ml_peer); 702 703 return status; 704 } 705 706 static QDF_STATUS mlo_dev_get_link_vdevs( 707 struct wlan_objmgr_vdev *vdev, 708 struct wlan_mlo_dev_context *ml_dev, 709 struct mlo_partner_info *ml_info, 710 struct wlan_objmgr_vdev *link_vdevs[]) 711 { 712 uint16_t i, j; 713 struct wlan_objmgr_vdev *vdev_link; 714 uint8_t link_id; 715 716 if (!ml_dev) { 717 mlo_err("ml_dev is null"); 718 return QDF_STATUS_E_INVAL; 719 } 720 721 if (!ml_info) { 722 mlo_err("ml_info is null"); 723 return QDF_STATUS_E_INVAL; 724 } 725 726 mlo_debug("num_partner_links %d", ml_info->num_partner_links); 727 for (i = 0; i < ml_info->num_partner_links; i++) { 728 link_id = ml_info->partner_link_info[i].link_id; 729 vdev_link = mlo_get_vdev_by_link_id(vdev, link_id); 730 if (vdev_link) { 731 link_vdevs[i] = vdev_link; 732 } else { 733 /* release ref which were taken before failure */ 734 for (j = 0; j < i; j++) { 735 vdev_link = link_vdevs[j]; 736 if (!vdev_link) 737 continue; 738 739 wlan_objmgr_vdev_release_ref(vdev_link, 740 WLAN_MLO_MGR_ID); 741 } 742 return QDF_STATUS_E_INVAL; 743 } 744 } 745 746 return QDF_STATUS_SUCCESS; 747 } 748 749 static void mlo_dev_release_link_vdevs( 750 struct wlan_objmgr_vdev *link_vdevs[]) 751 { 752 uint16_t i; 753 struct wlan_objmgr_vdev *vdev_link; 754 755 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 756 vdev_link = link_vdevs[i]; 757 if (!vdev_link) 758 continue; 759 760 wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID); 761 } 762 } 763 764 #ifdef WLAN_FEATURE_11BE 765 static void 766 wlan_mlo_peer_set_t2lm_enable_val(struct wlan_mlo_peer_context *ml_peer, 767 struct mlo_partner_info *ml_info) 768 { 769 ml_peer->t2lm_policy.t2lm_enable_val = ml_info->t2lm_enable_val; 770 } 771 #else 772 static void 773 wlan_mlo_peer_set_t2lm_enable_val(struct wlan_mlo_peer_context *ml_peer, 774 struct mlo_partner_info *ml_info) 775 {} 776 #endif /* WLAN_FEATURE_11BE */ 777 778 QDF_STATUS wlan_mlo_peer_create(struct wlan_objmgr_vdev *vdev, 779 struct wlan_objmgr_peer *link_peer, 780 struct mlo_partner_info *ml_info, 781 qdf_nbuf_t frm_buf, 782 uint16_t aid) 783 { 784 struct wlan_mlo_dev_context *ml_dev; 785 struct wlan_mlo_peer_context *ml_peer = NULL; 786 struct wlan_objmgr_vdev *link_vdevs[WLAN_UMAC_MLO_MAX_VDEVS] = { NULL }; 787 struct wlan_objmgr_vdev *vdev_link; 788 QDF_STATUS status; 789 uint16_t i; 790 struct wlan_objmgr_peer *assoc_peer; 791 792 /* get ML VDEV from VDEV */ 793 ml_dev = vdev->mlo_dev_ctx; 794 795 if (!ml_dev) { 796 mlo_err("ML dev ctx is NULL"); 797 return QDF_STATUS_E_NULL_VALUE; 798 } 799 800 /* Check resources of Partner VDEV */ 801 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) { 802 if (wlan_mlo_is_mld_ctx_exist( 803 (struct qdf_mac_addr *)&link_peer->mldaddr[0])) { 804 mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " is matching with one of the MLD address in the system", 805 ml_dev->mld_id, 806 QDF_MAC_ADDR_REF(link_peer->mldaddr)); 807 return QDF_STATUS_E_FAILURE; 808 } 809 status = mlo_dev_get_link_vdevs(vdev, ml_dev, 810 ml_info, link_vdevs); 811 if (QDF_IS_STATUS_ERROR(status)) { 812 mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " get link vdevs failed", 813 ml_dev->mld_id, 814 QDF_MAC_ADDR_REF(link_peer->mldaddr)); 815 return QDF_STATUS_E_FAILURE; 816 } 817 818 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 819 vdev_link = link_vdevs[i]; 820 if (!vdev_link) { 821 mlo_debug("vdev_link is null"); 822 continue; 823 } 824 825 if (wlan_vdev_is_mlo_peer_create_allowed(vdev_link) 826 != QDF_STATUS_SUCCESS) { 827 mlo_dev_release_link_vdevs(link_vdevs); 828 829 mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " create not allowed on link vdev %d", 830 ml_dev->mld_id, 831 QDF_MAC_ADDR_REF 832 (link_peer->mldaddr), 833 wlan_vdev_get_id(vdev_link)); 834 return QDF_STATUS_E_INVAL; 835 } 836 } 837 838 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 839 vdev_link = link_vdevs[i]; 840 if (vdev_link && (vdev_link != vdev) && 841 (wlan_vdev_get_peer_count(vdev_link) > 842 wlan_vdev_get_max_peer_count(vdev_link))) { 843 mlo_dev_release_link_vdevs(link_vdevs); 844 mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " Max peer count reached on link vdev %d", 845 ml_dev->mld_id, 846 QDF_MAC_ADDR_REF 847 (link_peer->mldaddr), 848 wlan_vdev_get_id(vdev_link)); 849 return QDF_STATUS_E_RESOURCES; 850 } 851 } 852 } 853 854 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) 855 ml_peer = wlan_mlo_get_mlpeer(ml_dev, 856 (struct qdf_mac_addr *)&link_peer->mldaddr[0]); 857 858 if (!ml_peer) { 859 /* Allocate MLO peer */ 860 ml_peer = qdf_mem_malloc(sizeof(*ml_peer)); 861 if (!ml_peer) { 862 mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " mem alloc failed", 863 ml_dev->mld_id, 864 QDF_MAC_ADDR_REF(link_peer->mldaddr)); 865 mlo_dev_release_link_vdevs(link_vdevs); 866 return QDF_STATUS_E_NOMEM; 867 } 868 869 qdf_atomic_init(&ml_peer->ref_cnt); 870 mlo_peer_lock_create(ml_peer); 871 ml_peer->ml_dev = ml_dev; 872 ml_peer->mlpeer_state = ML_PEER_CREATED; 873 ml_peer->max_links = ml_info->num_partner_links; 874 ml_peer->primary_umac_psoc_id = ML_PRIMARY_UMAC_ID_INVAL; 875 876 ml_peer->mlo_peer_id = mlo_ap_ml_peerid_alloc(); 877 if (ml_peer->mlo_peer_id == MLO_INVALID_PEER_ID) { 878 mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " invalid ml peer id", 879 ml_dev->mld_id, 880 QDF_MAC_ADDR_REF 881 (ml_peer->peer_mld_addr.bytes)); 882 mlo_peer_free(ml_peer); 883 mlo_dev_release_link_vdevs(link_vdevs); 884 return QDF_STATUS_E_RESOURCES; 885 } 886 887 qdf_copy_macaddr((struct qdf_mac_addr *)&ml_peer->peer_mld_addr, 888 (struct qdf_mac_addr *)&link_peer->mldaddr[0]); 889 wlan_mlo_peer_set_t2lm_enable_val(ml_peer, ml_info); 890 891 /* Allocate AID */ 892 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) { 893 if (aid == (uint16_t)-1) { 894 status = mlo_peer_allocate_aid(ml_dev, ml_peer); 895 if (status != QDF_STATUS_SUCCESS) { 896 mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " aid alloc failed", 897 ml_dev->mld_id, 898 QDF_MAC_ADDR_REF 899 (ml_peer->peer_mld_addr.bytes)); 900 mlo_peer_free(ml_peer); 901 mlo_dev_release_link_vdevs(link_vdevs); 902 return status; 903 } 904 } else { 905 ml_peer->assoc_id = aid; 906 } 907 } 908 } 909 910 /* Populate Link peer pointer, peer MAC address, 911 * MLD address. HW link ID, update ref count 912 */ 913 status = mlo_peer_attach_link_peer(ml_peer, link_peer, NULL); 914 if (QDF_IS_STATUS_ERROR(status)) { 915 mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " link peer attach failed", 916 ml_dev->mld_id, 917 QDF_MAC_ADDR_REF 918 (ml_peer->peer_mld_addr.bytes)); 919 mlo_peer_free(ml_peer); 920 mlo_dev_release_link_vdevs(link_vdevs); 921 return status; 922 } 923 924 /* Allocate Primary UMAC */ 925 mlo_peer_allocate_primary_umac(ml_dev, ml_peer, link_vdevs); 926 927 /* Store AID, MLO Peer pointer in link peer, take link peer ref count */ 928 mlo_peer_populate_link_peer(ml_peer, link_peer); 929 930 mlo_peer_populate_nawds_params(ml_peer, ml_info); 931 932 if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) || 933 ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) && 934 !wlan_vdev_mlme_is_mlo_link_vdev(vdev))) { 935 /* Attach MLO peer to ML Peer table */ 936 status = mlo_dev_mlpeer_attach(ml_dev, ml_peer); 937 if (status != QDF_STATUS_SUCCESS) { 938 mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " attach failed", 939 ml_dev->mld_id, 940 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); 941 mlo_reset_link_peer(ml_peer, link_peer); 942 wlan_objmgr_peer_release_ref(link_peer, 943 WLAN_MLO_MGR_ID); 944 mlo_peer_free(ml_peer); 945 mlo_dev_release_link_vdevs(link_vdevs); 946 return status; 947 } 948 } 949 950 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) { 951 /* Notify other vdevs about link peer creation */ 952 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 953 vdev_link = link_vdevs[i]; 954 if (!vdev_link) 955 continue; 956 957 if (vdev_link == vdev) 958 continue; 959 960 mlo_partner_peer_create_post(ml_dev, vdev_link, 961 ml_peer, frm_buf, ml_info); 962 } 963 } 964 mlo_dev_release_link_vdevs(link_vdevs); 965 mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " allocated %pK", 966 ml_dev->mld_id, 967 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 968 ml_peer); 969 970 /* 971 * wlan_mlo_peer_create() is trigggered after getting peer 972 * assoc confirm from FW. For single link MLO connection, it is 973 * OK to trigger assoc response from here. 974 */ 975 if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) && 976 (!wlan_mlo_peer_is_nawds(ml_peer))) { 977 if (ml_peer->max_links == ml_peer->link_peer_cnt) { 978 assoc_peer = ml_peer->peer_list[0].link_peer; 979 if (assoc_peer) 980 mlo_mlme_peer_assoc_resp(assoc_peer); 981 } 982 } 983 984 return QDF_STATUS_SUCCESS; 985 } 986 987 QDF_STATUS wlan_mlo_link_peer_attach(struct wlan_mlo_peer_context *ml_peer, 988 struct wlan_objmgr_peer *peer, 989 qdf_nbuf_t frm_buf) 990 { 991 QDF_STATUS status; 992 struct wlan_objmgr_peer *assoc_peer; 993 struct wlan_objmgr_vdev *vdev = NULL; 994 995 if (!ml_peer) 996 return QDF_STATUS_E_FAILURE; 997 998 vdev = wlan_peer_get_vdev(peer); 999 if (!vdev) 1000 return QDF_STATUS_E_FAILURE; 1001 1002 /* Populate Link peer pointer, peer MAC address, 1003 * MLD address. HW link ID, update ref count 1004 */ 1005 status = mlo_peer_attach_link_peer(ml_peer, peer, frm_buf); 1006 if (QDF_IS_STATUS_ERROR(status)) 1007 return status; 1008 1009 /* Store AID, MLO Peer pointer in link peer, take link peer ref count */ 1010 mlo_peer_populate_link_peer(ml_peer, peer); 1011 1012 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) { 1013 if (ml_peer->max_links == ml_peer->link_peer_cnt) { 1014 assoc_peer = ml_peer->peer_list[0].link_peer; 1015 if (assoc_peer) 1016 mlo_mlme_peer_assoc_resp(assoc_peer); 1017 } 1018 } 1019 1020 return status; 1021 } 1022 1023 QDF_STATUS wlan_mlo_link_peer_delete(struct wlan_objmgr_peer *peer) 1024 { 1025 struct wlan_mlo_peer_context *ml_peer; 1026 1027 ml_peer = peer->mlo_peer_ctx; 1028 1029 if (!ml_peer) 1030 return QDF_STATUS_E_NOENT; 1031 1032 mlo_reset_link_peer(ml_peer, peer); 1033 mlo_peer_detach_link_peer(ml_peer, peer); 1034 wlan_mlo_peer_release_ref(ml_peer); 1035 1036 return QDF_STATUS_SUCCESS; 1037 } 1038 1039 qdf_export_symbol(wlan_mlo_link_peer_delete); 1040 1041 qdf_nbuf_t mlo_peer_get_link_peer_assoc_req_buf( 1042 struct wlan_mlo_peer_context *ml_peer, 1043 uint8_t link_ix) 1044 { 1045 struct wlan_objmgr_peer *peer = NULL; 1046 qdf_nbuf_t assocbuf = NULL; 1047 1048 if (!ml_peer) 1049 return NULL; 1050 1051 peer = wlan_mlo_peer_get_assoc_peer(ml_peer); 1052 if (!peer) 1053 return NULL; 1054 1055 assocbuf = mlo_mlme_get_link_assoc_req(peer, link_ix); 1056 1057 return assocbuf; 1058 } 1059 1060 void wlan_mlo_peer_get_links_info(struct wlan_objmgr_peer *peer, 1061 struct mlo_tgt_partner_info *ml_links) 1062 { 1063 struct wlan_mlo_peer_context *ml_peer; 1064 struct wlan_mlo_link_peer_entry *peer_entry; 1065 struct wlan_objmgr_peer *link_peer; 1066 struct wlan_objmgr_vdev *link_vdev; 1067 uint8_t i, ix; 1068 1069 ml_peer = peer->mlo_peer_ctx; 1070 ml_links->num_partner_links = 0; 1071 1072 if (!ml_peer) 1073 return; 1074 1075 mlo_peer_lock_acquire(ml_peer); 1076 1077 if ((ml_peer->mlpeer_state != ML_PEER_CREATED) && 1078 (ml_peer->mlpeer_state != ML_PEER_ASSOC_DONE)) { 1079 mlo_peer_lock_release(ml_peer); 1080 return; 1081 } 1082 1083 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 1084 peer_entry = &ml_peer->peer_list[i]; 1085 link_peer = peer_entry->link_peer; 1086 1087 if (!link_peer) 1088 continue; 1089 1090 if (link_peer == peer) 1091 continue; 1092 1093 link_vdev = wlan_peer_get_vdev(link_peer); 1094 if (!link_vdev) 1095 continue; 1096 1097 if (ml_links->num_partner_links >= WLAN_UMAC_MLO_MAX_VDEVS) 1098 break; 1099 1100 ix = ml_links->num_partner_links; 1101 ml_links->link_info[ix].vdev_id = wlan_vdev_get_id(link_vdev); 1102 ml_links->link_info[ix].hw_mld_link_id = peer_entry->hw_link_id; 1103 ml_links->num_partner_links++; 1104 } 1105 mlo_peer_lock_release(ml_peer); 1106 } 1107 1108 qdf_export_symbol(wlan_mlo_peer_get_links_info); 1109 1110 void wlan_mlo_peer_get_partner_links_info(struct wlan_objmgr_peer *peer, 1111 struct mlo_partner_info *ml_links) 1112 { 1113 struct wlan_mlo_peer_context *ml_peer; 1114 struct wlan_mlo_link_peer_entry *peer_entry; 1115 struct wlan_objmgr_peer *link_peer; 1116 struct wlan_objmgr_vdev *link_vdev; 1117 uint8_t i, ix; 1118 1119 ml_peer = peer->mlo_peer_ctx; 1120 ml_links->num_partner_links = 0; 1121 1122 if (!ml_peer) 1123 return; 1124 1125 mlo_peer_lock_acquire(ml_peer); 1126 1127 if ((ml_peer->mlpeer_state != ML_PEER_CREATED) && 1128 (ml_peer->mlpeer_state != ML_PEER_ASSOC_DONE)) { 1129 mlo_peer_lock_release(ml_peer); 1130 return; 1131 } 1132 1133 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 1134 peer_entry = &ml_peer->peer_list[i]; 1135 link_peer = peer_entry->link_peer; 1136 1137 if (!link_peer) 1138 continue; 1139 1140 if (link_peer == peer) 1141 continue; 1142 1143 link_vdev = wlan_peer_get_vdev(link_peer); 1144 if (!link_vdev) 1145 continue; 1146 1147 if (ml_links->num_partner_links >= WLAN_UMAC_MLO_MAX_VDEVS) 1148 break; 1149 1150 ix = ml_links->num_partner_links; 1151 ml_links->partner_link_info[ix].link_id = peer_entry->link_ix; 1152 1153 qdf_copy_macaddr(&ml_links->partner_link_info[ix].link_addr, 1154 &peer_entry->link_addr); 1155 ml_links->num_partner_links++; 1156 } 1157 mlo_peer_lock_release(ml_peer); 1158 } 1159 1160 qdf_export_symbol(wlan_mlo_peer_get_partner_links_info); 1161 1162 #ifdef UMAC_SUPPORT_MLNAWDS 1163 bool wlan_mlo_peer_is_nawds(struct wlan_mlo_peer_context *ml_peer) 1164 { 1165 bool status = false; 1166 1167 if (!ml_peer) 1168 return status; 1169 1170 mlo_peer_lock_acquire(ml_peer); 1171 if (ml_peer->is_nawds_ml_peer) 1172 status = true; 1173 mlo_peer_lock_release(ml_peer); 1174 1175 return status; 1176 } 1177 1178 qdf_export_symbol(wlan_mlo_peer_is_nawds); 1179 #endif 1180 1181 #ifdef UMAC_MLO_AUTH_DEFER 1182 void mlo_peer_free_auth_param(struct mlpeer_auth_params *auth_params) 1183 { 1184 if (auth_params->rs) 1185 qdf_mem_free(auth_params->rs); 1186 1187 if (auth_params->wbuf) 1188 qdf_nbuf_free(auth_params->wbuf); 1189 1190 qdf_mem_free(auth_params); 1191 } 1192 1193 QDF_STATUS mlo_peer_link_auth_defer(struct wlan_mlo_peer_context *ml_peer, 1194 struct qdf_mac_addr *link_mac, 1195 struct mlpeer_auth_params *auth_params) 1196 { 1197 uint8_t i; 1198 uint8_t free_entries = 0; 1199 struct mlpeer_auth_params *recv_auth; 1200 QDF_STATUS status = QDF_STATUS_E_FAILURE; 1201 1202 if (!ml_peer) 1203 return status; 1204 1205 mlo_peer_lock_acquire(ml_peer); 1206 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 1207 recv_auth = ml_peer->pending_auth[i]; 1208 if (!recv_auth) { 1209 free_entries++; 1210 continue; 1211 } 1212 /* overwrite the entry with latest entry */ 1213 if (qdf_is_macaddr_equal(link_mac, &recv_auth->link_addr)) { 1214 mlo_peer_free_auth_param(recv_auth); 1215 ml_peer->pending_auth[i] = auth_params; 1216 mlo_peer_lock_release(ml_peer); 1217 1218 return QDF_STATUS_SUCCESS; 1219 } 1220 } 1221 1222 if (!free_entries) { 1223 mlo_peer_lock_release(ml_peer); 1224 return QDF_STATUS_E_FAILURE; 1225 } 1226 1227 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { 1228 recv_auth = ml_peer->pending_auth[i]; 1229 if (!recv_auth) { 1230 ml_peer->pending_auth[i] = auth_params; 1231 status = QDF_STATUS_SUCCESS; 1232 break; 1233 } 1234 } 1235 mlo_peer_lock_release(ml_peer); 1236 1237 return status; 1238 } 1239 #endif 1240