1 /* 2 * Copyright (c) 2022-2024 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_mgr_cmn.h> 26 #include <qdf_util.h> 27 #include <wlan_cm_api.h> 28 #include "wlan_utility.h" 29 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE) 30 #include <wlan_t2lm_api.h> 31 #endif 32 #include <wlan_mlo_mgr_sta.h> 33 34 QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie, 35 struct wlan_t2lm_info *t2lm) 36 { 37 struct wlan_ie_tid_to_link_mapping *t2lm_ie; 38 enum wlan_t2lm_direction dir; 39 uint8_t *t2lm_control_field; 40 uint16_t t2lm_control; 41 uint8_t link_mapping_presence_ind = 0; 42 uint8_t *link_mapping_of_tids; 43 uint8_t tid_num; 44 uint8_t *ie_ptr = NULL; 45 46 t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)ie; 47 48 t2lm_control_field = t2lm_ie->data; 49 if (!t2lm_control_field) { 50 t2lm_err("t2lm_control_field is null"); 51 return QDF_STATUS_E_NULL_VALUE; 52 } 53 54 t2lm_control = qdf_le16_to_cpu(*(uint16_t *)t2lm_control_field); 55 56 dir = QDF_GET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX, 57 WLAN_T2LM_CONTROL_DIRECTION_BITS); 58 if (dir > WLAN_T2LM_BIDI_DIRECTION) { 59 t2lm_err("Invalid direction"); 60 return QDF_STATUS_E_NULL_VALUE; 61 } 62 63 t2lm->direction = dir; 64 t2lm->default_link_mapping = 65 QDF_GET_BITS(t2lm_control, 66 WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_IDX, 67 WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS); 68 69 t2lm->mapping_switch_time_present = 70 QDF_GET_BITS(t2lm_control, 71 WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX, 72 WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS); 73 74 t2lm->expected_duration_present = 75 QDF_GET_BITS(t2lm_control, 76 WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX, 77 WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS); 78 79 t2lm->link_mapping_size = 80 QDF_GET_BITS(t2lm_control, 81 WLAN_T2LM_CONTROL_LINK_MAPPING_SIZE_IDX, 82 WLAN_T2LM_CONTROL_LINK_MAPPING_SIZE_BITS); 83 84 t2lm_debug("direction:%d default_link_mapping:%d mapping_switch_time_present:%d expected_duration_present:%d link_mapping_size:%d", 85 t2lm->direction, t2lm->default_link_mapping, 86 t2lm->mapping_switch_time_present, 87 t2lm->expected_duration_present, 88 t2lm->link_mapping_size); 89 90 if (t2lm->default_link_mapping) { 91 ie_ptr = t2lm_control_field + sizeof(uint8_t); 92 } else { 93 link_mapping_presence_ind = 94 QDF_GET_BITS(t2lm_control, 95 WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX, 96 WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS); 97 ie_ptr = t2lm_control_field + sizeof(t2lm_control); 98 } 99 100 if (t2lm->mapping_switch_time_present) { 101 t2lm->mapping_switch_time = 102 qdf_le16_to_cpu(*(uint16_t *)ie_ptr); 103 ie_ptr += sizeof(uint16_t); 104 } 105 106 if (t2lm->expected_duration_present) { 107 qdf_mem_copy(&t2lm->expected_duration, ie_ptr, 108 WLAN_T2LM_EXPECTED_DURATION_SIZE * 109 (sizeof(uint8_t))); 110 ie_ptr += WLAN_T2LM_EXPECTED_DURATION_SIZE * (sizeof(uint8_t)); 111 } 112 113 t2lm_debug("mapping_switch_time:%d expected_duration:%d", 114 t2lm->mapping_switch_time, t2lm->expected_duration); 115 116 if (t2lm->default_link_mapping) 117 return QDF_STATUS_SUCCESS; 118 119 link_mapping_of_tids = ie_ptr; 120 121 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 122 if (!(link_mapping_presence_ind & BIT(tid_num))) 123 continue; 124 125 if (!t2lm->link_mapping_size) { 126 t2lm->ieee_link_map_tid[tid_num] = 127 qdf_le16_to_cpu(*(uint16_t *)link_mapping_of_tids); 128 link_mapping_of_tids += sizeof(uint16_t); 129 } else { 130 t2lm->ieee_link_map_tid[tid_num] = 131 *(uint8_t *)link_mapping_of_tids; 132 link_mapping_of_tids += sizeof(uint8_t); 133 } 134 135 t2lm_rl_debug("link mapping of TID%d is %x", tid_num, 136 t2lm->ieee_link_map_tid[tid_num]); 137 } 138 139 return QDF_STATUS_SUCCESS; 140 } 141 142 QDF_STATUS wlan_mlo_parse_bcn_prbresp_t2lm_ie( 143 struct wlan_t2lm_context *t2lm_ctx, uint8_t *ie, 144 uint32_t frame_len) 145 { 146 struct wlan_t2lm_info t2lm = {0}; 147 struct extn_ie_header *ext_ie_hdr; 148 QDF_STATUS retval; 149 int i = 0; 150 uint32_t ie_len_parsed = 0; 151 152 qdf_mem_zero(&t2lm_ctx->established_t2lm, 153 sizeof(struct wlan_mlo_t2lm_ie)); 154 qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, sizeof(struct wlan_mlo_t2lm_ie)); 155 156 t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; 157 t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; 158 159 for (i = 0; i < WLAN_MAX_T2LM_IE; i++) { 160 if (!ie || !frame_len) { 161 t2lm_debug("ie is null or len is 0"); 162 return QDF_STATUS_E_NULL_VALUE; 163 } 164 165 if (frame_len == ie_len_parsed) 166 return QDF_STATUS_SUCCESS; 167 168 if (frame_len < (ie_len_parsed + 169 sizeof(struct extn_ie_header))) { 170 t2lm_debug("Frame length is lesser than parsed T2LM IE header length"); 171 continue; 172 } 173 174 ext_ie_hdr = (struct extn_ie_header *)ie; 175 176 if (!(ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM && 177 ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM)) 178 continue; 179 180 ie_len_parsed += ext_ie_hdr->ie_len + sizeof(struct ie_header); 181 if (frame_len < ie_len_parsed) { 182 t2lm_debug("Frame length is lesser than parsed T2LM IE length"); 183 continue; 184 } 185 186 t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; 187 retval = wlan_mlo_parse_t2lm_info(ie, &t2lm); 188 if (retval) { 189 t2lm_err("Failed to parse the T2LM IE"); 190 return retval; 191 } 192 193 if (!t2lm.mapping_switch_time_present && 194 t2lm.expected_duration_present) { 195 qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, &t2lm, 196 sizeof(struct wlan_t2lm_info)); 197 } else if (t2lm.mapping_switch_time_present) { 198 qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, &t2lm, 199 sizeof(struct wlan_t2lm_info)); 200 } 201 202 ie += ext_ie_hdr->ie_len + sizeof(struct ie_header); 203 } 204 205 return QDF_STATUS_SUCCESS; 206 } 207 208 QDF_STATUS wlan_mlo_parse_t2lm_ie( 209 struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie, 210 uint32_t frame_len) 211 { 212 struct extn_ie_header *ext_ie_hdr = NULL; 213 QDF_STATUS retval; 214 enum wlan_t2lm_direction dir; 215 struct wlan_t2lm_info t2lm_info; 216 uint32_t ie_len_parsed = 0; 217 218 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) 219 t2lm->t2lm_info[dir].direction = WLAN_T2LM_INVALID_DIRECTION; 220 221 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 222 if (!ie || !frame_len) { 223 t2lm_err("ie is null or len is 0"); 224 return QDF_STATUS_E_NULL_VALUE; 225 } 226 227 if (frame_len == ie_len_parsed) { 228 t2lm_debug("Received T2LM IEs are parsed successfully"); 229 return QDF_STATUS_SUCCESS; 230 } 231 232 if (frame_len < (ie_len_parsed + 233 sizeof(struct extn_ie_header))) { 234 t2lm_err("Frame length %d is lesser than parsed T2LM IE header length %zu", 235 frame_len, 236 ie_len_parsed + sizeof(struct extn_ie_header)); 237 return QDF_STATUS_E_PROTO; 238 } 239 240 ext_ie_hdr = (struct extn_ie_header *)ie; 241 242 if (ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM && 243 ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM) { 244 ie_len_parsed += ext_ie_hdr->ie_len + sizeof(struct ie_header); 245 if (frame_len < ie_len_parsed) { 246 t2lm_err("Frame length is lesser than parsed T2LM IE length"); 247 return QDF_STATUS_E_PROTO; 248 } 249 qdf_mem_zero(&t2lm_info, sizeof(t2lm_info)); 250 retval = wlan_mlo_parse_t2lm_info(ie, &t2lm_info); 251 if (!retval && 252 t2lm_info.direction < WLAN_T2LM_MAX_DIRECTION) { 253 qdf_mem_copy(&t2lm->t2lm_info[t2lm_info.direction], 254 &t2lm_info, 255 sizeof(struct wlan_t2lm_info)); 256 } else { 257 t2lm_err("Failed to parse the T2LM IE"); 258 return retval; 259 } 260 ie += ext_ie_hdr->ie_len + sizeof(struct ie_header); 261 } 262 } 263 264 if ((t2lm->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction == 265 WLAN_T2LM_DL_DIRECTION || 266 t2lm->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction == 267 WLAN_T2LM_UL_DIRECTION) && 268 t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction == 269 WLAN_T2LM_BIDI_DIRECTION) { 270 t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time"); 271 272 qdf_mem_zero(t2lm, sizeof(*t2lm)); 273 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 274 t2lm->t2lm_info[dir].direction = 275 WLAN_T2LM_INVALID_DIRECTION; 276 } 277 278 return QDF_STATUS_E_FAILURE; 279 } 280 281 return QDF_STATUS_SUCCESS; 282 } 283 284 uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm, 285 struct wlan_objmgr_vdev *vdev) 286 { 287 struct wlan_ie_tid_to_link_mapping *t2lm_ie; 288 uint16_t t2lm_control = 0; 289 uint8_t *t2lm_control_field; 290 uint8_t *link_mapping_of_tids; 291 uint8_t tid_num; 292 uint8_t num_tids = 0; 293 uint8_t link_mapping_presence_indicator = 0; 294 struct vdev_mlme_obj *vdev_mlme; 295 uint8_t *tmp_frm = frm; 296 297 t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)frm; 298 t2lm_ie->elem_id = WLAN_ELEMID_EXTN_ELEM; 299 t2lm_ie->elem_id_extn = WLAN_EXTN_ELEMID_T2LM; 300 301 t2lm_ie->elem_len = sizeof(*t2lm_ie) - sizeof(struct ie_header); 302 303 t2lm_control_field = t2lm_ie->data; 304 305 QDF_SET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX, 306 WLAN_T2LM_CONTROL_DIRECTION_BITS, t2lm->direction); 307 308 QDF_SET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_IDX, 309 WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS, 310 t2lm->default_link_mapping); 311 312 QDF_SET_BITS(t2lm_control, 313 WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX, 314 WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS, 315 t2lm->mapping_switch_time_present); 316 317 QDF_SET_BITS(t2lm_control, 318 WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX, 319 WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS, 320 t2lm->expected_duration_present); 321 322 QDF_SET_BITS(t2lm_control, 323 WLAN_T2LM_CONTROL_LINK_MAPPING_SIZE_IDX, 324 WLAN_T2LM_CONTROL_LINK_MAPPING_SIZE_BITS, 325 t2lm->link_mapping_size); 326 327 if (t2lm->default_link_mapping) { 328 /* Link mapping of TIDs are not present when default mapping is 329 * set. Hence, the size of TID-To-Link mapping control is one 330 * octet. 331 */ 332 *t2lm_control_field = (uint8_t)t2lm_control; 333 334 t2lm_ie->elem_len += sizeof(uint8_t); 335 336 t2lm_rl_debug("T2LM IE added, default_link_mapping: %d dir:%d", 337 t2lm->default_link_mapping, t2lm->direction); 338 339 frm += sizeof(*t2lm_ie) + sizeof(uint8_t); 340 } else { 341 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) 342 if (t2lm->hw_link_map_tid[tid_num] || 343 t2lm->ieee_link_map_tid[tid_num]) 344 link_mapping_presence_indicator |= BIT(tid_num); 345 346 QDF_SET_BITS(t2lm_control, 347 WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX, 348 WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS, 349 link_mapping_presence_indicator); 350 t2lm_rl_debug("T2LM IE added, direction:%d link_mapping_presence_indicator:%x", 351 t2lm->direction, link_mapping_presence_indicator); 352 353 /* The size of TID-To-Link mapping control is two octets when 354 * default link mapping is not set. 355 */ 356 *(uint16_t *)t2lm_control_field = htole16(t2lm_control); 357 frm += sizeof(*t2lm_ie) + sizeof(uint16_t); 358 t2lm_ie->elem_len += sizeof(uint16_t); 359 } 360 361 if (t2lm->mapping_switch_time_present) { 362 /* Mapping switch time is different for each vdevs. Hence, 363 * populate the mapping switch time from vdev_mlme_obj. 364 */ 365 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 366 if (!vdev_mlme) { 367 t2lm_err("null vdev_mlme"); 368 return tmp_frm; 369 } 370 371 *(uint16_t *)frm = 372 htole16(vdev_mlme->proto.ap.mapping_switch_time); 373 frm += sizeof(uint16_t); 374 t2lm_ie->elem_len += sizeof(uint16_t); 375 } 376 377 if (t2lm->expected_duration_present) { 378 qdf_mem_copy(frm, &t2lm->expected_duration, 379 WLAN_T2LM_EXPECTED_DURATION_SIZE * 380 sizeof(uint8_t)); 381 frm += WLAN_T2LM_EXPECTED_DURATION_SIZE * sizeof(uint8_t); 382 t2lm_ie->elem_len += 383 WLAN_T2LM_EXPECTED_DURATION_SIZE * sizeof(uint8_t); 384 } 385 386 t2lm_rl_debug("mapping_switch_time:%d expected_duration:%u", 387 t2lm->mapping_switch_time, t2lm->expected_duration); 388 389 if (t2lm->default_link_mapping) 390 return frm; 391 392 link_mapping_of_tids = frm; 393 394 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 395 if (!t2lm->ieee_link_map_tid[tid_num]) 396 continue; 397 398 if (!t2lm->link_mapping_size) { 399 *(uint16_t *)link_mapping_of_tids = 400 htole16(t2lm->ieee_link_map_tid[tid_num]); 401 t2lm_rl_debug("link mapping of TID%d is %x", 402 tid_num, 403 htole16(t2lm->ieee_link_map_tid[tid_num])); 404 link_mapping_of_tids += sizeof(uint16_t); 405 } else { 406 *(uint8_t *)link_mapping_of_tids = 407 t2lm->ieee_link_map_tid[tid_num]; 408 t2lm_rl_debug("link mapping of TID%d is %x", 409 tid_num, 410 t2lm->ieee_link_map_tid[tid_num]); 411 link_mapping_of_tids += sizeof(uint8_t); 412 } 413 num_tids++; 414 } 415 416 if (!t2lm->link_mapping_size) { 417 frm += num_tids * sizeof(uint16_t); 418 t2lm_ie->elem_len += (num_tids * sizeof(uint16_t)); 419 } else { 420 frm += num_tids * sizeof(uint8_t); 421 t2lm_ie->elem_len += (num_tids * sizeof(uint8_t)); 422 } 423 424 return frm; 425 } 426 427 uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, 428 struct wlan_t2lm_onging_negotiation_info *t2lm, 429 struct wlan_objmgr_vdev *vdev) 430 { 431 uint8_t dir; 432 433 if (!frm) { 434 t2lm_err("frm is null"); 435 return NULL; 436 } 437 438 if (!t2lm) { 439 t2lm_err("t2lm is null"); 440 return NULL; 441 } 442 443 /* As per spec, the frame should include one or two T2LM IEs. When it is 444 * two, then direction should DL and UL. 445 */ 446 if ((t2lm->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction == 447 WLAN_T2LM_DL_DIRECTION || 448 t2lm->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction == 449 WLAN_T2LM_UL_DIRECTION) && 450 t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction == 451 WLAN_T2LM_BIDI_DIRECTION) { 452 t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time"); 453 return NULL; 454 } 455 456 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 457 if (t2lm->t2lm_info[dir].direction != 458 WLAN_T2LM_INVALID_DIRECTION) 459 frm = wlan_mlo_add_t2lm_info_ie(frm, 460 &t2lm->t2lm_info[dir], 461 vdev); 462 } 463 464 return frm; 465 } 466 467 /** 468 * wlan_mlo_parse_t2lm_request_action_frame() - API to parse T2LM request action 469 * frame. 470 * @t2lm: Pointer to T2LM structure 471 * @action_frm: Pointer to action frame 472 * @frame_len: Received frame pointer 473 * @category: T2LM action frame category 474 * 475 * Return: QDF_STATUS 476 */ 477 static QDF_STATUS wlan_mlo_parse_t2lm_request_action_frame( 478 struct wlan_t2lm_onging_negotiation_info *t2lm, 479 struct wlan_action_frame *action_frm, 480 uint32_t frame_len, 481 enum wlan_t2lm_category category) 482 { 483 uint8_t *t2lm_action_frm; 484 uint32_t ie_len_parsed; 485 486 t2lm->category = category; 487 488 /* 489 * T2LM request action frame 490 * 491 * 1-byte 1-byte 1-byte variable 492 *------------------------------------------- 493 * | | | | | 494 * | Category| Protected | Dialog | T2LM IE | 495 * | | EHT | token | | 496 * | | Action | | | 497 *------------------------------------------- 498 */ 499 500 ie_len_parsed = sizeof(*action_frm) + sizeof(uint8_t); 501 502 if (frame_len < ie_len_parsed) { 503 t2lm_err("Action frame length %d too short", frame_len); 504 return QDF_STATUS_E_FAILURE; 505 } 506 507 t2lm_action_frm = (uint8_t *)action_frm + sizeof(*action_frm); 508 509 t2lm->dialog_token = *t2lm_action_frm; 510 511 return wlan_mlo_parse_t2lm_ie(t2lm, 512 t2lm_action_frm + sizeof(uint8_t), 513 frame_len - ie_len_parsed); 514 } 515 516 /** 517 * wlan_mlo_parse_t2lm_response_action_frame() - API to parse T2LM response 518 * action frame. 519 * @t2lm: Pointer to T2LM structure 520 * @action_frm: Pointer to action frame 521 * @frame_len: Action frame length 522 * @category: T2LM action frame category 523 * 524 * Return: QDF_STATUS 525 */ 526 static QDF_STATUS wlan_mlo_parse_t2lm_response_action_frame( 527 struct wlan_t2lm_onging_negotiation_info *t2lm, 528 struct wlan_action_frame *action_frm, 529 uint32_t frame_len, 530 enum wlan_t2lm_category category) 531 { 532 uint8_t *t2lm_action_frm; 533 QDF_STATUS ret_val = QDF_STATUS_SUCCESS; 534 uint32_t ie_len_parsed; 535 536 t2lm->category = WLAN_T2LM_CATEGORY_RESPONSE; 537 /* 538 * T2LM response action frame 539 * 540 * 1-byte 1-byte 1-byte 2-byte variable 541 *---------------------------------------------------- 542 * | | | | | | 543 * | Category| Protected | Dialog | Status | T2LM IE | 544 * | | EHT | token | code | | 545 * | | Action | | | | 546 *---------------------------------------------------- 547 */ 548 549 ie_len_parsed = sizeof(*action_frm) + sizeof(uint8_t) + 550 sizeof(uint16_t); 551 552 if (frame_len < ie_len_parsed) { 553 t2lm_err("Action frame length %d too short", frame_len); 554 return QDF_STATUS_E_FAILURE; 555 } 556 557 t2lm_action_frm = (uint8_t *)action_frm + sizeof(*action_frm); 558 559 t2lm->dialog_token = *t2lm_action_frm; 560 t2lm->t2lm_resp_type = 561 qdf_le16_to_cpu(*(uint16_t *)(t2lm_action_frm + sizeof(uint8_t))); 562 563 if (t2lm->t2lm_resp_type == 564 WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) { 565 t2lm_action_frm += sizeof(uint8_t) + sizeof(uint16_t); 566 ret_val = wlan_mlo_parse_t2lm_ie(t2lm, t2lm_action_frm, 567 frame_len - ie_len_parsed); 568 } 569 570 return ret_val; 571 } 572 573 int wlan_mlo_parse_t2lm_action_frame( 574 struct wlan_t2lm_onging_negotiation_info *t2lm, 575 struct wlan_action_frame *action_frm, 576 uint32_t frame_len, 577 enum wlan_t2lm_category category) 578 { 579 QDF_STATUS ret_val = QDF_STATUS_SUCCESS; 580 581 switch (category) { 582 case WLAN_T2LM_CATEGORY_REQUEST: 583 { 584 ret_val = wlan_mlo_parse_t2lm_request_action_frame( 585 t2lm, action_frm, frame_len, category); 586 return qdf_status_to_os_return(ret_val); 587 } 588 case WLAN_T2LM_CATEGORY_RESPONSE: 589 { 590 ret_val = wlan_mlo_parse_t2lm_response_action_frame( 591 t2lm, action_frm, frame_len, category); 592 593 return qdf_status_to_os_return(ret_val); 594 } 595 case WLAN_T2LM_CATEGORY_TEARDOWN: 596 /* Nothing to parse from T2LM teardown frame, just reset 597 * the mapping to default mapping. 598 * 599 * T2LM teardown action frame 600 * 601 * 1-byte 1-byte 602 *------------------------ 603 * | | | 604 * | Category| Protected | 605 * | | EHT | 606 * | | Action | 607 *------------------------ 608 */ 609 break; 610 default: 611 t2lm_err("Invalid category:%d", category); 612 } 613 614 return ret_val; 615 } 616 617 static uint8_t *wlan_mlo_add_t2lm_request_action_frame( 618 uint8_t *frm, 619 struct wlan_action_frame_args *args, uint8_t *buf, 620 enum wlan_t2lm_category category) 621 { 622 *frm++ = args->category; 623 *frm++ = args->action; 624 /* Dialog token*/ 625 *frm++ = args->arg1; 626 627 t2lm_info("T2LM request frame: category:%d action:%d dialog_token:%d", 628 args->category, args->action, args->arg1); 629 return wlan_mlo_add_t2lm_ie(frm, (void *)buf, NULL); 630 } 631 632 static uint8_t *wlan_mlo_add_t2lm_response_action_frame( 633 uint8_t *frm, 634 struct wlan_action_frame_args *args, uint8_t *buf, 635 enum wlan_t2lm_category category) 636 { 637 *frm++ = args->category; 638 *frm++ = args->action; 639 /* Dialog token*/ 640 *frm++ = args->arg1; 641 /* Status code (2 bytes)*/ 642 *(uint16_t *)frm = htole16(args->arg2); 643 frm += sizeof(uint16_t); 644 645 t2lm_info("T2LM response frame: category:%d action:%d dialog_token:%d status_code:%d", 646 args->category, args->action, args->arg1, args->arg2); 647 648 if (args->arg2 == WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) 649 frm = wlan_mlo_add_t2lm_ie(frm, (void *)buf, NULL); 650 651 return frm; 652 } 653 654 uint8_t *wlan_mlo_add_t2lm_action_frame( 655 uint8_t *frm, 656 struct wlan_action_frame_args *args, uint8_t *buf, 657 enum wlan_t2lm_category category) 658 { 659 660 switch (category) { 661 case WLAN_T2LM_CATEGORY_REQUEST: 662 return wlan_mlo_add_t2lm_request_action_frame(frm, args, 663 buf, category); 664 case WLAN_T2LM_CATEGORY_RESPONSE: 665 return wlan_mlo_add_t2lm_response_action_frame(frm, args, 666 buf, category); 667 case WLAN_T2LM_CATEGORY_TEARDOWN: 668 *frm++ = args->category; 669 *frm++ = args->action; 670 return frm; 671 default: 672 t2lm_err("Invalid category:%d", category); 673 } 674 675 return frm; 676 } 677 678 /** 679 * wlan_mlo_t2lm_handle_mapping_switch_time_expiry() - API to handle the mapping 680 * switch timer expiry. 681 * @t2lm_ctx: Pointer to T2LM context 682 * @vdev: Pointer to vdev structure 683 * 684 * Return: None 685 */ 686 static void wlan_mlo_t2lm_handle_mapping_switch_time_expiry( 687 struct wlan_t2lm_context *t2lm_ctx, 688 struct wlan_objmgr_vdev *vdev) 689 { 690 struct wlan_t2lm_info *t2lm; 691 692 t2lm_debug("Mapping switch time expired for vdev_id:%d ", 693 wlan_vdev_get_id(vdev)); 694 695 qdf_mem_copy(&t2lm_ctx->established_t2lm, &t2lm_ctx->upcoming_t2lm, 696 sizeof(struct wlan_mlo_t2lm_ie)); 697 698 t2lm_ctx->established_t2lm.t2lm.mapping_switch_time_present = false; 699 t2lm_ctx->established_t2lm.t2lm.mapping_switch_time = 0; 700 701 t2lm = &t2lm_ctx->established_t2lm.t2lm; 702 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", 703 t2lm_ctx->established_t2lm.disabled_link_bitmap, 704 t2lm->direction, t2lm->default_link_mapping, 705 t2lm->mapping_switch_time_present, 706 t2lm->expected_duration_present, 707 t2lm->mapping_switch_time, t2lm->expected_duration, 708 t2lm->ieee_link_map_tid[0], t2lm->hw_link_map_tid[0]); 709 710 qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, sizeof(struct wlan_mlo_t2lm_ie)); 711 t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; 712 } 713 714 /** 715 * wlan_mlo_t2lm_handle_expected_duration_expiry() - API to handle the expected 716 * duration timer expiry. 717 * @t2lm_ctx: Pointer to T2LM context 718 * @vdev: Pointer to vdev structure 719 * 720 * Return: none 721 */ 722 static void wlan_mlo_t2lm_handle_expected_duration_expiry( 723 struct wlan_t2lm_context *t2lm_ctx, 724 struct wlan_objmgr_vdev *vdev) 725 { 726 t2lm_debug("Expected duration expired for vdev_id:%d ", 727 wlan_vdev_get_id(vdev)); 728 729 if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) { 730 /* Copy the new non-default ongoing mapping to established 731 * mapping if expected duration expires for the established 732 * mapping. 733 */ 734 wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, 735 vdev); 736 return; 737 } 738 739 /* Use the default mapping when expected duration expires for the 740 * established mapping and no new non-default T2LM announcement is 741 * ongoing. 742 */ 743 qdf_mem_zero(&t2lm_ctx->established_t2lm, 744 sizeof(struct wlan_mlo_t2lm_ie)); 745 746 t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_BIDI_DIRECTION; 747 t2lm_ctx->established_t2lm.t2lm.default_link_mapping = 1; 748 t2lm_ctx->established_t2lm.disabled_link_bitmap = 0; 749 t2lm_ctx->established_t2lm.t2lm.link_mapping_size = 0; 750 t2lm_debug("Set established mapping to default mapping"); 751 752 wlan_clear_peer_level_tid_to_link_mapping(vdev); 753 } 754 755 QDF_STATUS wlan_mlo_vdev_tid_to_link_map_event( 756 struct wlan_objmgr_psoc *psoc, 757 struct mlo_vdev_host_tid_to_link_map_resp *event) 758 { 759 struct wlan_objmgr_vdev *vdev; 760 struct wlan_t2lm_context *t2lm_ctx; 761 struct vdev_mlme_obj *vdev_mlme; 762 763 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id, 764 WLAN_MLO_MGR_ID); 765 if (!vdev) { 766 t2lm_err("null vdev"); 767 return QDF_STATUS_E_NULL_VALUE; 768 } 769 770 if (!vdev->mlo_dev_ctx) { 771 t2lm_err("null mlo_dev_ctx"); 772 return QDF_STATUS_E_NULL_VALUE; 773 } 774 775 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 776 if (!vdev_mlme) { 777 t2lm_err("null vdev_mlme"); 778 return QDF_STATUS_E_FAILURE; 779 } 780 781 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 782 783 t2lm_debug("psoc_id:%d vdev_id:%d status:%d", 784 wlan_psoc_get_id(psoc), event->vdev_id, event->status); 785 786 t2lm_dev_lock_acquire(t2lm_ctx); 787 switch (event->status) { 788 case WLAN_MAP_SWITCH_TIMER_TSF: 789 790 /* Mapping switch time is different for each AP vdev of a given 791 * MLD as these vdevs can have separate beacon TDF value. 792 */ 793 if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) 794 vdev_mlme->proto.ap.mapping_switch_time = 795 (event->mapping_switch_tsf & 796 WLAN_T2LM_MAPPING_SWITCH_TSF_BITS) >> 10; 797 798 t2lm_debug("vdev_id:%d updated mapping switch time:%d", 799 event->vdev_id, 800 vdev_mlme->proto.ap.mapping_switch_time); 801 break; 802 case WLAN_MAP_SWITCH_TIMER_EXPIRED: 803 vdev_mlme->proto.ap.mapping_switch_time = 0; 804 wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, vdev); 805 806 /* Notify the registered caller about the link update*/ 807 wlan_mlo_dev_t2lm_notify_link_update(vdev, 808 &t2lm_ctx->established_t2lm.t2lm); 809 break; 810 case WLAN_EXPECTED_DUR_EXPIRED: 811 wlan_mlo_t2lm_handle_expected_duration_expiry(t2lm_ctx, vdev); 812 813 /* Notify the registered caller about the link update*/ 814 wlan_mlo_dev_t2lm_notify_link_update(vdev, 815 &t2lm_ctx->established_t2lm.t2lm); 816 break; 817 default: 818 t2lm_err("Invalid status"); 819 } 820 821 t2lm_dev_lock_release(t2lm_ctx); 822 mlo_release_vdev_ref(vdev); 823 824 return QDF_STATUS_SUCCESS; 825 } 826 827 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 828 static 829 QDF_STATUS wlan_send_t2lm_info(struct wlan_objmgr_vdev *vdev, 830 struct wlan_t2lm_info *t2lm, 831 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops) 832 { 833 QDF_STATUS status = QDF_STATUS_E_FAILURE; 834 835 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 836 t2lm_err("vdev is not MLO vdev"); 837 return status; 838 } 839 840 status = mlo_tx_ops->send_tid_to_link_mapping(vdev, t2lm); 841 if (QDF_IS_STATUS_ERROR(status)) 842 t2lm_err("Failed to send T2LM command to FW"); 843 844 return status; 845 } 846 #else 847 static 848 QDF_STATUS wlan_send_t2lm_info(struct wlan_objmgr_vdev *vdev, 849 struct wlan_t2lm_info *t2lm, 850 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops) 851 { 852 struct wlan_objmgr_vdev *co_mld_vdev; 853 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 854 uint16_t vdev_count = 0; 855 int i = 0; 856 QDF_STATUS status = QDF_STATUS_E_FAILURE; 857 858 mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list); 859 if (!vdev_count) { 860 t2lm_err("Number of VDEVs under MLD is reported as 0"); 861 return QDF_STATUS_E_NULL_VALUE; 862 } 863 864 for (i = 0; i < vdev_count; i++) { 865 co_mld_vdev = wlan_vdev_list[i]; 866 if (!co_mld_vdev) { 867 t2lm_err("co_mld_vdev is null"); 868 mlo_release_vdev_ref(co_mld_vdev); 869 continue; 870 } 871 872 if (mlo_is_sta_bridge_vdev(co_mld_vdev)) { 873 t2lm_debug("skip co_mld_vdev for bridge sta"); 874 mlo_release_vdev_ref(co_mld_vdev); 875 continue; 876 } 877 878 status = mlo_tx_ops->send_tid_to_link_mapping(co_mld_vdev, 879 t2lm); 880 if (QDF_IS_STATUS_ERROR(status)) 881 t2lm_err("Failed to send T2LM command to FW"); 882 mlo_release_vdev_ref(co_mld_vdev); 883 } 884 885 return status; 886 } 887 #endif 888 889 QDF_STATUS wlan_send_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev, 890 struct wlan_t2lm_info *t2lm) 891 { 892 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 893 struct wlan_objmgr_psoc *psoc; 894 QDF_STATUS status = QDF_STATUS_E_FAILURE; 895 896 psoc = wlan_vdev_get_psoc(vdev); 897 if (!psoc) { 898 t2lm_err("null psoc"); 899 return QDF_STATUS_E_NULL_VALUE; 900 } 901 902 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; 903 if (!mlo_tx_ops) { 904 t2lm_err("tx_ops is null!"); 905 return QDF_STATUS_E_NULL_VALUE; 906 } 907 908 if (!mlo_tx_ops->send_tid_to_link_mapping) { 909 t2lm_err("send_tid_to_link_mapping is null"); 910 return QDF_STATUS_E_NULL_VALUE; 911 } 912 913 status = wlan_send_t2lm_info(vdev, t2lm, mlo_tx_ops); 914 915 return status; 916 } 917 918 /** 919 * wlan_get_vdev_t2lm_mapping_status() - API to get vdev level T2LM info 920 * @vdev: vdev object 921 * @t2lm: T2LM info 922 * 923 * Return: QDF_STATUS 924 */ 925 static 926 QDF_STATUS wlan_get_vdev_t2lm_mapping_status(struct wlan_objmgr_vdev *vdev, 927 struct wlan_t2lm_info *t2lm) 928 { 929 struct wlan_t2lm_context *t2lm_ctx; 930 int i = 0; 931 932 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 933 934 t2lm_dev_lock_acquire(t2lm_ctx); 935 qdf_mem_copy(&t2lm[i++], &t2lm_ctx->established_t2lm.t2lm, 936 sizeof(struct wlan_t2lm_info)); 937 t2lm_dev_lock_release(t2lm_ctx); 938 939 return QDF_STATUS_SUCCESS; 940 } 941 942 /** 943 * wlan_get_peer_t2lm_mapping_status() - API to get peer level T2LM info 944 * @peer: peer object 945 * @t2lm: T2LM info 946 * 947 * Return: QDF_STATUS 948 */ 949 static 950 QDF_STATUS wlan_get_peer_t2lm_mapping_status(struct wlan_objmgr_peer *peer, 951 struct wlan_t2lm_info *t2lm) 952 { 953 enum wlan_t2lm_direction dir = WLAN_T2LM_INVALID_DIRECTION; 954 struct wlan_mlo_peer_context *ml_peer; 955 struct wlan_prev_t2lm_negotiated_info *t2lm_req; 956 int i = 0; 957 958 ml_peer = peer->mlo_peer_ctx; 959 if (!ml_peer) 960 return QDF_STATUS_E_FAILURE; 961 962 t2lm_req = &ml_peer->t2lm_policy.t2lm_negotiated_info; 963 if ((t2lm_req->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction == 964 WLAN_T2LM_DL_DIRECTION || 965 t2lm_req->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction == 966 WLAN_T2LM_UL_DIRECTION) && 967 t2lm_req->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction == 968 WLAN_T2LM_BIDI_DIRECTION) { 969 t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time"); 970 return QDF_STATUS_E_FAILURE; 971 } 972 973 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 974 if (t2lm_req->t2lm_info[dir].direction != 975 WLAN_T2LM_INVALID_DIRECTION) 976 qdf_mem_copy(&t2lm[i++], &t2lm_req->t2lm_info[dir], 977 sizeof(struct wlan_t2lm_info)); 978 } 979 980 if (i == 0) 981 return QDF_STATUS_E_EMPTY; 982 983 return QDF_STATUS_SUCCESS; 984 } 985 986 QDF_STATUS wlan_get_t2lm_mapping_status(struct wlan_objmgr_vdev *vdev, 987 struct wlan_t2lm_info *t2lm) 988 { 989 struct wlan_objmgr_peer *peer; 990 QDF_STATUS status = QDF_STATUS_E_FAILURE; 991 992 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID); 993 if (!peer) { 994 t2lm_err("peer not found"); 995 return QDF_STATUS_E_NULL_VALUE; 996 } 997 998 status = wlan_get_peer_t2lm_mapping_status(peer, t2lm); 999 if (QDF_IS_STATUS_SUCCESS(status)) { 1000 t2lm_debug("peer level T2LM info"); 1001 goto peer_release; 1002 } 1003 1004 t2lm_debug("vdev level T2LM info"); 1005 status = wlan_get_vdev_t2lm_mapping_status(vdev, t2lm); 1006 1007 peer_release: 1008 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 1009 1010 return status; 1011 } 1012 1013 QDF_STATUS 1014 wlan_send_peer_level_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev, 1015 struct wlan_objmgr_peer *peer) 1016 { 1017 uint8_t dir, idx = 0; 1018 struct wlan_mlo_peer_context *ml_peer; 1019 struct wlan_t2lm_info *t2lm_info; 1020 QDF_STATUS status = QDF_STATUS_E_NULL_VALUE; 1021 1022 if (!peer) { 1023 t2lm_err("peer is null"); 1024 return status; 1025 } 1026 1027 ml_peer = peer->mlo_peer_ctx; 1028 if (!ml_peer) { 1029 t2lm_err("ml peer is null"); 1030 return status; 1031 } 1032 1033 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 1034 t2lm_info = &ml_peer->t2lm_policy.t2lm_negotiated_info.t2lm_info[dir]; 1035 if (t2lm_info && t2lm_info->direction != 1036 WLAN_T2LM_INVALID_DIRECTION) { 1037 t2lm_debug("send peer-level mapping to FW for dir: %d", dir); 1038 1039 /* Notify the registered caller about the link update*/ 1040 wlan_mlo_dev_t2lm_notify_link_update(vdev, t2lm_info); 1041 status = wlan_send_tid_to_link_mapping(vdev, t2lm_info); 1042 idx++; 1043 } 1044 } 1045 1046 if (!idx) 1047 t2lm_debug("No peer-level mapping present"); 1048 1049 return status; 1050 } 1051 1052 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE) 1053 void 1054 wlan_clear_peer_level_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev) 1055 { 1056 struct wlan_objmgr_peer *peer; 1057 1058 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID); 1059 if (!peer) { 1060 t2lm_err("Peer not found"); 1061 return; 1062 } 1063 1064 wlan_t2lm_clear_peer_negotiation(peer); 1065 1066 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 1067 } 1068 #endif 1069 1070 void wlan_mlo_t2lm_timer_expiry_handler(void *vdev) 1071 { 1072 struct wlan_objmgr_vdev *vdev_ctx = (struct wlan_objmgr_vdev *)vdev; 1073 1074 struct wlan_t2lm_timer *t2lm_timer; 1075 struct wlan_t2lm_context *t2lm_ctx; 1076 1077 if (!vdev_ctx || !vdev_ctx->mlo_dev_ctx) 1078 return; 1079 1080 t2lm_ctx = &vdev_ctx->mlo_dev_ctx->t2lm_ctx; 1081 t2lm_timer = &vdev_ctx->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 1082 1083 wlan_mlo_t2lm_timer_stop(vdev_ctx); 1084 1085 /* Since qdf_mutex_acquire cannot be called from interrupt context, 1086 * change needed to create a workqueue and offload the timer expiry 1087 * handling to workqueue. 1088 */ 1089 if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present) { 1090 wlan_mlo_t2lm_handle_expected_duration_expiry(t2lm_ctx, vdev); 1091 1092 /* Notify the registered caller about the link update*/ 1093 wlan_mlo_dev_t2lm_notify_link_update(vdev_ctx, 1094 &t2lm_ctx->established_t2lm.t2lm); 1095 wlan_send_tid_to_link_mapping( 1096 vdev, &t2lm_ctx->established_t2lm.t2lm); 1097 1098 wlan_handle_t2lm_timer(vdev_ctx); 1099 } else if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) { 1100 wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, vdev); 1101 1102 /* Notify the registered caller about the link update*/ 1103 wlan_mlo_dev_t2lm_notify_link_update(vdev_ctx, 1104 &t2lm_ctx->established_t2lm.t2lm); 1105 wlan_send_tid_to_link_mapping( 1106 vdev, &t2lm_ctx->established_t2lm.t2lm); 1107 wlan_handle_t2lm_timer(vdev_ctx); 1108 } 1109 1110 } 1111 1112 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1113 /** 1114 * wlan_mlo_t2lm_update_peer_to_peer_negotiation() - API to update peer-to-peer 1115 * level T2LM negotiation data structure on mapping switch time expiry and 1116 * expected duration expiry. 1117 * @ml_dev: Pointer to ML dev structure 1118 * @ml_peer: Pointer to ML peer 1119 * @arg: Pointer to advertised T2LM structure 1120 * 1121 * Return: QDF_STATUS 1122 */ 1123 static QDF_STATUS wlan_mlo_t2lm_update_peer_to_peer_negotiation( 1124 struct wlan_mlo_dev_context *ml_dev, 1125 void *ml_peer, void *arg) 1126 { 1127 struct wlan_mlo_peer_context *mlo_peer; 1128 struct wlan_t2lm_info *t2lm; 1129 struct wlan_prev_t2lm_negotiated_info *negotiated_t2lm = NULL; 1130 uint8_t dir = 0; 1131 1132 mlo_peer = (struct wlan_mlo_peer_context *)ml_peer; 1133 if (!mlo_peer) { 1134 t2lm_err("null mlo_peer"); 1135 return QDF_STATUS_E_NULL_VALUE; 1136 } 1137 1138 t2lm = (struct wlan_t2lm_info *)arg; 1139 if (!t2lm) { 1140 t2lm_err("null T2LM"); 1141 return QDF_STATUS_E_NULL_VALUE; 1142 } 1143 1144 negotiated_t2lm = &mlo_peer->t2lm_policy.t2lm_negotiated_info; 1145 negotiated_t2lm->dialog_token = 0; 1146 1147 /* Reset the peer-to-peer level mapping to default mapping */ 1148 for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { 1149 negotiated_t2lm->t2lm_info[dir].direction = 1150 WLAN_T2LM_INVALID_DIRECTION; 1151 } 1152 1153 /* Copy the Advertised T2LM established mapping to peer-to-peer level 1154 * DIBI direction data structure. 1155 */ 1156 qdf_mem_copy(&negotiated_t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION], 1157 t2lm, sizeof(struct wlan_t2lm_info)); 1158 1159 return QDF_STATUS_SUCCESS; 1160 } 1161 1162 /** 1163 * wlan_mlo_t2lm_link_update_notifier_callback() - This callback API is invoked 1164 * when mapping switch timer expires and expected duration expires. 1165 * @vdev: Pointer to vdev structure 1166 * @t2lm: Pointer to advertised T2LM structure 1167 * 1168 * Return: QDF_STATUS 1169 */ 1170 static QDF_STATUS wlan_mlo_t2lm_link_update_notifier_callback( 1171 struct wlan_objmgr_vdev *vdev, 1172 struct wlan_t2lm_info *t2lm) 1173 { 1174 /* Go over all MLO peers on this MLD and clear the peer-to-peer level 1175 * mapping. 1176 */ 1177 wlan_mlo_iterate_ml_peerlist( 1178 vdev->mlo_dev_ctx, 1179 wlan_mlo_t2lm_update_peer_to_peer_negotiation, t2lm); 1180 1181 return QDF_STATUS_SUCCESS; 1182 } 1183 1184 QDF_STATUS wlan_mlo_t2lm_register_link_update_notify_handler( 1185 struct wlan_mlo_dev_context *ml_dev) 1186 { 1187 ml_dev->t2lm_ctx.link_update_callback_index = 1188 wlan_register_t2lm_link_update_notify_handler( 1189 wlan_mlo_t2lm_link_update_notifier_callback, 1190 ml_dev); 1191 1192 return QDF_STATUS_SUCCESS; 1193 } 1194 #endif 1195 1196 QDF_STATUS 1197 wlan_mlo_t2lm_timer_init(struct wlan_objmgr_vdev *vdev) 1198 { 1199 struct wlan_t2lm_timer *t2lm_timer = NULL; 1200 1201 if (!vdev || !vdev->mlo_dev_ctx) 1202 return QDF_STATUS_E_FAILURE; 1203 1204 t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 1205 if (!t2lm_timer) { 1206 t2lm_err("t2lm timer ctx is null"); 1207 return QDF_STATUS_E_NULL_VALUE; 1208 } 1209 1210 t2lm_dev_lock_create(&vdev->mlo_dev_ctx->t2lm_ctx); 1211 t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx); 1212 qdf_timer_init(NULL, &t2lm_timer->t2lm_timer, 1213 wlan_mlo_t2lm_timer_expiry_handler, 1214 vdev, QDF_TIMER_TYPE_WAKE_APPS); 1215 1216 t2lm_timer->timer_started = false; 1217 t2lm_timer->timer_interval = 0; 1218 t2lm_timer->timer_out_time = 0; 1219 t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx); 1220 return QDF_STATUS_SUCCESS; 1221 } 1222 1223 QDF_STATUS 1224 wlan_mlo_t2lm_timer_start(struct wlan_objmgr_vdev *vdev, 1225 uint32_t interval) 1226 { 1227 struct wlan_t2lm_timer *t2lm_timer; 1228 struct wlan_t2lm_context *t2lm_ctx; 1229 uint32_t target_out_time; 1230 struct wlan_mlo_dev_context *mlo_dev_ctx; 1231 1232 if (!interval) { 1233 t2lm_debug("Timer interval is 0"); 1234 return QDF_STATUS_E_NULL_VALUE; 1235 } 1236 1237 if (!vdev) 1238 return QDF_STATUS_E_NULL_VALUE; 1239 1240 mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); 1241 if (!mlo_dev_ctx) 1242 return QDF_STATUS_E_NULL_VALUE; 1243 1244 t2lm_ctx = &mlo_dev_ctx->t2lm_ctx; 1245 t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 1246 if (!t2lm_timer) { 1247 t2lm_err("t2lm timer ctx is null"); 1248 return QDF_STATUS_E_NULL_VALUE; 1249 } 1250 1251 interval = (interval * 1024) / 1000; 1252 target_out_time = qdf_system_ticks_to_msecs(qdf_system_ticks()); 1253 target_out_time += interval; 1254 t2lm_debug("earlier timer @%u ms out, new @%u ms out", 1255 t2lm_timer->timer_out_time, target_out_time); 1256 1257 /* sometimes the host process the beacon maybe delay, it may help for 1258 * update the new expected time. 1259 */ 1260 if (t2lm_timer->timer_out_time && 1261 (target_out_time > t2lm_timer->timer_out_time || 1262 (t2lm_timer->timer_out_time - target_out_time) < 1263 WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY)) 1264 return QDF_STATUS_E_NULL_VALUE; 1265 1266 if (t2lm_timer->timer_started) 1267 qdf_timer_stop(&t2lm_timer->t2lm_timer); 1268 1269 t2lm_debug("t2lm timer started with interval %d ms", interval); 1270 t2lm_timer->timer_interval = interval; 1271 t2lm_timer->timer_started = true; 1272 t2lm_timer->timer_out_time = target_out_time; 1273 qdf_timer_start(&t2lm_timer->t2lm_timer, t2lm_timer->timer_interval); 1274 1275 return QDF_STATUS_SUCCESS; 1276 } 1277 1278 QDF_STATUS 1279 wlan_mlo_t2lm_timer_stop(struct wlan_objmgr_vdev *vdev) 1280 { 1281 struct wlan_t2lm_timer *t2lm_timer; 1282 1283 if (!vdev || !vdev->mlo_dev_ctx) 1284 return QDF_STATUS_E_NULL_VALUE; 1285 1286 t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 1287 if (!t2lm_timer) { 1288 t2lm_err("t2lm timer ctx is null"); 1289 return QDF_STATUS_E_NULL_VALUE; 1290 } 1291 1292 if (t2lm_timer->timer_started) { 1293 qdf_timer_stop(&t2lm_timer->t2lm_timer); 1294 t2lm_timer->timer_started = false; 1295 t2lm_timer->timer_interval = 0; 1296 t2lm_timer->timer_out_time = 0; 1297 } 1298 return QDF_STATUS_SUCCESS; 1299 } 1300 1301 QDF_STATUS wlan_handle_t2lm_timer(struct wlan_objmgr_vdev *vdev) 1302 { 1303 struct wlan_t2lm_context *t2lm_ctx; 1304 struct vdev_mlme_obj *vdev_mlme; 1305 QDF_STATUS status = QDF_STATUS_SUCCESS; 1306 1307 if (!vdev || !vdev->mlo_dev_ctx) 1308 return QDF_STATUS_E_NULL_VALUE; 1309 1310 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 1311 1312 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 1313 if (!vdev_mlme) 1314 return QDF_STATUS_E_FAILURE; 1315 1316 if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present) { 1317 if (t2lm_ctx->established_t2lm.t2lm.expected_duration == 1318 T2LM_EXPECTED_DURATION_MAX_VALUE) { 1319 return status; 1320 } 1321 1322 status = wlan_mlo_t2lm_timer_start( 1323 vdev, 1324 t2lm_ctx->established_t2lm.t2lm.expected_duration); 1325 } else if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) { 1326 status = wlan_mlo_t2lm_timer_start( 1327 vdev, 1328 t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time); 1329 } 1330 1331 return status; 1332 } 1333 1334 /** 1335 * wlan_update_mapping_switch_time_expected_dur() - API to update the mapping 1336 * switch time and expected duration. 1337 * @vdev:Pointer to vdev 1338 * @rx_t2lm: Pointer to received T2LM IE 1339 * @tsf: TSF value of beacon/probe response 1340 * 1341 * Return: None 1342 */ 1343 static QDF_STATUS wlan_update_mapping_switch_time_expected_dur( 1344 struct wlan_objmgr_vdev *vdev, 1345 struct wlan_t2lm_context *rx_t2lm, uint64_t tsf) 1346 { 1347 struct wlan_t2lm_context *t2lm_ctx; 1348 uint16_t tsf_bit25_10, ms_time; 1349 struct wlan_mlo_dev_context *mlo_dev_ctx; 1350 1351 if (!vdev) 1352 return QDF_STATUS_E_NULL_VALUE; 1353 1354 mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); 1355 if (!mlo_dev_ctx) 1356 return QDF_STATUS_E_NULL_VALUE; 1357 1358 tsf_bit25_10 = (tsf & WLAN_T2LM_MAPPING_SWITCH_TSF_BITS) >> 10; 1359 t2lm_ctx = &mlo_dev_ctx->t2lm_ctx; 1360 1361 t2lm_dev_lock_acquire(t2lm_ctx); 1362 1363 if ((t2lm_ctx->established_t2lm.t2lm.expected_duration_present && 1364 rx_t2lm->established_t2lm.t2lm.expected_duration_present) && 1365 (rx_t2lm->established_t2lm.t2lm.expected_duration < 1366 t2lm_ctx->established_t2lm.t2lm.expected_duration)) { 1367 /* Established T2LM is already saved in the T2LM context. 1368 * T2LM IE in the beacon/probe response frame has the updated 1369 * expected duration. 1370 */ 1371 if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid, 1372 rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid, 1373 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { 1374 t2lm_ctx->established_t2lm.t2lm.expected_duration = 1375 rx_t2lm->established_t2lm.t2lm.expected_duration; 1376 } 1377 } else if (rx_t2lm->established_t2lm.t2lm.expected_duration_present && 1378 !rx_t2lm->established_t2lm.t2lm.mapping_switch_time_present) { 1379 if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid, 1380 rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid, 1381 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { 1382 t2lm_debug("T2LM mapping is already configured"); 1383 t2lm_dev_lock_release(t2lm_ctx); 1384 return QDF_STATUS_E_ALREADY; 1385 } 1386 1387 /* Mapping switch time is already expired when STA receives the 1388 * T2LM IE from beacon/probe response frame. 1389 */ 1390 qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, 1391 &rx_t2lm->established_t2lm.t2lm, 1392 sizeof(struct wlan_t2lm_info)); 1393 1394 /* Notify the registered caller about the link update*/ 1395 wlan_mlo_dev_t2lm_notify_link_update(vdev, 1396 &t2lm_ctx->established_t2lm.t2lm); 1397 wlan_clear_peer_level_tid_to_link_mapping(vdev); 1398 wlan_send_tid_to_link_mapping( 1399 vdev, &t2lm_ctx->established_t2lm.t2lm); 1400 } 1401 1402 if (rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time_present) { 1403 if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid, 1404 rx_t2lm->upcoming_t2lm.t2lm.ieee_link_map_tid, 1405 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { 1406 t2lm_debug("Ongoing mapping is already established"); 1407 t2lm_dev_lock_release(t2lm_ctx); 1408 return QDF_STATUS_E_ALREADY; 1409 } 1410 1411 qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, 1412 &rx_t2lm->upcoming_t2lm.t2lm, 1413 sizeof(struct wlan_t2lm_info)); 1414 1415 ms_time = t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time; 1416 /* Per test, -300ms is fine */ 1417 if (ms_time > tsf_bit25_10) { 1418 t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time = 1419 (ms_time - tsf_bit25_10 - (3 * WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY)); 1420 } else { 1421 t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time = 1422 0xFFFF - (tsf_bit25_10 - ms_time) - (3 * WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY); 1423 } 1424 } 1425 1426 t2lm_dev_lock_release(t2lm_ctx); 1427 1428 return QDF_STATUS_SUCCESS; 1429 } 1430 1431 QDF_STATUS wlan_process_bcn_prbrsp_t2lm_ie( 1432 struct wlan_objmgr_vdev *vdev, 1433 struct wlan_t2lm_context *rx_t2lm_ie, uint64_t tsf) 1434 { 1435 struct wlan_t2lm_context *t2lm_ctx; 1436 QDF_STATUS status; 1437 struct wlan_mlo_dev_context *mlo_dev_ctx; 1438 1439 /* Do not parse the T2LM IE if STA is not in connected state */ 1440 if (!wlan_cm_is_vdev_connected(vdev)) 1441 return QDF_STATUS_SUCCESS; 1442 1443 if (!vdev) 1444 return QDF_STATUS_E_NULL_VALUE; 1445 1446 mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); 1447 if (!mlo_dev_ctx) 1448 return QDF_STATUS_E_NULL_VALUE; 1449 1450 t2lm_ctx = &mlo_dev_ctx->t2lm_ctx; 1451 1452 status = wlan_update_mapping_switch_time_expected_dur( 1453 vdev, rx_t2lm_ie, tsf); 1454 if (QDF_IS_STATUS_ERROR(status)) 1455 return status; 1456 1457 t2lm_dev_lock_acquire(t2lm_ctx); 1458 if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present || 1459 t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) { 1460 wlan_handle_t2lm_timer(vdev); 1461 } 1462 t2lm_dev_lock_release(t2lm_ctx); 1463 1464 return QDF_STATUS_SUCCESS; 1465 } 1466 1467 int wlan_register_t2lm_link_update_notify_handler( 1468 wlan_mlo_t2lm_link_update_handler handler, 1469 struct wlan_mlo_dev_context *mldev) 1470 { 1471 struct wlan_t2lm_context *t2lm_ctx = &mldev->t2lm_ctx; 1472 int i; 1473 1474 for (i = 0; i < MAX_T2LM_HANDLERS; i++) { 1475 if (t2lm_ctx->is_valid_handler[i]) 1476 continue; 1477 1478 t2lm_ctx->link_update_handler[i] = handler; 1479 t2lm_ctx->is_valid_handler[i] = true; 1480 break; 1481 } 1482 1483 if (i == MAX_T2LM_HANDLERS) { 1484 t2lm_err("Failed to register the link disablement callback"); 1485 return -EINVAL; 1486 } 1487 1488 return i; 1489 } 1490 1491 void wlan_unregister_t2lm_link_update_notify_handler( 1492 struct wlan_mlo_dev_context *mldev, 1493 uint8_t index) 1494 { 1495 if (index >= MAX_T2LM_HANDLERS) 1496 return; 1497 1498 mldev->t2lm_ctx.link_update_handler[index] = NULL; 1499 mldev->t2lm_ctx.is_valid_handler[index] = false; 1500 } 1501 1502 QDF_STATUS wlan_mlo_dev_t2lm_notify_link_update( 1503 struct wlan_objmgr_vdev *vdev, 1504 struct wlan_t2lm_info *t2lm) 1505 { 1506 struct wlan_t2lm_context *t2lm_ctx; 1507 wlan_mlo_t2lm_link_update_handler handler; 1508 int i; 1509 1510 if (!vdev || !vdev->mlo_dev_ctx) 1511 return QDF_STATUS_E_FAILURE; 1512 1513 if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE && 1514 !wlan_cm_is_vdev_connected(vdev)) { 1515 t2lm_err("Not associated!"); 1516 return QDF_STATUS_E_AGAIN; 1517 } 1518 1519 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1520 t2lm_err("failed due to non-ML connection"); 1521 return QDF_STATUS_E_INVAL; 1522 } 1523 1524 t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; 1525 for (i = 0; i < MAX_T2LM_HANDLERS; i++) { 1526 if (!t2lm_ctx->is_valid_handler[i]) 1527 continue; 1528 1529 handler = t2lm_ctx->link_update_handler[i]; 1530 if (!handler) 1531 continue; 1532 1533 handler(vdev, t2lm); 1534 } 1535 return QDF_STATUS_SUCCESS; 1536 } 1537 1538 QDF_STATUS 1539 wlan_mlo_t2lm_timer_deinit(struct wlan_objmgr_vdev *vdev) 1540 { 1541 struct wlan_t2lm_timer *t2lm_timer = NULL; 1542 1543 if (!vdev || !vdev->mlo_dev_ctx) 1544 return QDF_STATUS_E_FAILURE; 1545 1546 t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer; 1547 if (!t2lm_timer) { 1548 t2lm_err("t2lm timer ctx is null"); 1549 return QDF_STATUS_E_NULL_VALUE; 1550 } 1551 1552 t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx); 1553 t2lm_timer->timer_started = false; 1554 t2lm_timer->timer_interval = 0; 1555 t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx); 1556 qdf_timer_free(&t2lm_timer->t2lm_timer); 1557 t2lm_dev_lock_destroy(&vdev->mlo_dev_ctx->t2lm_ctx); 1558 return QDF_STATUS_SUCCESS; 1559 } 1560 1561 #if defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE) && defined(WLAN_FEATURE_11BE) 1562 QDF_STATUS 1563 wlan_mlo_link_disable_request_handler(struct wlan_objmgr_psoc *psoc, 1564 void *evt_params) 1565 { 1566 struct wlan_objmgr_vdev *vdev; 1567 QDF_STATUS status = QDF_STATUS_SUCCESS; 1568 uint8_t vdev_id; 1569 bool is_connected = false; 1570 struct mlo_link_disable_request_evt_params *params; 1571 1572 if (!psoc) 1573 return QDF_STATUS_E_NULL_VALUE; 1574 1575 if (!evt_params) { 1576 t2lm_err("event params is null"); 1577 return QDF_STATUS_E_NULL_VALUE; 1578 } 1579 1580 params = (struct mlo_link_disable_request_evt_params *)evt_params; 1581 if (qdf_is_macaddr_zero(¶ms->mld_addr)) { 1582 t2lm_err("mld mac addr in event params is null"); 1583 return QDF_STATUS_E_NULL_VALUE; 1584 } 1585 1586 if (!params->link_id_bitmap) { 1587 t2lm_debug("Link id bitmap is 0, no action frame to be sent"); 1588 return QDF_STATUS_SUCCESS; 1589 } 1590 1591 is_connected = wlan_get_connected_vdev_by_mld_addr(psoc, 1592 params->mld_addr.bytes, 1593 &vdev_id); 1594 if (!is_connected) { 1595 t2lm_err("Not connected to peer MLD " QDF_MAC_ADDR_FMT, 1596 QDF_MAC_ADDR_REF(params->mld_addr.bytes)); 1597 return QDF_STATUS_E_FAILURE; 1598 } 1599 1600 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1601 WLAN_MLO_MGR_ID); 1602 if (!vdev) { 1603 t2lm_err("vdev is null"); 1604 return QDF_STATUS_E_NULL_VALUE; 1605 } 1606 1607 status = wlan_populate_link_disable_t2lm_frame(vdev, params); 1608 1609 if (QDF_IS_STATUS_ERROR(status)) 1610 t2lm_err("Failed to handle link disable"); 1611 1612 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1613 return status; 1614 } 1615 #endif 1616 1617