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 T2LM APIs 19 */ 20 21 #include <wlan_objmgr_pdev_obj.h> 22 #include <wlan_objmgr_vdev_obj.h> 23 #include <wlan_objmgr_peer_obj.h> 24 #include <wlan_mlo_mgr_public_structs.h> 25 #include <wlan_mlo_t2lm.h> 26 #include <wlan_mlo_mgr_cmn.h> 27 #include <qdf_util.h> 28 #include <wlan_cm_api.h> 29 30 QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie, 31 struct wlan_t2lm_info *t2lm) 32 { 33 struct wlan_ie_tid_to_link_mapping *t2lm_ie; 34 enum wlan_t2lm_direction dir; 35 uint8_t *t2lm_control_field; 36 uint16_t t2lm_control; 37 uint8_t link_mapping_presence_ind; 38 uint8_t *link_mapping_of_tids; 39 uint8_t tid_num; 40 uint8_t *ie_ptr = NULL; 41 42 t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)ie; 43 44 t2lm_control_field = t2lm_ie->data; 45 if (!t2lm_control_field) { 46 t2lm_err("t2lm_control_field is null"); 47 return QDF_STATUS_E_NULL_VALUE; 48 } 49 50 t2lm_control = qdf_le16_to_cpu(*(uint16_t *)t2lm_control_field); 51 52 dir = QDF_GET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX, 53 WLAN_T2LM_CONTROL_DIRECTION_BITS); 54 if (dir > WLAN_T2LM_BIDI_DIRECTION) { 55 t2lm_err("Invalid direction"); 56 return QDF_STATUS_E_NULL_VALUE; 57 } 58 59 t2lm->direction = dir; 60 t2lm->default_link_mapping = 61 QDF_GET_BITS(t2lm_control, 62 WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_IDX, 63 WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS); 64 65 t2lm->mapping_switch_time_present = 66 QDF_GET_BITS(t2lm_control, 67 WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX, 68 WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS); 69 70 t2lm->expected_duration_present = 71 QDF_GET_BITS(t2lm_control, 72 WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX, 73 WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS); 74 75 t2lm_debug("direction:%d default_link_mapping:%d mapping_switch_time_present:%d expected_duration_present:%d", 76 t2lm->direction, t2lm->default_link_mapping, 77 t2lm->mapping_switch_time_present, 78 t2lm->expected_duration_present); 79 80 if (t2lm->default_link_mapping) { 81 ie_ptr = t2lm_control_field + sizeof(uint8_t); 82 } else { 83 link_mapping_presence_ind = 84 QDF_GET_BITS(t2lm_control, 85 WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX, 86 WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS); 87 ie_ptr = t2lm_control_field + sizeof(t2lm_control); 88 } 89 90 if (t2lm->mapping_switch_time_present) { 91 t2lm->mapping_switch_time = 92 qdf_le16_to_cpu(*(uint16_t *)ie_ptr); 93 ie_ptr += sizeof(uint16_t); 94 } 95 96 if (t2lm->expected_duration_present) { 97 qdf_mem_copy(&t2lm->expected_duration, ie_ptr, 98 WLAN_T2LM_EXPECTED_DURATION_SIZE * 99 (sizeof(uint8_t))); 100 ie_ptr += WLAN_T2LM_EXPECTED_DURATION_SIZE * (sizeof(uint8_t)); 101 } 102 103 t2lm_debug("mapping_switch_time:%d expected_duration:%d", 104 t2lm->mapping_switch_time, t2lm->expected_duration); 105 106 if (t2lm->default_link_mapping) 107 return QDF_STATUS_SUCCESS; 108 109 link_mapping_of_tids = ie_ptr; 110 111 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 112 if (!(link_mapping_presence_ind & BIT(tid_num))) 113 continue; 114 115 t2lm->ieee_link_map_tid[tid_num] = 116 qdf_le16_to_cpu(*(uint16_t *)link_mapping_of_tids); 117 118 t2lm_rl_debug("link mapping of TID%d is %x", tid_num, 119 t2lm->ieee_link_map_tid[tid_num]); 120 121 link_mapping_of_tids += sizeof(uint16_t); 122 } 123 124 return QDF_STATUS_SUCCESS; 125 } 126 127 QDF_STATUS wlan_mlo_parse_bcn_prbresp_t2lm_ie( 128 struct wlan_t2lm_context *t2lm_ctx, uint8_t *ie) 129 { 130 struct wlan_t2lm_info t2lm = {0}; 131 struct extn_ie_header *ext_ie_hdr; 132 QDF_STATUS retval; 133 int i = 0; 134 135 qdf_mem_zero(&t2lm_ctx->established_t2lm, 136 sizeof(struct wlan_mlo_t2lm_ie)); 137 qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, sizeof(struct wlan_mlo_t2lm_ie)); 138 139 t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; 140 t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; 141 142 for (i = 0; i < WLAN_MAX_T2LM_IE; i++) { 143 if (!ie) { 144 t2lm_err("ie is null"); 145 return QDF_STATUS_E_NULL_VALUE; 146 } 147 148 ext_ie_hdr = (struct extn_ie_header *)ie; 149 150 if (!(ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM && 151 ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM)) 152 continue; 153 154 t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; 155 retval = wlan_mlo_parse_t2lm_info(ie, &t2lm); 156 if (retval) { 157 t2lm_err("Failed to parse the T2LM IE"); 158 return retval; 159 } 160 161 if (!t2lm.mapping_switch_time_present && 162 t2lm.expected_duration_present) { 163 qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, &t2lm, 164 sizeof(struct wlan_t2lm_info)); 165 } else if (t2lm.mapping_switch_time_present) { 166 qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, &t2lm, 167 sizeof(struct wlan_t2lm_info)); 168 } 169 170 ie += ext_ie_hdr->ie_len + sizeof(struct ie_header); 171 } 172 173 return QDF_STATUS_SUCCESS; 174 } 175 176 QDF_STATUS wlan_mlo_parse_t2lm_ie( 177 struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie) 178 { 179 struct extn_ie_header *ext_ie_hdr = NULL; 180 QDF_STATUS retval; 181 enum wlan_t2lm_direction dir; 182 struct wlan_t2lm_info t2lm_info; 183 184 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) 185 t2lm->t2lm_info[dir].direction = WLAN_T2LM_INVALID_DIRECTION; 186 187 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 188 if (!ie) { 189 t2lm_err("ie is null"); 190 return QDF_STATUS_E_NULL_VALUE; 191 } 192 193 ext_ie_hdr = (struct extn_ie_header *)ie; 194 195 if (ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM && 196 ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM) { 197 qdf_mem_zero(&t2lm_info, sizeof(t2lm_info)); 198 retval = wlan_mlo_parse_t2lm_info(ie, &t2lm_info); 199 if (!retval && 200 t2lm_info.direction < WLAN_T2LM_MAX_DIRECTION) { 201 qdf_mem_copy(&t2lm->t2lm_info[t2lm_info.direction], 202 &t2lm_info, 203 sizeof(struct wlan_t2lm_info)); 204 } else { 205 t2lm_err("Failed to parse the T2LM IE"); 206 return retval; 207 } 208 ie += ext_ie_hdr->ie_len + sizeof(struct ie_header); 209 } 210 } 211 212 if ((t2lm->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction == 213 WLAN_T2LM_DL_DIRECTION || 214 t2lm->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction == 215 WLAN_T2LM_UL_DIRECTION) && 216 t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction == 217 WLAN_T2LM_BIDI_DIRECTION) { 218 t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time"); 219 220 qdf_mem_zero(t2lm, sizeof(*t2lm)); 221 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 222 t2lm->t2lm_info[dir].direction = 223 WLAN_T2LM_INVALID_DIRECTION; 224 } 225 226 return QDF_STATUS_E_FAILURE; 227 } 228 229 return QDF_STATUS_SUCCESS; 230 } 231 232 uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm, 233 struct wlan_objmgr_vdev *vdev) 234 { 235 struct wlan_ie_tid_to_link_mapping *t2lm_ie; 236 uint16_t t2lm_control = 0; 237 uint8_t *t2lm_control_field; 238 uint8_t *link_mapping_of_tids; 239 uint8_t tid_num; 240 uint8_t num_tids = 0; 241 uint8_t link_mapping_presence_indicator = 0; 242 struct vdev_mlme_obj *vdev_mlme; 243 244 t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)frm; 245 t2lm_ie->elem_id = WLAN_ELEMID_EXTN_ELEM; 246 t2lm_ie->elem_id_extn = WLAN_EXTN_ELEMID_T2LM; 247 248 t2lm_ie->elem_len = sizeof(*t2lm_ie) - sizeof(struct ie_header); 249 250 t2lm_control_field = t2lm_ie->data; 251 252 QDF_SET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX, 253 WLAN_T2LM_CONTROL_DIRECTION_BITS, t2lm->direction); 254 255 QDF_SET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_IDX, 256 WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS, 257 t2lm->default_link_mapping); 258 259 QDF_SET_BITS(t2lm_control, 260 WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX, 261 WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS, 262 t2lm->mapping_switch_time_present); 263 264 QDF_SET_BITS(t2lm_control, 265 WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX, 266 WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS, 267 t2lm->expected_duration_present); 268 269 if (t2lm->default_link_mapping) { 270 /* Link mapping of TIDs are not present when default mapping is 271 * set. Hence, the size of TID-To-Link mapping control is one 272 * octet. 273 */ 274 *t2lm_control_field = (uint8_t)t2lm_control; 275 276 t2lm_ie->elem_len += sizeof(uint8_t); 277 278 t2lm_rl_debug("T2LM IE added, default_link_mapping: %d dir:%d", 279 t2lm->default_link_mapping, t2lm->direction); 280 281 frm += sizeof(*t2lm_ie) + sizeof(uint8_t); 282 } else { 283 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) 284 if (t2lm->hw_link_map_tid[tid_num]) 285 link_mapping_presence_indicator |= BIT(tid_num); 286 287 QDF_SET_BITS(t2lm_control, 288 WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX, 289 WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS, 290 link_mapping_presence_indicator); 291 t2lm_rl_debug("T2LM IE added, direction:%d link_mapping_presence_indicator:%x", 292 t2lm->direction, link_mapping_presence_indicator); 293 294 /* The size of TID-To-Link mapping control is two octets when 295 * default link mapping is not set. 296 */ 297 *(uint16_t *)t2lm_control_field = htole16(t2lm_control); 298 frm += sizeof(*t2lm_ie) + sizeof(uint16_t); 299 t2lm_ie->elem_len += sizeof(uint16_t); 300 } 301 302 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 303 if (vdev_mlme && t2lm->mapping_switch_time_present) { 304 /* Mapping switch time is different for each vdevs. Hence, 305 * populate the mapping switch time from vdev_mlme_obj. 306 */ 307 *(uint16_t *)frm = 308 htole16(vdev_mlme->proto.ap.mapping_switch_time); 309 frm += sizeof(uint16_t); 310 t2lm_ie->elem_len += sizeof(uint16_t); 311 } 312 313 if (t2lm->expected_duration_present) { 314 qdf_mem_copy(frm, &t2lm->expected_duration, 315 WLAN_T2LM_EXPECTED_DURATION_SIZE * 316 sizeof(uint8_t)); 317 frm += WLAN_T2LM_EXPECTED_DURATION_SIZE * sizeof(uint8_t); 318 t2lm_ie->elem_len += 319 WLAN_T2LM_EXPECTED_DURATION_SIZE * sizeof(uint8_t); 320 } 321 322 t2lm_rl_debug("mapping_switch_time:%d expected_duration:%u", 323 t2lm->mapping_switch_time, t2lm->expected_duration); 324 325 if (t2lm->default_link_mapping) 326 return frm; 327 328 link_mapping_of_tids = frm; 329 330 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 331 if (!t2lm->ieee_link_map_tid[tid_num]) 332 continue; 333 334 *(uint16_t *)link_mapping_of_tids = 335 htole16(t2lm->ieee_link_map_tid[tid_num]); 336 t2lm_rl_debug("link mapping of TID%d is %x", tid_num, 337 htole16(t2lm->ieee_link_map_tid[tid_num])); 338 link_mapping_of_tids += sizeof(uint16_t); 339 num_tids++; 340 } 341 342 frm += num_tids * sizeof(uint16_t); 343 t2lm_ie->elem_len += (num_tids * sizeof(uint16_t)); 344 345 return frm; 346 } 347 348 uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, 349 struct wlan_t2lm_onging_negotiation_info *t2lm, 350 struct wlan_objmgr_vdev *vdev) 351 { 352 uint8_t dir; 353 354 if (!frm) { 355 t2lm_err("frm is null"); 356 return NULL; 357 } 358 359 if (!t2lm) { 360 t2lm_err("t2lm is null"); 361 return NULL; 362 } 363 364 /* As per spec, the frame should include one or two T2LM IEs. When it is 365 * two, then direction should DL and UL. 366 */ 367 if ((t2lm->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction == 368 WLAN_T2LM_DL_DIRECTION || 369 t2lm->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction == 370 WLAN_T2LM_UL_DIRECTION) && 371 t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction == 372 WLAN_T2LM_BIDI_DIRECTION) { 373 t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time"); 374 return NULL; 375 } 376 377 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 378 if (t2lm->t2lm_info[dir].direction != 379 WLAN_T2LM_INVALID_DIRECTION) 380 frm = wlan_mlo_add_t2lm_info_ie(frm, 381 &t2lm->t2lm_info[dir], 382 vdev); 383 } 384 385 return frm; 386 } 387 388 /** 389 * wlan_mlo_parse_t2lm_request_action_frame() - API to parse T2LM request action 390 * frame. 391 * @t2lm: Pointer to T2LM structure 392 * @action_frm: Pointer to action frame 393 * @category: T2LM action frame category 394 * 395 * Return: QDF_STATUS 396 */ 397 static QDF_STATUS wlan_mlo_parse_t2lm_request_action_frame( 398 struct wlan_t2lm_onging_negotiation_info *t2lm, 399 struct wlan_action_frame *action_frm, 400 enum wlan_t2lm_category category) 401 { 402 uint8_t *t2lm_action_frm; 403 404 t2lm->category = category; 405 406 /* 407 * T2LM request action frame 408 * 409 * 1-byte 1-byte 1-byte variable 410 *------------------------------------------- 411 * | | | | | 412 * | Category| Protected | Dialog | T2LM IE | 413 * | | EHT | token | | 414 * | | Action | | | 415 *------------------------------------------- 416 */ 417 418 t2lm_action_frm = (uint8_t *)action_frm + sizeof(*action_frm); 419 420 t2lm->dialog_token = *t2lm_action_frm; 421 422 return wlan_mlo_parse_t2lm_ie(t2lm, 423 t2lm_action_frm + sizeof(uint8_t)); 424 } 425 426 /** 427 * wlan_mlo_parse_t2lm_response_action_frame() - API to parse T2LM response 428 * action frame. 429 * @t2lm: Pointer to T2LM structure 430 * @action_frm: Pointer to action frame 431 * @category: T2LM action frame category 432 * 433 * Return: QDF_STATUS 434 */ 435 static QDF_STATUS wlan_mlo_parse_t2lm_response_action_frame( 436 struct wlan_t2lm_onging_negotiation_info *t2lm, 437 struct wlan_action_frame *action_frm, 438 enum wlan_t2lm_category category) 439 { 440 uint8_t *t2lm_action_frm; 441 QDF_STATUS ret_val = QDF_STATUS_SUCCESS; 442 443 t2lm->category = WLAN_T2LM_CATEGORY_RESPONSE; 444 /* 445 * T2LM response action frame 446 * 447 * 1-byte 1-byte 1-byte 1-byte variable 448 *---------------------------------------------------- 449 * | | | | | | 450 * | Category| Protected | Dialog | Status | T2LM IE | 451 * | | EHT | token | code | | 452 * | | Action | | | | 453 *---------------------------------------------------- 454 */ 455 456 t2lm_action_frm = (uint8_t *)action_frm + sizeof(*action_frm); 457 458 t2lm->dialog_token = *t2lm_action_frm; 459 t2lm->t2lm_resp_type = *(t2lm_action_frm + sizeof(uint8_t)); 460 461 if (t2lm->t2lm_resp_type == 462 WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) { 463 t2lm_action_frm += sizeof(uint8_t) + sizeof(uint8_t); 464 ret_val = wlan_mlo_parse_t2lm_ie(t2lm, t2lm_action_frm); 465 } 466 467 return ret_val; 468 } 469 470 int wlan_mlo_parse_t2lm_action_frame( 471 struct wlan_t2lm_onging_negotiation_info *t2lm, 472 struct wlan_action_frame *action_frm, 473 enum wlan_t2lm_category category) 474 { 475 QDF_STATUS ret_val = QDF_STATUS_SUCCESS; 476 477 switch (category) { 478 case WLAN_T2LM_CATEGORY_REQUEST: 479 { 480 ret_val = wlan_mlo_parse_t2lm_request_action_frame( 481 t2lm, action_frm, category); 482 return qdf_status_to_os_return(ret_val); 483 } 484 case WLAN_T2LM_CATEGORY_RESPONSE: 485 { 486 ret_val = wlan_mlo_parse_t2lm_response_action_frame( 487 t2lm, action_frm, category); 488 489 return qdf_status_to_os_return(ret_val); 490 } 491 case WLAN_T2LM_CATEGORY_TEARDOWN: 492 /* Nothing to parse from T2LM teardown frame, just reset 493 * the mapping to default mapping. 494 * 495 * T2LM teardown action frame 496 * 497 * 1-byte 1-byte 498 *------------------------ 499 * | | | 500 * | Category| Protected | 501 * | | EHT | 502 * | | Action | 503 *------------------------ 504 */ 505 break; 506 default: 507 t2lm_err("Invalid category:%d", category); 508 } 509 510 return ret_val; 511 } 512 513 static uint8_t *wlan_mlo_add_t2lm_request_action_frame( 514 uint8_t *frm, 515 struct wlan_action_frame_args *args, uint8_t *buf, 516 enum wlan_t2lm_category category) 517 { 518 *frm++ = args->category; 519 *frm++ = args->action; 520 /* Dialog token*/ 521 *frm++ = args->arg1; 522 523 t2lm_info("T2LM request frame: category:%d action:%d dialog_token:%d", 524 args->category, args->action, args->arg1); 525 return wlan_mlo_add_t2lm_ie(frm, (void *)buf, NULL); 526 } 527 528 static uint8_t *wlan_mlo_add_t2lm_response_action_frame( 529 uint8_t *frm, 530 struct wlan_action_frame_args *args, uint8_t *buf, 531 enum wlan_t2lm_category category) 532 { 533 *frm++ = args->category; 534 *frm++ = args->action; 535 /* Dialog token*/ 536 *frm++ = args->arg1; 537 /* Status code */ 538 *frm++ = args->arg2; 539 540 t2lm_info("T2LM response frame: category:%d action:%d dialog_token:%d status_code:%d", 541 args->category, args->action, args->arg1, args->arg2); 542 543 if (args->arg2 == WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) 544 frm = wlan_mlo_add_t2lm_ie(frm, (void *)buf, NULL); 545 546 return frm; 547 } 548 549 uint8_t *wlan_mlo_add_t2lm_action_frame( 550 uint8_t *frm, 551 struct wlan_action_frame_args *args, uint8_t *buf, 552 enum wlan_t2lm_category category) 553 { 554 555 switch (category) { 556 case WLAN_T2LM_CATEGORY_REQUEST: 557 return wlan_mlo_add_t2lm_request_action_frame(frm, args, 558 buf, category); 559 case WLAN_T2LM_CATEGORY_RESPONSE: 560 return wlan_mlo_add_t2lm_response_action_frame(frm, args, 561 buf, category); 562 case WLAN_T2LM_CATEGORY_TEARDOWN: 563 *frm++ = args->category; 564 *frm++ = args->action; 565 return frm; 566 default: 567 t2lm_err("Invalid category:%d", category); 568 } 569 570 return frm; 571 } 572 573 /** 574 * wlan_mlo_t2lm_handle_mapping_switch_time_expiry() - API to handle the mapping 575 * switch timer expiry. 576 * @t2lm_ctx: Pointer to T2LM context 577 * @vdev: Pointer to vdev structure 578 * 579 * Return: None 580 */ 581 static void wlan_mlo_t2lm_handle_mapping_switch_time_expiry( 582 struct wlan_t2lm_context *t2lm_ctx, 583 struct wlan_objmgr_vdev *vdev) 584 { 585 struct wlan_t2lm_info *t2lm; 586 587 t2lm_debug("Mapping switch time expired for vdev_id:%d ", 588 wlan_vdev_get_id(vdev)); 589 590 qdf_mem_copy(&t2lm_ctx->established_t2lm, &t2lm_ctx->upcoming_t2lm, 591 sizeof(struct wlan_mlo_t2lm_ie)); 592 593 t2lm_ctx->established_t2lm.t2lm.mapping_switch_time_present = false; 594 t2lm_ctx->established_t2lm.t2lm.mapping_switch_time = 0; 595 596 t2lm = &t2lm_ctx->established_t2lm.t2lm; 597 t2lm_debug("Established mapping: disabled_link_bitmap:%x dir:%d default_map:%d MSTP:%d EDP:%d MST:%d ED:%d ieee_link_map:%x hw_link_map:%x", 598 t2lm_ctx->established_t2lm.disabled_link_bitmap, 599 t2lm->direction, t2lm->default_link_mapping, 600 t2lm->mapping_switch_time_present, 601 t2lm->expected_duration_present, 602 t2lm->mapping_switch_time, t2lm->expected_duration, 603 t2lm->ieee_link_map_tid[0], t2lm->hw_link_map_tid[0]); 604 605 qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, sizeof(struct wlan_mlo_t2lm_ie)); 606 t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; 607 608 /* Notify the registered caller about the link update*/ 609 wlan_mlo_dev_t2lm_notify_link_update(vdev->mlo_dev_ctx); 610 } 611 612 /** 613 * wlan_mlo_t2lm_handle_expected_duration_expiry() - API to handle the expected 614 * duration timer expiry. 615 * @t2lm_ctx: Pointer to T2LM context 616 * @vdev: Pointer to vdev structure 617 * 618 * Return: none 619 */ 620 static void wlan_mlo_t2lm_handle_expected_duration_expiry( 621 struct wlan_t2lm_context *t2lm_ctx, 622 struct wlan_objmgr_vdev *vdev) 623 { 624 t2lm_debug("Expected duration expired for vdev_id:%d ", 625 wlan_vdev_get_id(vdev)); 626 627 if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) { 628 /* Copy the new non-default ongoing mapping to established 629 * mapping if expected duration expires for the established 630 * mapping. 631 */ 632 wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, 633 vdev); 634 return; 635 } 636 637 /* Use the default mapping when expected duration expires for the 638 * established mapping and no new non-default T2LM announcement is 639 * ongoing. 640 */ 641 qdf_mem_zero(&t2lm_ctx->established_t2lm, 642 sizeof(struct wlan_mlo_t2lm_ie)); 643 644 t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_BIDI_DIRECTION; 645 t2lm_ctx->established_t2lm.t2lm.default_link_mapping = 1; 646 t2lm_ctx->established_t2lm.disabled_link_bitmap = 0; 647 t2lm_debug("Set established mapping to default mapping"); 648 649 /* Notify the registered caller about the link update*/ 650 wlan_mlo_dev_t2lm_notify_link_update(vdev->mlo_dev_ctx); 651 } 652 653 QDF_STATUS wlan_mlo_vdev_tid_to_link_map_event( 654 struct wlan_objmgr_psoc *psoc, 655 struct mlo_vdev_host_tid_to_link_map_resp *event) 656 { 657 struct wlan_objmgr_vdev *vdev; 658 struct wlan_t2lm_context *t2lm_ctx; 659 struct vdev_mlme_obj *vdev_mlme; 660 661 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id, 662 WLAN_MLO_MGR_ID); 663 if (!vdev) { 664 t2lm_err("null vdev"); 665 return QDF_STATUS_E_NULL_VALUE; 666 } 667 668 if (!vdev->mlo_dev_ctx) { 669 t2lm_err("null mlo_dev_ctx"); 670 return QDF_STATUS_E_NULL_VALUE; 671 } 672 673 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 674 if (!vdev_mlme) { 675 t2lm_err("null vdev_mlme"); 676 return QDF_STATUS_E_FAILURE; 677 } 678 679 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 680 681 t2lm_debug("psoc_id:%d vdev_id:%d status:%d", 682 wlan_psoc_get_id(psoc), event->vdev_id, event->status); 683 684 t2lm_dev_lock_acquire(t2lm_ctx); 685 switch (event->status) { 686 case WLAN_MAP_SWITCH_TIMER_TSF: 687 688 /* Mapping switch time is different for each AP vdev of a given 689 * MLD as these vdevs can have separate beacon TDF value. 690 */ 691 if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) 692 vdev_mlme->proto.ap.mapping_switch_time = 693 (event->mapping_switch_tsf & 694 WLAN_T2LM_MAPPING_SWITCH_TSF_BITS) >> 10; 695 696 t2lm_debug("vdev_id:%d updated mapping switch time:%d", 697 event->vdev_id, 698 vdev_mlme->proto.ap.mapping_switch_time); 699 break; 700 case WLAN_MAP_SWITCH_TIMER_EXPIRED: 701 vdev_mlme->proto.ap.mapping_switch_time = 0; 702 wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, vdev); 703 break; 704 case WLAN_EXPECTED_DUR_EXPIRED: 705 wlan_mlo_t2lm_handle_expected_duration_expiry(t2lm_ctx, vdev); 706 break; 707 default: 708 t2lm_err("Invalid status"); 709 } 710 711 t2lm_dev_lock_release(t2lm_ctx); 712 mlo_release_vdev_ref(vdev); 713 714 return QDF_STATUS_SUCCESS; 715 } 716 717 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 718 static 719 QDF_STATUS wlan_send_t2lm_info(struct wlan_objmgr_vdev *vdev, 720 struct wlan_t2lm_info *t2lm, 721 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops) 722 { 723 QDF_STATUS status = QDF_STATUS_E_FAILURE; 724 725 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 726 t2lm_err("vdev is not MLO vdev"); 727 return status; 728 } 729 730 status = mlo_tx_ops->send_tid_to_link_mapping(vdev, t2lm); 731 if (QDF_IS_STATUS_ERROR(status)) 732 t2lm_err("Failed to send T2LM command to FW"); 733 734 return status; 735 } 736 #else 737 static 738 QDF_STATUS wlan_send_t2lm_info(struct wlan_objmgr_vdev *vdev, 739 struct wlan_t2lm_info *t2lm, 740 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops) 741 { 742 struct wlan_objmgr_vdev *co_mld_vdev; 743 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 744 uint16_t vdev_count = 0; 745 int i = 0; 746 QDF_STATUS status = QDF_STATUS_E_FAILURE; 747 748 mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list); 749 if (!vdev_count) { 750 t2lm_err("Number of VDEVs under MLD is reported as 0"); 751 return QDF_STATUS_E_NULL_VALUE; 752 } 753 754 for (i = 0; i < vdev_count; i++) { 755 co_mld_vdev = wlan_vdev_list[i]; 756 if (!co_mld_vdev) { 757 t2lm_err("co_mld_vdev is null"); 758 mlo_release_vdev_ref(co_mld_vdev); 759 continue; 760 } 761 762 status = mlo_tx_ops->send_tid_to_link_mapping(co_mld_vdev, 763 t2lm); 764 if (QDF_IS_STATUS_ERROR(status)) 765 t2lm_err("Failed to send T2LM command to FW"); 766 mlo_release_vdev_ref(co_mld_vdev); 767 } 768 769 return status; 770 } 771 #endif 772 773 QDF_STATUS wlan_send_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev, 774 struct wlan_t2lm_info *t2lm) 775 { 776 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 777 struct wlan_objmgr_psoc *psoc; 778 QDF_STATUS status = QDF_STATUS_E_FAILURE; 779 780 psoc = wlan_vdev_get_psoc(vdev); 781 if (!psoc) { 782 t2lm_err("null psoc"); 783 return QDF_STATUS_E_NULL_VALUE; 784 } 785 786 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; 787 if (!mlo_tx_ops) { 788 t2lm_err("tx_ops is null!"); 789 return QDF_STATUS_E_NULL_VALUE; 790 } 791 792 if (!mlo_tx_ops->send_tid_to_link_mapping) { 793 t2lm_err("send_tid_to_link_mapping is null"); 794 return QDF_STATUS_E_NULL_VALUE; 795 } 796 797 status = wlan_send_t2lm_info(vdev, t2lm, mlo_tx_ops); 798 799 return status; 800 } 801 802 void wlan_mlo_t2lm_timer_expiry_handler(void *vdev) 803 { 804 struct wlan_objmgr_vdev *vdev_ctx = (struct wlan_objmgr_vdev *)vdev; 805 806 struct wlan_t2lm_timer *t2lm_timer; 807 struct wlan_t2lm_context *t2lm_ctx; 808 809 if (!vdev_ctx || !vdev_ctx->mlo_dev_ctx) 810 return; 811 812 t2lm_ctx = &vdev_ctx->mlo_dev_ctx->t2lm_ctx; 813 t2lm_timer = &vdev_ctx->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 814 815 wlan_mlo_t2lm_timer_stop(vdev_ctx); 816 817 /* Since qdf_mutex_acquire cannot be called from interrupt context, 818 * change needed to create a workqueue and offload the timer expiry 819 * handling to workqueue. 820 */ 821 if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present) { 822 wlan_mlo_t2lm_handle_expected_duration_expiry(t2lm_ctx, vdev); 823 wlan_send_tid_to_link_mapping( 824 vdev, &t2lm_ctx->established_t2lm.t2lm); 825 826 wlan_handle_t2lm_timer(vdev_ctx); 827 } else if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) { 828 wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, vdev); 829 wlan_send_tid_to_link_mapping( 830 vdev, &t2lm_ctx->established_t2lm.t2lm); 831 832 wlan_handle_t2lm_timer(vdev_ctx); 833 } 834 835 } 836 837 QDF_STATUS 838 wlan_mlo_t2lm_timer_init(struct wlan_objmgr_vdev *vdev) 839 { 840 struct wlan_t2lm_timer *t2lm_timer = NULL; 841 842 if (!vdev || !vdev->mlo_dev_ctx) 843 return QDF_STATUS_E_FAILURE; 844 845 t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 846 if (!t2lm_timer) { 847 t2lm_err("t2lm timer ctx is null"); 848 return QDF_STATUS_E_NULL_VALUE; 849 } 850 851 t2lm_dev_lock_create(&vdev->mlo_dev_ctx->t2lm_ctx); 852 t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx); 853 qdf_timer_init(NULL, &t2lm_timer->t2lm_timer, 854 wlan_mlo_t2lm_timer_expiry_handler, 855 vdev, QDF_TIMER_TYPE_WAKE_APPS); 856 857 t2lm_timer->timer_started = false; 858 t2lm_timer->timer_interval = 0; 859 t2lm_timer->timer_out_time = 0; 860 t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx); 861 return QDF_STATUS_SUCCESS; 862 } 863 864 QDF_STATUS 865 wlan_mlo_t2lm_timer_start(struct wlan_objmgr_vdev *vdev, 866 uint32_t interval) 867 { 868 struct wlan_t2lm_timer *t2lm_timer; 869 struct wlan_t2lm_context *t2lm_ctx; 870 uint32_t target_out_time; 871 872 if (!interval) { 873 t2lm_debug("Timer interval is 0"); 874 return QDF_STATUS_E_NULL_VALUE; 875 } 876 877 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 878 t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 879 if (!t2lm_timer) { 880 t2lm_err("t2lm timer ctx is null"); 881 return QDF_STATUS_E_NULL_VALUE; 882 } 883 884 interval = (interval * 1024) / 1000; 885 target_out_time = qdf_system_ticks_to_msecs(qdf_system_ticks()); 886 target_out_time += interval; 887 t2lm_debug("earlier timer @%u ms out, new @%u ms out", 888 t2lm_timer->timer_out_time, target_out_time); 889 890 /* sometimes the host process the beacon maybe delay, it may help for 891 * update the new expected time. 892 */ 893 if (t2lm_timer->timer_out_time && 894 (target_out_time > t2lm_timer->timer_out_time || 895 (t2lm_timer->timer_out_time - target_out_time) < 896 WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY)) 897 return QDF_STATUS_E_NULL_VALUE; 898 899 if (t2lm_timer->timer_started) 900 qdf_timer_stop(&t2lm_timer->t2lm_timer); 901 902 t2lm_debug("t2lm timer started with interval %d ms", interval); 903 t2lm_timer->timer_interval = interval; 904 t2lm_timer->timer_started = true; 905 t2lm_timer->timer_out_time = target_out_time; 906 qdf_timer_start(&t2lm_timer->t2lm_timer, t2lm_timer->timer_interval); 907 908 return QDF_STATUS_SUCCESS; 909 } 910 911 QDF_STATUS 912 wlan_mlo_t2lm_timer_stop(struct wlan_objmgr_vdev *vdev) 913 { 914 struct wlan_t2lm_timer *t2lm_timer; 915 916 if (!vdev || !vdev->mlo_dev_ctx) 917 return QDF_STATUS_E_NULL_VALUE; 918 919 t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 920 if (!t2lm_timer) { 921 t2lm_err("t2lm timer ctx is null"); 922 return QDF_STATUS_E_NULL_VALUE; 923 } 924 925 t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx); 926 if (t2lm_timer->timer_started) { 927 qdf_timer_stop(&t2lm_timer->t2lm_timer); 928 t2lm_timer->timer_started = false; 929 t2lm_timer->timer_interval = 0; 930 t2lm_timer->timer_out_time = 0; 931 } 932 t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx); 933 return QDF_STATUS_SUCCESS; 934 } 935 936 QDF_STATUS wlan_handle_t2lm_timer(struct wlan_objmgr_vdev *vdev) 937 { 938 struct wlan_t2lm_context *t2lm_ctx; 939 struct vdev_mlme_obj *vdev_mlme; 940 QDF_STATUS status = QDF_STATUS_SUCCESS; 941 942 if (!vdev || !vdev->mlo_dev_ctx) 943 return QDF_STATUS_E_NULL_VALUE; 944 945 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 946 947 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 948 if (!vdev_mlme) 949 return QDF_STATUS_E_FAILURE; 950 951 if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present) { 952 if (t2lm_ctx->established_t2lm.t2lm.expected_duration == 953 T2LM_EXPECTED_DURATION_MAX_VALUE) { 954 return status; 955 } 956 957 status = wlan_mlo_t2lm_timer_start( 958 vdev, 959 t2lm_ctx->established_t2lm.t2lm.expected_duration); 960 } else if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) { 961 status = wlan_mlo_t2lm_timer_start( 962 vdev, 963 t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time); 964 } 965 966 return status; 967 } 968 969 /** 970 * wlan_update_mapping_switch_time_expected_dur() - API to update the mapping 971 * switch time and expected duration. 972 * @vdev:Pointer to vdev 973 * @rx_t2lm: Pointer to received T2LM IE 974 * @tsf: TSF value of beacon/probe response 975 * 976 * Return: None 977 */ 978 static QDF_STATUS wlan_update_mapping_switch_time_expected_dur( 979 struct wlan_objmgr_vdev *vdev, 980 struct wlan_t2lm_context *rx_t2lm, uint64_t tsf) 981 { 982 struct wlan_t2lm_context *t2lm_ctx; 983 uint16_t tsf_bit25_10, ms_time; 984 985 tsf_bit25_10 = (tsf & WLAN_T2LM_MAPPING_SWITCH_TSF_BITS) >> 10; 986 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 987 988 t2lm_dev_lock_acquire(t2lm_ctx); 989 990 if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present && 991 rx_t2lm->established_t2lm.t2lm.expected_duration_present) { 992 /* Established T2LM is already saved in the T2LM context. 993 * T2LM IE in the beacon/probe response frame has the updated 994 * expected duration. 995 */ 996 if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid, 997 rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid, 998 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { 999 t2lm_ctx->established_t2lm.t2lm.expected_duration = 1000 rx_t2lm->established_t2lm.t2lm.expected_duration; 1001 } 1002 } else if (rx_t2lm->established_t2lm.t2lm.expected_duration_present && 1003 !rx_t2lm->established_t2lm.t2lm.mapping_switch_time_present) { 1004 /* Mapping switch time is already expired when STA receives the 1005 * T2LM IE from beacon/probe response frame. 1006 */ 1007 qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, 1008 &rx_t2lm->established_t2lm.t2lm, 1009 sizeof(struct wlan_t2lm_info)); 1010 wlan_send_tid_to_link_mapping( 1011 vdev, &t2lm_ctx->established_t2lm.t2lm); 1012 } 1013 1014 if (rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time_present) { 1015 if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid, 1016 rx_t2lm->upcoming_t2lm.t2lm.ieee_link_map_tid, 1017 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { 1018 t2lm_debug("Ongoing mapping is already established"); 1019 t2lm_dev_lock_release(t2lm_ctx); 1020 return QDF_STATUS_E_ALREADY; 1021 } 1022 1023 qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, 1024 &rx_t2lm->upcoming_t2lm.t2lm, 1025 sizeof(struct wlan_t2lm_info)); 1026 1027 ms_time = t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time; 1028 /* Per test, -300ms is fine */ 1029 if (ms_time > tsf_bit25_10) { 1030 t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time = 1031 (ms_time - tsf_bit25_10 - (3 * WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY)); 1032 } else { 1033 t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time = 1034 0xFFFF - (tsf_bit25_10 - ms_time) - (3 * WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY); 1035 } 1036 } 1037 1038 t2lm_dev_lock_release(t2lm_ctx); 1039 1040 return QDF_STATUS_SUCCESS; 1041 } 1042 1043 QDF_STATUS wlan_process_bcn_prbrsp_t2lm_ie( 1044 struct wlan_objmgr_vdev *vdev, 1045 struct wlan_t2lm_context *rx_t2lm_ie, uint64_t tsf) 1046 { 1047 struct wlan_t2lm_context *t2lm_ctx; 1048 QDF_STATUS status; 1049 1050 /* Do not parse the T2LM IE if STA is not in connected state */ 1051 if (!wlan_cm_is_vdev_connected(vdev)) 1052 return QDF_STATUS_SUCCESS; 1053 1054 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 1055 1056 status = wlan_update_mapping_switch_time_expected_dur( 1057 vdev, rx_t2lm_ie, tsf); 1058 if (QDF_IS_STATUS_ERROR(status)) 1059 return status; 1060 1061 t2lm_dev_lock_acquire(t2lm_ctx); 1062 if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present || 1063 t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) { 1064 wlan_handle_t2lm_timer(vdev); 1065 } 1066 t2lm_dev_lock_release(t2lm_ctx); 1067 1068 return QDF_STATUS_SUCCESS; 1069 } 1070 1071 int wlan_register_t2lm_link_update_notify_handler( 1072 wlan_mlo_t2lm_link_update_handler handler, 1073 struct wlan_mlo_dev_context *mldev) 1074 { 1075 struct wlan_t2lm_context *t2lm_ctx = &mldev->t2lm_ctx; 1076 int i; 1077 1078 for (i = 0; i < MAX_T2LM_HANDLERS; i++) { 1079 if (t2lm_ctx->is_valid_handler[i]) 1080 continue; 1081 1082 t2lm_ctx->link_update_handler[i] = handler; 1083 t2lm_ctx->is_valid_handler[i] = true; 1084 break; 1085 } 1086 1087 if (i == MAX_T2LM_HANDLERS) { 1088 t2lm_err("Failed to register the link disablement callback"); 1089 return -EINVAL; 1090 } 1091 1092 return i; 1093 } 1094 1095 void wlan_unregister_t2lm_link_update_notify_handler( 1096 struct wlan_mlo_dev_context *mldev, 1097 uint8_t index) 1098 { 1099 if (index >= MAX_T2LM_HANDLERS) 1100 return; 1101 1102 mldev->t2lm_ctx.link_update_handler[index] = NULL; 1103 mldev->t2lm_ctx.is_valid_handler[index] = false; 1104 } 1105 1106 QDF_STATUS wlan_mlo_dev_t2lm_notify_link_update( 1107 struct wlan_mlo_dev_context *mldev) 1108 { 1109 struct wlan_t2lm_context *t2lm_ctx = &mldev->t2lm_ctx; 1110 wlan_mlo_t2lm_link_update_handler handler; 1111 int i; 1112 1113 for (i = 0; i < MAX_T2LM_HANDLERS; i++) { 1114 if (!t2lm_ctx->is_valid_handler[i]) 1115 continue; 1116 1117 handler = t2lm_ctx->link_update_handler[i]; 1118 if (!handler) 1119 continue; 1120 1121 handler(mldev, 1122 &t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid[0]); 1123 } 1124 return QDF_STATUS_SUCCESS; 1125 } 1126 1127 QDF_STATUS 1128 wlan_mlo_t2lm_timer_deinit(struct wlan_objmgr_vdev *vdev) 1129 { 1130 struct wlan_t2lm_timer *t2lm_timer = NULL; 1131 1132 if (!vdev || !vdev->mlo_dev_ctx) 1133 return QDF_STATUS_E_FAILURE; 1134 1135 t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 1136 if (!t2lm_timer) { 1137 t2lm_err("t2lm timer ctx is null"); 1138 return QDF_STATUS_E_NULL_VALUE; 1139 } 1140 1141 t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx); 1142 t2lm_timer->timer_started = false; 1143 t2lm_timer->timer_interval = 0; 1144 t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx); 1145 qdf_timer_free(&t2lm_timer->t2lm_timer); 1146 t2lm_dev_lock_destroy(&vdev->mlo_dev_ctx->t2lm_ctx); 1147 return QDF_STATUS_SUCCESS; 1148 } 1149