1 /* 2 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. 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 TID to Link mapping related functionality 19 */ 20 #include <wlan_cmn.h> 21 #include <wlan_cm_public_struct.h> 22 #include "wlan_t2lm_api.h" 23 #include <wlan_mlo_t2lm.h> 24 #include "wlan_cm_api.h" 25 #include "wlan_mlo_mgr_roam.h" 26 27 #define T2LM_MIN_DIALOG_TOKEN 1 28 #define T2LM_MAX_DIALOG_TOKEN 0xFF 29 30 static 31 const char *t2lm_get_event_str(enum wlan_t2lm_evt event) 32 { 33 if (event > WLAN_T2LM_EV_ACTION_FRAME_MAX) 34 return ""; 35 36 switch (event) { 37 CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_RX_REQ); 38 CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_TX_RESP); 39 CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_TX_REQ); 40 CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_RX_RESP); 41 CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN); 42 CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_TX_TEARDOWN); 43 default: 44 return "Unknown"; 45 } 46 } 47 48 static 49 bool t2lm_is_valid_t2lm_link_map(struct wlan_objmgr_vdev *vdev, 50 struct wlan_t2lm_onging_negotiation_info *t2lm, 51 enum wlan_t2lm_direction *valid_dir) 52 { 53 uint8_t i, tid = 0; 54 enum wlan_t2lm_direction dir = WLAN_T2LM_INVALID_DIRECTION; 55 uint16_t ieee_link_mask = 0; 56 uint16_t provisioned_links = 0; 57 bool is_valid_link_mask = false; 58 struct wlan_objmgr_vdev *ml_vdev = NULL; 59 struct wlan_objmgr_vdev *ml_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL}; 60 uint16_t ml_vdev_cnt = 0; 61 62 /* Get the valid hw_link_id map from ML vdev list */ 63 mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, ml_vdev_list); 64 if (!ml_vdev_cnt) { 65 t2lm_err("Number of VDEVs under MLD is reported as 0"); 66 return false; 67 } 68 69 for (i = 0; i < ml_vdev_cnt; i++) { 70 ml_vdev = ml_vdev_list[i]; 71 if (!ml_vdev || !wlan_cm_is_vdev_connected(ml_vdev)) { 72 t2lm_err("ML vdev is null"); 73 continue; 74 } 75 76 ieee_link_mask |= BIT(wlan_vdev_get_link_id(ml_vdev)); 77 } 78 79 if (ml_vdev_cnt) { 80 for (i = 0; i < ml_vdev_cnt; i++) 81 mlo_release_vdev_ref(ml_vdev_list[i]); 82 } 83 84 /* Check if the configured hw_link_id map is valid */ 85 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 86 if (t2lm->t2lm_info[dir].direction == 87 WLAN_T2LM_INVALID_DIRECTION) 88 continue; 89 90 if (t2lm->t2lm_info[dir].default_link_mapping) { 91 is_valid_link_mask = true; 92 continue; 93 } 94 95 for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) { 96 provisioned_links = 97 t2lm->t2lm_info[dir].ieee_link_map_tid[tid]; 98 99 for (i = 0; i < WLAN_T2LM_MAX_NUM_LINKS; i++) { 100 if (!(provisioned_links & BIT(i))) 101 continue; 102 103 if (ieee_link_mask & BIT(i)) { 104 is_valid_link_mask = true; 105 *valid_dir = dir; 106 continue; 107 } else { 108 return false; 109 } 110 } 111 } 112 } 113 114 return is_valid_link_mask; 115 } 116 117 static uint8_t 118 t2lm_gen_dialog_token(struct wlan_mlo_peer_t2lm_policy *t2lm_policy) 119 { 120 if (!t2lm_policy) 121 return 0; 122 123 if (t2lm_policy->self_gen_dialog_token == T2LM_MAX_DIALOG_TOKEN) 124 /* wrap is ok */ 125 t2lm_policy->self_gen_dialog_token = T2LM_MIN_DIALOG_TOKEN; 126 else 127 t2lm_policy->self_gen_dialog_token += 1; 128 129 t2lm_debug("gen dialog token %d", t2lm_policy->self_gen_dialog_token); 130 return t2lm_policy->self_gen_dialog_token; 131 } 132 133 QDF_STATUS t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev, 134 struct wlan_objmgr_peer *peer, 135 void *event_data, uint8_t *token) 136 { 137 struct wlan_t2lm_onging_negotiation_info t2lm_req = {0}; 138 struct wlan_t2lm_info *t2lm_info; 139 enum wlan_t2lm_direction dir = WLAN_T2LM_MAX_DIRECTION; 140 bool valid_map = false; 141 QDF_STATUS status; 142 struct wlan_mlo_peer_context *ml_peer; 143 144 ml_peer = peer->mlo_peer_ctx; 145 if (!ml_peer) 146 return QDF_STATUS_E_FAILURE; 147 148 status = wlan_mlo_parse_t2lm_action_frame(&t2lm_req, event_data, 149 WLAN_T2LM_CATEGORY_REQUEST); 150 if (status != QDF_STATUS_SUCCESS) { 151 mlme_err("Unable to parse T2LM request action frame"); 152 return QDF_STATUS_E_FAILURE; 153 } 154 155 /* 156 * Check if ML vdevs are connected and link id matches with T2LM 157 * negotiation action request link id 158 */ 159 valid_map = t2lm_is_valid_t2lm_link_map(vdev, &t2lm_req, &dir); 160 if (valid_map) { 161 mlme_debug("Link match found,accept t2lm conf"); 162 status = QDF_STATUS_SUCCESS; 163 } else { 164 status = QDF_STATUS_E_FAILURE; 165 mlme_err("reject t2lm conf"); 166 } 167 168 if (dir >= WLAN_T2LM_MAX_DIRECTION) { 169 mlme_err("Received T2LM IE has invalid direction"); 170 status = QDF_STATUS_E_INVAL; 171 } 172 173 if (QDF_IS_STATUS_SUCCESS(status) && 174 t2lm_req.t2lm_info[dir].direction != WLAN_T2LM_INVALID_DIRECTION) { 175 wlan_t2lm_clear_peer_negotiation(peer); 176 /* Apply T2LM config to peer T2LM ctx */ 177 t2lm_info = &ml_peer->t2lm_policy.t2lm_negotiated_info.t2lm_info[dir]; 178 qdf_mem_copy(t2lm_info, &t2lm_req.t2lm_info[dir], 179 sizeof(struct wlan_t2lm_info)); 180 } 181 182 *token = t2lm_req.dialog_token; 183 184 return status; 185 } 186 187 QDF_STATUS t2lm_handle_tx_resp(struct wlan_objmgr_vdev *vdev, 188 void *event_data, uint8_t *token) 189 { 190 return QDF_STATUS_SUCCESS; 191 } 192 193 QDF_STATUS t2lm_handle_tx_req(struct wlan_objmgr_vdev *vdev, 194 struct wlan_objmgr_peer *peer, 195 void *event_data, uint8_t *token) 196 { 197 struct wlan_t2lm_onging_negotiation_info *t2lm_neg; 198 struct wlan_action_frame_args args; 199 QDF_STATUS status; 200 201 if (!vdev) 202 return QDF_STATUS_E_NULL_VALUE; 203 204 if (!event_data) { 205 t2lm_err("Null event data ptr"); 206 return QDF_STATUS_E_NULL_VALUE; 207 } 208 209 t2lm_neg = (struct wlan_t2lm_onging_negotiation_info *)event_data; 210 args.category = ACTION_CATEGORY_PROTECTED_EHT; 211 args.action = EHT_T2LM_REQUEST; 212 args.arg1 = *token; 213 214 status = lim_send_t2lm_action_req_frame(vdev, 215 wlan_peer_get_macaddr(peer), 216 &args, t2lm_neg, 217 *token); 218 219 if (QDF_IS_STATUS_ERROR(status)) { 220 t2lm_err("Failed to send T2LM action request frame"); 221 } else { 222 t2lm_debug("Copy the ongoing neg to peer"); 223 qdf_mem_copy(&peer->mlo_peer_ctx->t2lm_policy.ongoing_tid_to_link_mapping, 224 t2lm_neg, sizeof(struct wlan_t2lm_onging_negotiation_info)); 225 } 226 227 return status; 228 } 229 230 QDF_STATUS t2lm_handle_rx_resp(struct wlan_objmgr_vdev *vdev, 231 struct wlan_objmgr_peer *peer, 232 void *event_data, uint8_t *token) 233 { 234 struct wlan_t2lm_onging_negotiation_info t2lm_rsp = {0}; 235 struct wlan_t2lm_onging_negotiation_info *t2lm_req; 236 QDF_STATUS status; 237 struct wlan_mlo_peer_context *ml_peer; 238 struct wlan_t2lm_info *t2lm_info; 239 uint8_t dir; 240 241 if (!peer) { 242 t2lm_err("peer is null"); 243 return QDF_STATUS_E_NULL_VALUE; 244 } 245 246 ml_peer = peer->mlo_peer_ctx; 247 if (!ml_peer) { 248 t2lm_err("ml peer is null"); 249 return QDF_STATUS_E_NULL_VALUE; 250 } 251 252 /* ignore the frame if all links are not connected */ 253 if (!mlo_check_if_all_links_up(vdev)) 254 return QDF_STATUS_SUCCESS; 255 256 status = wlan_mlo_parse_t2lm_action_frame(&t2lm_rsp, event_data, 257 WLAN_T2LM_CATEGORY_RESPONSE); 258 if (status != QDF_STATUS_SUCCESS) { 259 mlme_err("Unable to parse T2LM request action frame"); 260 return QDF_STATUS_E_FAILURE; 261 } 262 263 mlme_debug("t2lm rsp dialog token %d", t2lm_rsp.dialog_token); 264 mlme_debug("t2lm rsp is %d", t2lm_rsp.t2lm_resp_type); 265 t2lm_req = &ml_peer->t2lm_policy.ongoing_tid_to_link_mapping; 266 if (!t2lm_req) { 267 t2lm_err("Ongoing tid neg is null"); 268 return QDF_STATUS_E_FAILURE; 269 } 270 271 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 272 t2lm_info = &t2lm_req->t2lm_info[dir]; 273 if (t2lm_info && 274 t2lm_info->direction != WLAN_T2LM_INVALID_DIRECTION) { 275 if (t2lm_rsp.dialog_token == t2lm_req->dialog_token && 276 t2lm_rsp.t2lm_resp_type == WLAN_T2LM_RESP_TYPE_SUCCESS) { 277 status = wlan_send_tid_to_link_mapping(vdev, 278 t2lm_info); 279 if (QDF_IS_STATUS_ERROR(status)) { 280 t2lm_err("sending t2lm wmi failed"); 281 break; 282 } 283 } else if (t2lm_rsp.dialog_token == t2lm_req->dialog_token && 284 t2lm_rsp.t2lm_resp_type != WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) { 285 t2lm_debug("T2LM rsp status denied, clear ongoing tid mapping"); 286 wlan_t2lm_clear_ongoing_negotiation(peer); 287 } 288 } 289 } 290 291 return status; 292 } 293 294 QDF_STATUS t2lm_handle_rx_teardown(struct wlan_objmgr_vdev *vdev, 295 struct wlan_objmgr_peer *peer, 296 void *event_data) 297 { 298 struct wlan_mlo_dev_context *mlo_dev_ctx; 299 struct wlan_t2lm_context *t2lm_ctx; 300 301 if (!peer) { 302 t2lm_err("peer is null"); 303 return QDF_STATUS_E_NULL_VALUE; 304 } 305 306 if (!vdev) { 307 t2lm_err("vdev is null"); 308 return QDF_STATUS_E_NULL_VALUE; 309 } 310 311 mlo_dev_ctx = vdev->mlo_dev_ctx; 312 if (!mlo_dev_ctx) { 313 t2lm_err("mlo dev ctx is null"); 314 return QDF_STATUS_E_NULL_VALUE; 315 } 316 317 t2lm_ctx = &mlo_dev_ctx->t2lm_ctx; 318 if (!t2lm_ctx) { 319 t2lm_err("t2lm ctx is null"); 320 return QDF_STATUS_E_NULL_VALUE; 321 } 322 323 wlan_t2lm_clear_peer_negotiation(peer); 324 325 /* Notify the registered caller about the link update*/ 326 wlan_mlo_dev_t2lm_notify_link_update(vdev, 327 &t2lm_ctx->established_t2lm.t2lm); 328 wlan_send_tid_to_link_mapping(vdev, 329 &t2lm_ctx->established_t2lm.t2lm); 330 331 return QDF_STATUS_SUCCESS; 332 } 333 334 QDF_STATUS t2lm_handle_tx_teardown(struct wlan_objmgr_vdev *vdev, 335 void *event_data) 336 { 337 return QDF_STATUS_SUCCESS; 338 } 339 340 QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev, 341 struct wlan_objmgr_peer *peer, 342 enum wlan_t2lm_evt event, 343 void *event_data, uint8_t *token) 344 { 345 struct wlan_objmgr_psoc *psoc; 346 QDF_STATUS status; 347 348 psoc = wlan_vdev_get_psoc(vdev); 349 if (!psoc) 350 return QDF_STATUS_E_FAILURE; 351 352 mlme_debug("T2LM event received: %s(%d)", 353 t2lm_get_event_str(event), event); 354 355 switch (event) { 356 case WLAN_T2LM_EV_ACTION_FRAME_RX_REQ: 357 status = t2lm_handle_rx_req(vdev, peer, event_data, token); 358 break; 359 case WLAN_T2LM_EV_ACTION_FRAME_TX_RESP: 360 status = t2lm_handle_tx_resp(vdev, event_data, token); 361 break; 362 case WLAN_T2LM_EV_ACTION_FRAME_TX_REQ: 363 status = t2lm_handle_tx_req(vdev, peer, event_data, token); 364 break; 365 case WLAN_T2LM_EV_ACTION_FRAME_RX_RESP: 366 status = t2lm_handle_rx_resp(vdev, peer, event_data, token); 367 break; 368 case WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN: 369 status = t2lm_handle_rx_teardown(vdev, peer, event_data); 370 break; 371 case WLAN_T2LM_EV_ACTION_FRAME_TX_TEARDOWN: 372 status = t2lm_handle_tx_teardown(vdev, event_data); 373 break; 374 default: 375 status = QDF_STATUS_E_FAILURE; 376 mlme_err("Unhandled T2LM event"); 377 } 378 379 return status; 380 } 381 382 static uint16_t 383 t2lm_get_tids_mapped_link_id(uint16_t link_map_tid) 384 { 385 uint16_t all_tids_mapped_link_id = 0; 386 uint8_t i; 387 uint8_t bit_mask = 1; 388 389 for (i = 0; i < WLAN_T2LM_MAX_NUM_LINKS; i++) { 390 if (link_map_tid & bit_mask) 391 all_tids_mapped_link_id = i; 392 bit_mask = bit_mask << 1; 393 } 394 395 return all_tids_mapped_link_id; 396 } 397 398 static QDF_STATUS 399 t2lm_find_tid_mapped_link_id(struct wlan_t2lm_info *t2lm_info, 400 uint16_t *tid_mapped_link_id) 401 { 402 uint16_t link_map_tid; 403 uint8_t tid; 404 405 if (!t2lm_info) 406 return QDF_STATUS_E_NULL_VALUE; 407 408 if (t2lm_info->default_link_mapping) { 409 t2lm_debug("T2LM ie has default link mapping"); 410 *tid_mapped_link_id = 0xFFFF; 411 return QDF_STATUS_SUCCESS; 412 } 413 414 link_map_tid = t2lm_info->ieee_link_map_tid[0]; 415 for (tid = 1; tid < T2LM_MAX_NUM_TIDS; tid++) { 416 if (link_map_tid != t2lm_info->ieee_link_map_tid[tid]) { 417 mlme_debug("all tids are not mapped to same link set"); 418 return QDF_STATUS_E_FAILURE; 419 } 420 } 421 422 *tid_mapped_link_id = t2lm_get_tids_mapped_link_id(link_map_tid); 423 return QDF_STATUS_SUCCESS; 424 } 425 426 QDF_STATUS 427 wlan_t2lm_validate_candidate(struct cnx_mgr *cm_ctx, 428 struct scan_cache_entry *scan_entry) 429 { 430 QDF_STATUS status = QDF_STATUS_SUCCESS; 431 struct wlan_objmgr_vdev *vdev; 432 struct wlan_t2lm_context t2lm_ctx; 433 uint16_t tid_map_link_id; 434 uint16_t established_tid_mapped_link_id = 0; 435 uint16_t upcoming_tid_mapped_link_id = 0; 436 437 if (!scan_entry) 438 return QDF_STATUS_E_NULL_VALUE; 439 440 if (!cm_ctx || !cm_ctx->vdev) 441 return QDF_STATUS_E_NULL_VALUE; 442 443 vdev = cm_ctx->vdev; 444 445 if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { 446 mlme_debug("Skip t2lm validation for link vdev"); 447 return QDF_STATUS_SUCCESS; 448 } 449 450 if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) && 451 scan_entry->ie_list.t2lm[0]) { 452 status = wlan_mlo_parse_bcn_prbresp_t2lm_ie(&t2lm_ctx, 453 scan_entry->ie_list.t2lm[0]); 454 if (QDF_IS_STATUS_ERROR(status)) 455 goto end; 456 457 status = 458 t2lm_find_tid_mapped_link_id(&t2lm_ctx.established_t2lm.t2lm, 459 &established_tid_mapped_link_id); 460 if (QDF_IS_STATUS_ERROR(status)) 461 goto end; 462 463 status = 464 t2lm_find_tid_mapped_link_id(&t2lm_ctx.upcoming_t2lm.t2lm, 465 &upcoming_tid_mapped_link_id); 466 if (QDF_IS_STATUS_ERROR(status)) 467 goto end; 468 t2lm_debug("established_tid_mapped_link_id %x, upcoming_tid_mapped_link_id %x", 469 established_tid_mapped_link_id, 470 upcoming_tid_mapped_link_id); 471 472 tid_map_link_id = 473 established_tid_mapped_link_id & upcoming_tid_mapped_link_id; 474 if (!tid_map_link_id) 475 tid_map_link_id = established_tid_mapped_link_id; 476 477 if (tid_map_link_id == scan_entry->ml_info.self_link_id) { 478 t2lm_debug("self link id %d, tid map link id %d match", 479 scan_entry->ml_info.self_link_id, 480 tid_map_link_id); 481 status = QDF_STATUS_SUCCESS; 482 } else { 483 t2lm_debug("self link id %d, tid map link id %d do not match", 484 scan_entry->ml_info.self_link_id, 485 tid_map_link_id); 486 status = QDF_STATUS_E_FAILURE; 487 } 488 } else { 489 t2lm_debug("T2LM IE is not present in scan entry"); 490 status = QDF_STATUS_SUCCESS; 491 } 492 493 end: 494 return status; 495 } 496 497 void 498 wlan_t2lm_clear_ongoing_negotiation(struct wlan_objmgr_peer *peer) 499 { 500 struct wlan_mlo_peer_context *ml_peer; 501 struct wlan_t2lm_onging_negotiation_info *ongoing_tid_to_link_mapping; 502 uint8_t i; 503 504 ml_peer = peer->mlo_peer_ctx; 505 if (!ml_peer) { 506 t2lm_err("ml peer is null"); 507 return; 508 } 509 510 ongoing_tid_to_link_mapping = &ml_peer->t2lm_policy.ongoing_tid_to_link_mapping; 511 if (!ongoing_tid_to_link_mapping) { 512 t2lm_err("ongoing tid mapping is null"); 513 return; 514 } 515 516 qdf_mem_zero(&ongoing_tid_to_link_mapping->t2lm_info, 517 sizeof(struct wlan_t2lm_info) * WLAN_T2LM_MAX_DIRECTION); 518 519 ongoing_tid_to_link_mapping->dialog_token = 0; 520 ongoing_tid_to_link_mapping->category = WLAN_T2LM_CATEGORY_NONE; 521 ongoing_tid_to_link_mapping->t2lm_resp_type = WLAN_T2LM_RESP_TYPE_INVALID; 522 ongoing_tid_to_link_mapping->t2lm_tx_status = WLAN_T2LM_TX_STATUS_NONE; 523 524 for (i = 0; i < WLAN_T2LM_MAX_DIRECTION; i++) 525 ongoing_tid_to_link_mapping->t2lm_info[i].direction = 526 WLAN_T2LM_INVALID_DIRECTION; 527 } 528 529 void 530 wlan_t2lm_clear_peer_negotiation(struct wlan_objmgr_peer *peer) 531 { 532 struct wlan_mlo_peer_context *ml_peer; 533 struct wlan_prev_t2lm_negotiated_info *t2lm_negotiated_info; 534 uint8_t i; 535 536 ml_peer = peer->mlo_peer_ctx; 537 if (!ml_peer) { 538 t2lm_err("ml peer is null"); 539 return; 540 } 541 542 qdf_mem_zero(&ml_peer->t2lm_policy.t2lm_negotiated_info.t2lm_info, 543 sizeof(struct wlan_t2lm_info) * WLAN_T2LM_MAX_DIRECTION); 544 545 ml_peer->t2lm_policy.t2lm_negotiated_info.dialog_token = 0; 546 t2lm_negotiated_info = &ml_peer->t2lm_policy.t2lm_negotiated_info; 547 for (i = 0; i < WLAN_T2LM_MAX_DIRECTION; i++) 548 t2lm_negotiated_info->t2lm_info[i].direction = 549 WLAN_T2LM_INVALID_DIRECTION; 550 } 551 552 void 553 wlan_t2lm_clear_all_tid_mapping(struct wlan_objmgr_vdev *vdev) 554 { 555 struct wlan_objmgr_peer *peer; 556 struct wlan_t2lm_context *t2lm_ctx; 557 558 if (!vdev) { 559 t2lm_err("Vdev is null"); 560 return; 561 } 562 563 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 564 return; 565 566 if (!vdev->mlo_dev_ctx) { 567 t2lm_err("mlo dev ctx is null"); 568 return; 569 } 570 571 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 572 peer = wlan_vdev_get_bsspeer(vdev); 573 if (!peer) { 574 t2lm_err("peer is null"); 575 return; 576 } 577 qdf_mem_zero(&t2lm_ctx->established_t2lm, 578 sizeof(struct wlan_mlo_t2lm_ie)); 579 t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_BIDI_DIRECTION; 580 t2lm_ctx->established_t2lm.t2lm.default_link_mapping = 1; 581 t2lm_ctx->established_t2lm.t2lm.link_mapping_size = 0; 582 583 qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, 584 sizeof(struct wlan_mlo_t2lm_ie)); 585 t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; 586 587 wlan_t2lm_clear_peer_negotiation(peer); 588 wlan_t2lm_clear_ongoing_negotiation(peer); 589 wlan_mlo_t2lm_timer_stop(vdev); 590 } 591 592 static bool 593 wlan_is_ml_link_disabled(uint32_t link_id_bitmap, 594 uint8_t ml_link_id) 595 { 596 uint8_t link; 597 598 if (!link_id_bitmap) { 599 t2lm_err("Link id bitmap is 0"); 600 return false; 601 } 602 603 for (link = 0; link < WLAN_T2LM_MAX_NUM_LINKS; link++) { 604 if ((link == ml_link_id) && 605 (link_id_bitmap & BIT(link))) { 606 return true; 607 } 608 } 609 610 return false; 611 } 612 613 static void 614 wlan_t2lm_set_link_mapping_of_tids(uint8_t link_id, 615 struct wlan_t2lm_info *t2lm_info, 616 bool set) 617 { 618 uint8_t tid_num; 619 620 if (link_id >= WLAN_T2LM_MAX_NUM_LINKS) { 621 t2lm_err("Max 16 t2lm links are supported"); 622 return; 623 } 624 625 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 626 if (set) 627 t2lm_info->ieee_link_map_tid[tid_num] |= BIT(link_id); 628 else 629 t2lm_info->ieee_link_map_tid[tid_num] &= ~BIT(link_id); 630 } 631 } 632 633 QDF_STATUS 634 wlan_populate_link_disable_t2lm_frame(struct wlan_objmgr_vdev *vdev, 635 struct mlo_link_disable_request_evt_params *params) 636 { 637 struct wlan_objmgr_peer *peer; 638 struct wlan_mlo_dev_context *ml_dev_ctx; 639 struct wlan_mlo_peer_t2lm_policy *t2lm_policy; 640 struct wlan_objmgr_vdev *tmp_vdev; 641 struct wlan_t2lm_onging_negotiation_info t2lm_neg = {0}; 642 uint8_t dir = WLAN_T2LM_BIDI_DIRECTION; 643 uint8_t i = 0; 644 QDF_STATUS status; 645 uint8_t link_id; 646 647 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, 648 WLAN_MLO_MGR_ID); 649 650 if (!peer) { 651 t2lm_err("peer is null"); 652 return QDF_STATUS_E_NULL_VALUE; 653 } 654 655 if (!vdev->mlo_dev_ctx) 656 return QDF_STATUS_E_NULL_VALUE; 657 658 t2lm_policy = &peer->mlo_peer_ctx->t2lm_policy; 659 t2lm_neg = t2lm_policy->ongoing_tid_to_link_mapping; 660 661 t2lm_neg.category = WLAN_T2LM_CATEGORY_REQUEST; 662 t2lm_neg.dialog_token = t2lm_gen_dialog_token(t2lm_policy); 663 qdf_mem_zero(&t2lm_neg.t2lm_info, 664 sizeof(struct wlan_t2lm_info) * WLAN_T2LM_MAX_DIRECTION); 665 for (i = 0; i < WLAN_T2LM_MAX_DIRECTION; i++) 666 t2lm_neg.t2lm_info[i].direction = WLAN_T2LM_INVALID_DIRECTION; 667 668 t2lm_neg.t2lm_info[dir].default_link_mapping = 0; 669 t2lm_neg.t2lm_info[dir].direction = WLAN_T2LM_BIDI_DIRECTION; 670 t2lm_neg.t2lm_info[dir].mapping_switch_time_present = 0; 671 t2lm_neg.t2lm_info[dir].expected_duration_present = 0; 672 t2lm_neg.t2lm_info[dir].link_mapping_size = 1; 673 674 t2lm_debug("dir %d", t2lm_neg.t2lm_info[dir].direction); 675 ml_dev_ctx = vdev->mlo_dev_ctx; 676 677 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 678 if (!ml_dev_ctx->wlan_vdev_list[i]) 679 continue; 680 681 tmp_vdev = ml_dev_ctx->wlan_vdev_list[i]; 682 link_id = wlan_vdev_get_link_id(tmp_vdev); 683 684 /* if link id matches disabled link id bitmap 685 * set that bit as 0. 686 */ 687 if (wlan_is_ml_link_disabled(params->link_id_bitmap, 688 link_id)) { 689 wlan_t2lm_set_link_mapping_of_tids(link_id, 690 &t2lm_neg.t2lm_info[dir], 691 0); 692 t2lm_debug("Disabled link id %d", link_id); 693 } else { 694 wlan_t2lm_set_link_mapping_of_tids(link_id, 695 &t2lm_neg.t2lm_info[dir], 696 1); 697 t2lm_debug("Enabled link id %d", link_id); 698 } 699 } 700 701 status = t2lm_deliver_event(vdev, peer, 702 WLAN_T2LM_EV_ACTION_FRAME_TX_REQ, 703 &t2lm_neg, 704 &t2lm_neg.dialog_token); 705 706 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 707 return status; 708 } 709 710 QDF_STATUS wlan_t2lm_deliver_event(struct wlan_objmgr_vdev *vdev, 711 struct wlan_objmgr_peer *peer, 712 enum wlan_t2lm_evt event, 713 void *event_data, 714 uint8_t *dialog_token) 715 { 716 return t2lm_deliver_event(vdev, peer, event, event_data, dialog_token); 717 } 718