1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: wlan_hdd_mlo.c 20 * 21 * WLAN Host Device Driver file for 802.11be (Extremely High Throughput) 22 * support. 23 * 24 */ 25 #include "wlan_hdd_main.h" 26 #include "wlan_hdd_mlo.h" 27 #include "osif_vdev_sync.h" 28 #include "wlan_osif_features.h" 29 #include "wlan_dp_ucfg_api.h" 30 #include "wlan_psoc_mlme_ucfg_api.h" 31 #include "wlan_osif_request_manager.h" 32 #include "wlan_hdd_object_manager.h" 33 #include <wlan_osif_priv.h> 34 35 /*max time in ms, caller may wait for link state request get serviced */ 36 #define WLAN_WAIT_TIME_LINK_STATE 3000 37 38 #if defined(CFG80211_11BE_BASIC) 39 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV 40 #ifdef CFG80211_IFTYPE_MLO_LINK_SUPPORT 41 42 static 43 void wlan_hdd_register_ml_link(struct hdd_adapter *sta_adapter, 44 struct hdd_adapter *link_adapter) 45 { 46 int ret; 47 48 link_adapter->wdev.iftype = NL80211_IFTYPE_MLO_LINK; 49 mutex_lock(&sta_adapter->wdev.mtx); 50 ret = cfg80211_register_sta_mlo_link(&sta_adapter->wdev, 51 &link_adapter->wdev); 52 mutex_unlock(&sta_adapter->wdev.mtx); 53 54 if (ret) { 55 hdd_err("Failed to register ml link wdev %d", ret); 56 return; 57 } 58 } 59 60 static 61 void wlan_hdd_unregister_ml_link(struct hdd_adapter *link_adapter, 62 bool rtnl_held) 63 { 64 if (rtnl_held) 65 rtnl_unlock(); 66 67 cfg80211_unregister_wdev(&link_adapter->wdev); 68 69 if (rtnl_held) 70 rtnl_lock(); 71 } 72 #else 73 static 74 void wlan_hdd_register_ml_link(struct hdd_adapter *sta_adapter, 75 struct hdd_adapter *link_adapter) 76 { 77 } 78 79 static 80 void wlan_hdd_unregister_ml_link(struct hdd_adapter *link_adapter, 81 bool rtnl_held) 82 { 83 } 84 #endif 85 86 void hdd_register_wdev(struct hdd_adapter *sta_adapter, 87 struct hdd_adapter *link_adapter, 88 struct hdd_adapter_create_param *adapter_params) 89 { 90 int i; 91 92 hdd_enter_dev(sta_adapter->dev); 93 /* Set the relation between adapters*/ 94 wlan_hdd_register_ml_link(sta_adapter, link_adapter); 95 sta_adapter->mlo_adapter_info.is_ml_adapter = true; 96 sta_adapter->mlo_adapter_info.is_link_adapter = false; 97 link_adapter->mlo_adapter_info.is_link_adapter = true; 98 link_adapter->mlo_adapter_info.is_ml_adapter = false; 99 link_adapter->mlo_adapter_info.ml_adapter = sta_adapter; 100 link_adapter->mlo_adapter_info.associate_with_ml_adapter = 101 adapter_params->associate_with_ml_adapter; 102 qdf_set_bit(WDEV_ONLY_REGISTERED, &link_adapter->event_flags); 103 104 for (i = 0; i < WLAN_MAX_MLD; i++) { 105 if (sta_adapter->mlo_adapter_info.link_adapter[i]) 106 continue; 107 sta_adapter->mlo_adapter_info.link_adapter[i] = link_adapter; 108 break; 109 } 110 111 qdf_mem_copy(link_adapter->mld_addr.bytes, sta_adapter->mld_addr.bytes, 112 QDF_MAC_ADDR_SIZE); 113 hdd_exit(); 114 } 115 116 static 117 void hdd_mlo_close_adapter(struct hdd_adapter *link_adapter, bool rtnl_held) 118 { 119 struct osif_vdev_sync *vdev_sync; 120 121 vdev_sync = osif_vdev_sync_unregister(link_adapter->dev); 122 if (vdev_sync) 123 osif_vdev_sync_wait_for_ops(vdev_sync); 124 125 hdd_check_for_net_dev_ref_leak(link_adapter); 126 policy_mgr_clear_concurrency_mode(link_adapter->hdd_ctx->psoc, 127 link_adapter->device_mode); 128 link_adapter->wdev.netdev = NULL; 129 130 wlan_hdd_unregister_ml_link(link_adapter, rtnl_held); 131 free_netdev(link_adapter->dev); 132 133 if (vdev_sync) 134 osif_vdev_sync_destroy(vdev_sync); 135 } 136 137 QDF_STATUS hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter *adapter, 138 bool rtnl_held) 139 { 140 int i; 141 struct hdd_mlo_adapter_info *mlo_adapter_info; 142 struct hdd_adapter *link_adapter; 143 144 mlo_adapter_info = &adapter->mlo_adapter_info; 145 146 if (mlo_adapter_info->is_link_adapter) { 147 ucfg_dp_destroy_intf(adapter->hdd_ctx->psoc, 148 &adapter->mac_addr); 149 hdd_remove_front_adapter(adapter->hdd_ctx, &adapter); 150 return QDF_STATUS_E_AGAIN; 151 } 152 153 for (i = 0; i < WLAN_MAX_MLD; i++) { 154 link_adapter = mlo_adapter_info->link_adapter[i]; 155 if (!link_adapter) 156 continue; 157 hdd_cleanup_conn_info(link_adapter->deflink); 158 ucfg_dp_destroy_intf(link_adapter->hdd_ctx->psoc, 159 &link_adapter->mac_addr); 160 hdd_remove_adapter(link_adapter->hdd_ctx, link_adapter); 161 hdd_mlo_close_adapter(link_adapter, rtnl_held); 162 } 163 164 return QDF_STATUS_SUCCESS; 165 } 166 167 void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx) 168 { 169 int i = 0; 170 QDF_STATUS status; 171 struct hdd_adapter *ml_adapter; 172 struct wlan_hdd_link_info *link_info; 173 struct hdd_adapter_create_param params = {0}; 174 struct qdf_mac_addr link_addr[WLAN_MAX_ML_BSS_LINKS] = {0}; 175 176 ml_adapter = hdd_get_ml_adapter(hdd_ctx); 177 if (!ml_adapter) 178 return; 179 180 status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, 181 &ml_adapter->mld_addr, 182 &link_addr[0], 183 WLAN_MAX_ML_BSS_LINKS); 184 if (QDF_IS_STATUS_ERROR(status)) 185 return; 186 187 /* if target supports MLO create a new dev */ 188 params.only_wdev_register = true; 189 params.associate_with_ml_adapter = true; 190 status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, "null", 191 link_addr[0].bytes, ¶ms); 192 if (QDF_IS_STATUS_ERROR(status)) 193 hdd_err("Failed to register link adapter:%d", status); 194 195 qdf_mem_zero(¶ms, sizeof(params)); 196 params.only_wdev_register = true; 197 params.associate_with_ml_adapter = false; 198 /* if target supports MLO create a new dev */ 199 status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, "null", 200 link_addr[1].bytes, ¶ms); 201 if (QDF_IS_STATUS_ERROR(status)) { 202 hdd_err("Failed to register link adapter:%d", status); 203 } else { 204 hdd_adapter_for_each_link_info(ml_adapter, link_info) { 205 qdf_copy_macaddr(&link_info->link_addr, 206 &link_addr[i++]); 207 } 208 } 209 } 210 211 void 212 hdd_adapter_set_sl_ml_adapter(struct hdd_adapter *adapter) 213 { 214 adapter->mlo_adapter_info.is_single_link_ml = true; 215 } 216 217 void 218 hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter *adapter) 219 { 220 adapter->mlo_adapter_info.is_single_link_ml = false; 221 } 222 223 struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx) 224 { 225 struct hdd_adapter *adapter, *next_adapter = NULL; 226 wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_VDEV; 227 228 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 229 dbgid) { 230 if (hdd_adapter_is_ml_adapter(adapter)) { 231 hdd_adapter_dev_put_debug(adapter, dbgid); 232 if (next_adapter) 233 hdd_adapter_dev_put_debug(next_adapter, 234 dbgid); 235 return adapter; 236 } 237 hdd_adapter_dev_put_debug(adapter, dbgid); 238 } 239 240 return NULL; 241 } 242 #endif 243 244 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV 245 void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter) 246 { 247 adapter->mlo_adapter_info.is_ml_adapter = true; 248 qdf_copy_macaddr(&adapter->mld_addr, &adapter->mac_addr); 249 } 250 #else 251 void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter) 252 { 253 adapter->mlo_adapter_info.is_ml_adapter = true; 254 } 255 256 static struct mlo_osif_ext_ops mlo_osif_ops = { 257 .mlo_mgr_osif_update_bss_info = hdd_cm_save_connected_links_info, 258 .mlo_mgr_osif_update_mac_addr = hdd_link_switch_vdev_mac_addr_update, 259 .mlo_mgr_osif_link_switch_notification = 260 hdd_adapter_link_switch_notification, 261 }; 262 263 QDF_STATUS hdd_mlo_mgr_register_osif_ops(void) 264 { 265 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); 266 267 return wlan_mlo_mgr_register_osif_ext_ops(mlo_mgr_ctx, &mlo_osif_ops); 268 } 269 270 QDF_STATUS hdd_mlo_mgr_unregister_osif_ops(void) 271 { 272 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); 273 274 return wlan_mlo_mgr_unregister_osif_ext_ops(mlo_mgr_ctx); 275 } 276 277 QDF_STATUS hdd_adapter_link_switch_notification(struct wlan_objmgr_vdev *vdev, 278 uint8_t non_trans_vdev_id) 279 { 280 bool found = false; 281 struct hdd_adapter *adapter; 282 struct vdev_osif_priv *osif_priv; 283 struct wlan_hdd_link_info *link_info, *iter_link_info; 284 285 osif_priv = wlan_vdev_get_ospriv(vdev); 286 if (!osif_priv) { 287 hdd_err("Invalid osif priv"); 288 return QDF_STATUS_E_INVAL; 289 } 290 291 link_info = osif_priv->legacy_osif_priv; 292 adapter = link_info->adapter; 293 294 if (link_info->vdev_id != adapter->deflink->vdev_id) { 295 hdd_err("Deflink VDEV %d not equals current VDEV %d", 296 adapter->deflink->vdev_id, link_info->vdev_id); 297 return QDF_STATUS_E_INVAL; 298 } 299 300 hdd_adapter_for_each_link_info(adapter, iter_link_info) { 301 if (non_trans_vdev_id == iter_link_info->vdev_id) { 302 adapter->deflink = iter_link_info; 303 found = true; 304 break; 305 } 306 } 307 308 if (!found) 309 return QDF_STATUS_E_FAILURE; 310 311 return QDF_STATUS_SUCCESS; 312 } 313 #endif 314 315 void hdd_mlo_t2lm_register_callback(struct wlan_objmgr_vdev *vdev) 316 { 317 if (!vdev || !vdev->mlo_dev_ctx) 318 return; 319 320 wlan_register_t2lm_link_update_notify_handler( 321 hdd_mlo_dev_t2lm_notify_link_update, 322 vdev->mlo_dev_ctx); 323 } 324 325 void hdd_mlo_t2lm_unregister_callback(struct wlan_objmgr_vdev *vdev) 326 { 327 if (!vdev || !vdev->mlo_dev_ctx) 328 return; 329 330 wlan_unregister_t2lm_link_update_notify_handler(vdev->mlo_dev_ctx, 0); 331 } 332 333 QDF_STATUS hdd_derive_link_address_from_mld(struct wlan_objmgr_psoc *psoc, 334 struct qdf_mac_addr *mld_addr, 335 struct qdf_mac_addr *link_addr_list, 336 uint8_t max_idx) 337 { 338 uint8_t last_byte, temp_byte, idx, start_idx = 0; 339 struct qdf_mac_addr new_addr; 340 struct qdf_mac_addr *link_addr; 341 342 if (!psoc || !mld_addr || !link_addr_list || !max_idx || 343 max_idx > WLAN_MAX_ML_BSS_LINKS || qdf_is_macaddr_zero(mld_addr)) { 344 hdd_err("Invalid values"); 345 return QDF_STATUS_E_INVAL; 346 } 347 348 qdf_copy_macaddr(&new_addr, mld_addr); 349 /* Set locally administered bit */ 350 new_addr.bytes[0] |= 0x02; 351 352 link_addr = link_addr_list; 353 last_byte = mld_addr->bytes[5]; 354 hdd_debug("MLD addr: " QDF_MAC_ADDR_FMT, 355 QDF_MAC_ADDR_REF(mld_addr->bytes)); 356 357 if (wlan_mlme_get_sta_same_link_mld_addr(psoc)) { 358 qdf_copy_macaddr(link_addr, mld_addr); 359 link_addr++; 360 start_idx++; 361 } 362 363 for (idx = start_idx; idx < max_idx; idx++) { 364 temp_byte = ((last_byte >> 4 & INTF_MACADDR_MASK) + idx) & 365 INTF_MACADDR_MASK; 366 new_addr.bytes[5] = last_byte + temp_byte; 367 new_addr.bytes[5] ^= (1 << 7); 368 369 qdf_copy_macaddr(link_addr, &new_addr); 370 link_addr++; 371 hdd_debug("Derived link addr: " QDF_MAC_ADDR_FMT ", idx: %d", 372 QDF_MAC_ADDR_REF(new_addr.bytes), idx); 373 } 374 375 return QDF_STATUS_SUCCESS; 376 } 377 378 #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE 379 #ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV 380 static void hdd_adapter_restore_link_vdev_map(struct hdd_adapter *adapter) 381 { 382 int i; 383 unsigned long link_flags; 384 uint8_t vdev_id, cur_link_idx, temp_link_idx; 385 struct vdev_osif_priv *osif_priv; 386 struct wlan_objmgr_vdev *vdev; 387 struct wlan_hdd_link_info *temp_link_info, *link_info; 388 389 hdd_adapter_for_each_link_info(adapter, link_info) { 390 cur_link_idx = hdd_adapter_get_index_of_link_info(link_info); 391 /* If the current index matches the current pos in mapping 392 * then the link info is in same position 393 */ 394 if (adapter->curr_link_info_map[cur_link_idx] == cur_link_idx) 395 continue; 396 397 /* Find the index where current link info is moved to perform 398 * VDEV info swap. 399 */ 400 for (i = cur_link_idx + 1; i < WLAN_MAX_ML_BSS_LINKS; i++) { 401 if (adapter->curr_link_info_map[i] == cur_link_idx) { 402 temp_link_idx = i; 403 break; 404 } 405 } 406 407 if (i == WLAN_MAX_ML_BSS_LINKS) 408 continue; 409 410 temp_link_info = &adapter->link_info[temp_link_idx]; 411 412 /* Move VDEV info from current link info */ 413 qdf_spin_lock_bh(&temp_link_info->vdev_lock); 414 vdev = temp_link_info->vdev; 415 vdev_id = temp_link_info->vdev_id; 416 temp_link_info->vdev = link_info->vdev; 417 temp_link_info->vdev_id = link_info->vdev_id; 418 qdf_spin_unlock_bh(&temp_link_info->vdev_lock); 419 420 /* Update VDEV-OSIF priv pointer to new link info. */ 421 if (temp_link_info->vdev) { 422 osif_priv = wlan_vdev_get_ospriv(temp_link_info->vdev); 423 if (osif_priv) 424 osif_priv->legacy_osif_priv = temp_link_info; 425 } 426 427 /* Fill current link info's actual VDEV info */ 428 qdf_spin_lock_bh(&link_info->vdev_lock); 429 link_info->vdev = vdev; 430 link_info->vdev_id = vdev_id; 431 qdf_spin_unlock_bh(&link_info->vdev_lock); 432 433 /* Update VDEV-OSIF priv pointer to new link info. */ 434 if (link_info->vdev) { 435 osif_priv = wlan_vdev_get_ospriv(link_info->vdev); 436 if (osif_priv) 437 osif_priv->legacy_osif_priv = link_info; 438 } 439 440 /* Swap link flags */ 441 link_flags = temp_link_info->link_flags; 442 temp_link_info->link_flags = link_info->link_flags; 443 link_info->link_flags = link_flags; 444 445 /* Update the mapping, current link info's mapping will be 446 * set to be proper. 447 */ 448 adapter->curr_link_info_map[temp_link_idx] = 449 adapter->curr_link_info_map[cur_link_idx]; 450 adapter->curr_link_info_map[cur_link_idx] = cur_link_idx; 451 } 452 hdd_adapter_disable_all_links(adapter); 453 } 454 455 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter, 456 struct qdf_mac_addr mac_addr) 457 { 458 int idx, i, ret = 0; 459 bool update_self_peer; 460 QDF_STATUS status; 461 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 462 struct wlan_hdd_link_info *link_info; 463 uint8_t *addr_list[WLAN_MAX_ML_BSS_LINKS + 1] = {0}; 464 struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0}; 465 466 /* This API is only called with is ml adapter set for STA mode adapter. 467 * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for 468 * MAC address update. 469 */ 470 471 if (!hdd_adapter_is_ml_adapter(adapter)) { 472 struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; 473 474 ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr, 475 mld_addr, true); 476 return ret; 477 } 478 479 status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, 480 &mac_addr, &link_addrs[0], 481 WLAN_MAX_ML_BSS_LINKS); 482 483 if (QDF_IS_STATUS_ERROR(status)) 484 return qdf_status_to_os_return(status); 485 486 hdd_adapter_restore_link_vdev_map(adapter); 487 488 i = 0; 489 hdd_adapter_for_each_active_link_info(adapter, link_info) { 490 idx = hdd_adapter_get_index_of_link_info(link_info); 491 addr_list[i++] = &link_addrs[idx].bytes[0]; 492 } 493 494 status = sme_check_for_duplicate_session(hdd_ctx->mac_handle, 495 &addr_list[0]); 496 if (QDF_IS_STATUS_ERROR(status)) 497 return qdf_status_to_os_return(status); 498 499 i = 0; 500 hdd_adapter_for_each_link_info(adapter, link_info) 501 qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]); 502 503 hdd_adapter_for_each_active_link_info(adapter, link_info) { 504 idx = hdd_adapter_get_index_of_link_info(link_info); 505 update_self_peer = 506 (link_info == adapter->deflink) ? true : false; 507 ret = hdd_dynamic_mac_address_set(link_info, link_addrs[idx], 508 mac_addr, update_self_peer); 509 if (ret) 510 return ret; 511 512 qdf_copy_macaddr(&link_info->link_addr, &link_addrs[idx]); 513 } 514 515 hdd_adapter_update_mlo_mgr_mac_addr(adapter); 516 return ret; 517 } 518 #else 519 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter, 520 struct qdf_mac_addr mac_addr) 521 { 522 int i, ret = 0; 523 QDF_STATUS status; 524 bool eht_capab, update_self_peer; 525 struct hdd_adapter *link_adapter; 526 struct hdd_mlo_adapter_info *mlo_adapter_info; 527 struct hdd_context *hdd_ctx = adapter->hdd_ctx; 528 uint8_t *addr_list[WLAN_MAX_MLD + 1] = {0}; 529 struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0}; 530 531 /* This API is only called with is ml adapter set for STA mode adapter. 532 * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for 533 * MAC address update. 534 */ 535 ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); 536 if (!(eht_capab && hdd_adapter_is_ml_adapter(adapter))) { 537 struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; 538 539 ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr, 540 mld_addr, true); 541 return ret; 542 } 543 544 status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, 545 &mac_addr, &link_addrs[0], 546 WLAN_MAX_ML_BSS_LINKS); 547 548 if (QDF_IS_STATUS_ERROR(status)) 549 return qdf_status_to_os_return(status); 550 551 for (i = 0; i < WLAN_MAX_MLD; i++) 552 addr_list[i] = &link_addrs[i].bytes[0]; 553 554 status = sme_check_for_duplicate_session(hdd_ctx->mac_handle, 555 &addr_list[0]); 556 if (QDF_IS_STATUS_ERROR(status)) 557 return qdf_status_to_os_return(status); 558 559 mlo_adapter_info = &adapter->mlo_adapter_info; 560 for (i = 0; i < WLAN_MAX_MLD; i++) { 561 link_adapter = mlo_adapter_info->link_adapter[i]; 562 if (!link_adapter) 563 continue; 564 565 if (hdd_adapter_is_associated_with_ml_adapter(link_adapter)) 566 update_self_peer = true; 567 else 568 update_self_peer = false; 569 570 ret = hdd_dynamic_mac_address_set(link_adapter->deflink, 571 link_addrs[i], mac_addr, 572 update_self_peer); 573 if (ret) 574 return ret; 575 576 /* Update DP intf and new link address in link adapter 577 */ 578 ucfg_dp_update_intf_mac(hdd_ctx->psoc, &link_adapter->mac_addr, 579 &link_addrs[i], 580 link_adapter->deflink->vdev); 581 qdf_copy_macaddr(&link_adapter->mac_addr, &link_addrs[i]); 582 qdf_copy_macaddr(&adapter->link_info[i].link_addr, 583 &link_addrs[i]); 584 } 585 586 qdf_copy_macaddr(&adapter->link_info[i].link_addr, &link_addrs[i]); 587 hdd_adapter_update_mlo_mgr_mac_addr(adapter); 588 589 return ret; 590 } 591 #endif 592 #endif /* WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE */ 593 594 const struct nla_policy 595 ml_link_state_config_policy [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1] = { 596 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID] = {.type = NLA_U8}, 597 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE] = {.type = NLA_U32}, 598 }; 599 600 const struct nla_policy 601 ml_link_state_request_policy[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1] = { 602 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE] = {.type = NLA_U32}, 603 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE] = {.type = NLA_U32}, 604 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG] = {.type = NLA_NESTED}, 605 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS] = { 606 .type = NLA_U8}, 607 }; 608 609 static int 610 __wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy, 611 struct wireless_dev *wdev, 612 const void *data, int data_len) 613 { 614 int ret = 0; 615 struct net_device *dev = wdev->netdev; 616 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 617 struct wlan_objmgr_vdev *vdev; 618 struct hdd_context *hdd_ctx = NULL; 619 620 hdd_enter_dev(wdev->netdev); 621 622 if (hdd_validate_adapter(adapter)) 623 return -EINVAL; 624 625 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 626 if (!hdd_ctx) 627 return -EINVAL; 628 629 if (adapter->device_mode != QDF_STA_MODE) 630 return -EINVAL; 631 632 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); 633 634 if (!vdev) 635 return -EINVAL; 636 637 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 638 goto release_ref; 639 640 ret = wlan_handle_mlo_link_state_operation(adapter, wiphy, vdev, 641 hdd_ctx, data, data_len); 642 643 release_ref: 644 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); 645 646 return ret; 647 } 648 649 int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy, 650 struct wireless_dev *wdev, 651 const void *data, int data_len) 652 { 653 int errno; 654 struct osif_vdev_sync *vdev_sync; 655 656 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 657 if (errno) 658 return errno; 659 660 errno = __wlan_hdd_cfg80211_process_ml_link_state(wiphy, wdev, data, 661 data_len); 662 663 osif_vdev_sync_op_stop(vdev_sync); 664 665 return errno; 666 } 667 668 static inline void ml_link_state_resp_cb(struct ml_link_state_info_event *ev, 669 void *cookie) 670 { 671 struct ml_link_state_info_event *priv; 672 struct osif_request *request; 673 674 request = osif_request_get(cookie); 675 676 if (!request) { 677 hdd_err("Obsolete request"); 678 return; 679 } 680 681 priv = osif_request_priv(request); 682 683 qdf_mem_copy(priv, ev, sizeof(*priv)); 684 osif_request_complete(request); 685 osif_request_put(request); 686 } 687 688 static uint32_t 689 hdd_get_ml_link_state_response_len(const struct ml_link_state_info_event *event) 690 { 691 uint32_t len = 0; 692 uint32_t info_len = 0; 693 694 len = NLMSG_HDRLEN; 695 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE */ 696 len += NLA_HDRLEN + sizeof(u32); 697 698 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE */ 699 len += NLA_HDRLEN + sizeof(u32); 700 701 /* nest */ 702 info_len = NLA_HDRLEN; 703 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID */ 704 info_len += NLA_HDRLEN + sizeof(u8); 705 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE */ 706 info_len += NLA_HDRLEN + sizeof(u32); 707 708 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG */ 709 len += NLA_HDRLEN + (info_len * event->num_mlo_vdev_link_info); 710 711 return len; 712 } 713 714 static int 715 hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb, 716 struct wlan_objmgr_psoc *psoc, 717 struct ml_link_state_info_event *params, 718 uint32_t num_link_info) 719 { 720 struct nlattr *nla_config_attr, *nla_config_params; 721 uint32_t i = 0, attr; 722 int errno; 723 uint32_t value; 724 725 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE; 726 value = ucfg_mlme_get_ml_link_control_mode(psoc, params->vdev_id); 727 errno = nla_put_u32(skb, attr, value); 728 if (errno) 729 return errno; 730 731 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE; 732 733 /* Default link state operation mode is only supported */ 734 value = QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT; 735 errno = nla_put_u32(skb, attr, value); 736 if (errno) 737 return errno; 738 739 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG; 740 nla_config_attr = nla_nest_start(skb, attr); 741 742 if (!nla_config_attr) 743 return -EINVAL; 744 745 for (i = 0; i < num_link_info; i++) { 746 nla_config_params = nla_nest_start(skb, attr); 747 if (!nla_config_params) 748 return -EINVAL; 749 750 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID; 751 value = params->link_info[i].link_id; 752 errno = nla_put_u8(skb, attr, value); 753 if (errno) 754 return errno; 755 756 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE; 757 value = params->link_info[i].link_status; 758 errno = nla_put_u32(skb, attr, value); 759 760 if (errno) 761 return errno; 762 763 nla_nest_end(skb, nla_config_params); 764 } 765 766 nla_nest_end(skb, nla_config_attr); 767 768 return 0; 769 } 770 771 static char *link_state_status_id_to_str(uint32_t status) 772 { 773 switch (status) { 774 case WLAN_LINK_INFO_EVENT_SUCCESS: 775 return "LINK_INFO_EVENT_SUCCESS"; 776 case WLAN_LINK_INFO_EVENT_REJECT_FAILURE: 777 return "LINK_INFO_EVENT_REJECT_FAILURE"; 778 case WLAN_LINK_INFO_EVENT_REJECT_VDEV_NOT_UP: 779 return "LINK_INFO_EVENT_REJECT_VDEV_NOT_UP"; 780 case WLAN_LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS: 781 return "LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS"; 782 case WLAN_LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION: 783 return "LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION"; 784 } 785 return "Undefined link state status ID"; 786 } 787 788 static bool 789 wlan_hdd_link_state_request_needed(struct hdd_adapter *adapter) 790 { 791 qdf_time_t link_state_cached_duration = 0; 792 793 link_state_cached_duration = 794 qdf_system_ticks_to_msecs(qdf_system_ticks()) - 795 adapter->link_state_cached_timestamp; 796 if (link_state_cached_duration <= 797 adapter->hdd_ctx->config->link_state_cache_expiry_time) 798 return false; 799 800 return true; 801 } 802 803 #ifdef WLAN_FEATURE_11BE_MLO 804 805 void hdd_update_link_state_cached_timestamp(struct hdd_adapter *adapter) 806 { 807 adapter->link_state_cached_timestamp = 808 qdf_system_ticks_to_msecs(qdf_system_ticks()); 809 } 810 #endif /* WLAN_FEATURE_11BE_MLO */ 811 812 static QDF_STATUS 813 wlan_hdd_cached_link_state_request(struct hdd_adapter *adapter, 814 struct wiphy *wiphy, 815 struct wlan_objmgr_psoc *psoc, 816 struct wlan_objmgr_vdev *vdev) 817 { 818 QDF_STATUS status = QDF_STATUS_E_INVAL; 819 struct ml_link_state_info_event link_state_event = {0}; 820 struct wlan_hdd_link_info *link_info; 821 struct hdd_station_ctx *sta_ctx; 822 int skb_len; 823 struct sk_buff *reply_skb = NULL; 824 int errno; 825 struct qdf_mac_addr *mld_addr; 826 uint8_t link_iter = 0; 827 struct mlo_link_info *ml_link_info; 828 struct wlan_mlo_dev_context *mlo_ctx; 829 830 mlo_ctx = vdev->mlo_dev_ctx; 831 if (!mlo_ctx) { 832 hdd_err("null mlo_dev_ctx"); 833 return -EINVAL; 834 } 835 836 hdd_adapter_for_each_link_info(adapter, link_info) { 837 838 if (link_iter >= WLAN_MAX_ML_BSS_LINKS) { 839 hdd_err("Invalid number of link info"); 840 return -EINVAL; 841 } 842 843 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); 844 link_state_event.link_info[link_iter].link_id = 845 sta_ctx->conn_info.ieee_link_id; 846 link_state_event.link_info[link_iter].vdev_id = 847 link_info->vdev_id; 848 link_state_event.link_info[link_iter].chan_freq = 849 sta_ctx->ch_info.freq; 850 851 if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID) 852 continue; 853 854 ml_link_info = mlo_mgr_get_ap_link_by_link_id( 855 mlo_ctx, 856 sta_ctx->conn_info.ieee_link_id); 857 if (!ml_link_info) { 858 hdd_debug("link: %d info does not exist", 859 sta_ctx->conn_info.ieee_link_id); 860 return -EINVAL; 861 } 862 863 link_state_event.link_info[link_iter].link_status = 864 ml_link_info->is_link_active; 865 866 link_iter++; 867 868 hdd_debug_rl("vdev id %d sta_ctx->conn_info.ieee_link_id %d is_mlo_vdev_active %d ", 869 link_info->vdev_id, sta_ctx->conn_info.ieee_link_id, 870 ml_link_info->is_link_active); 871 } 872 873 link_state_event.num_mlo_vdev_link_info = link_iter; 874 link_state_event.vdev_id = wlan_vdev_get_id(vdev); 875 link_state_event.status = 0; 876 mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); 877 link_state_event.mldaddr = *mld_addr; 878 879 hdd_debug_rl("cached link_state_resp: vdev id %d status %d num %d MAC addr " QDF_MAC_ADDR_FMT, 880 link_state_event.vdev_id, link_state_event.status, 881 link_state_event.num_mlo_vdev_link_info, 882 QDF_MAC_ADDR_REF(link_state_event.mldaddr.bytes)); 883 884 skb_len = hdd_get_ml_link_state_response_len(&link_state_event); 885 886 reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len); 887 if (!reply_skb) { 888 hdd_err("Get stats - alloc reply_skb failed"); 889 status = QDF_STATUS_E_NOMEM; 890 return status; 891 } 892 893 status = hdd_ml_generate_link_state_resp_nlmsg( 894 reply_skb, psoc, &link_state_event, 895 link_state_event.num_mlo_vdev_link_info); 896 if (QDF_IS_STATUS_ERROR(status)) { 897 hdd_err("Failed to pack nl response"); 898 goto free_skb; 899 } 900 901 errno = wlan_cfg80211_vendor_cmd_reply(reply_skb); 902 903 return qdf_status_from_os_return(errno); 904 905 free_skb: 906 wlan_cfg80211_vendor_free_skb(reply_skb); 907 return QDF_STATUS_SUCCESS; 908 } 909 910 static QDF_STATUS wlan_hdd_link_state_request(struct hdd_adapter *adapter, 911 struct wiphy *wiphy, 912 struct wlan_objmgr_psoc *psoc, 913 struct wlan_objmgr_vdev *vdev) 914 { 915 int errno; 916 int skb_len; 917 struct sk_buff *reply_skb = NULL; 918 QDF_STATUS status = QDF_STATUS_E_INVAL; 919 void *cookie; 920 struct ml_link_state_info_event *link_state_event = NULL; 921 struct osif_request *request; 922 struct ml_link_state_cmd_info info = {0}; 923 int num_info = 0; 924 static const struct osif_request_params params = { 925 .priv_size = sizeof(*link_state_event), 926 .timeout_ms = WLAN_WAIT_TIME_LINK_STATE, 927 .dealloc = NULL, 928 }; 929 930 if (!wiphy || !vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 931 return status; 932 933 if (adapter->device_mode != QDF_STA_MODE) 934 return QDF_STATUS_SUCCESS; 935 936 if (!wlan_hdd_link_state_request_needed(adapter)) { 937 hdd_debug_rl("sending cached link state request"); 938 status = wlan_hdd_cached_link_state_request(adapter, wiphy, 939 psoc, vdev); 940 return status; 941 } 942 943 request = osif_request_alloc(¶ms); 944 if (!request) 945 return QDF_STATUS_E_NOMEM; 946 947 cookie = osif_request_cookie(request); 948 link_state_event = osif_request_priv(request); 949 950 info.request_cookie = cookie; 951 info.ml_link_state_resp_cb = ml_link_state_resp_cb; 952 953 status = mlo_get_link_state_register_resp_cb(vdev, 954 &info); 955 if (QDF_IS_STATUS_ERROR(status)) { 956 hdd_err("Failed to register resp callback: %d", status); 957 status = qdf_status_to_os_return(status); 958 goto free_event; 959 } 960 961 status = ml_post_get_link_state_msg(vdev); 962 if (QDF_IS_STATUS_ERROR(status)) { 963 hdd_err("Failed to post scheduler msg"); 964 goto free_event; 965 } 966 967 status = osif_request_wait_for_response(request); 968 if (status) { 969 hdd_err("wait failed or timed out ret: %d", status); 970 goto free_event; 971 } 972 973 hdd_debug("ml_link_state_resp: vdev id %d status %d num %d MAC addr " QDF_MAC_ADDR_FMT, 974 link_state_event->vdev_id, link_state_event->status, 975 link_state_event->num_mlo_vdev_link_info, 976 QDF_MAC_ADDR_REF(link_state_event->mldaddr.bytes)); 977 978 if (QDF_IS_STATUS_ERROR(link_state_event->status)) { 979 hdd_debug("ml_link_state_status failed %s", 980 link_state_status_id_to_str(link_state_event->status)); 981 goto free_event; 982 } 983 984 for (num_info = 0; num_info < link_state_event->num_mlo_vdev_link_info; 985 num_info++) { 986 hdd_debug("ml_link_state_resp: chan_freq %d vdev_id %d link_id %d link_status %d", 987 link_state_event->link_info[num_info].chan_freq, 988 link_state_event->link_info[num_info].vdev_id, 989 link_state_event->link_info[num_info].link_id, 990 link_state_event->link_info[num_info].link_status); 991 } 992 993 hdd_update_link_state_cached_timestamp(adapter); 994 995 skb_len = hdd_get_ml_link_state_response_len(link_state_event); 996 997 reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb( 998 wiphy, 999 skb_len); 1000 if (!reply_skb) { 1001 hdd_err("Get stats - alloc reply_skb failed"); 1002 status = QDF_STATUS_E_NOMEM; 1003 goto free_event; 1004 } 1005 1006 status = hdd_ml_generate_link_state_resp_nlmsg( 1007 reply_skb, psoc, link_state_event, 1008 link_state_event->num_mlo_vdev_link_info); 1009 if (QDF_IS_STATUS_ERROR(status)) { 1010 hdd_err("Failed to pack nl response"); 1011 goto free_skb; 1012 } 1013 1014 osif_request_put(request); 1015 1016 errno = wlan_cfg80211_vendor_cmd_reply(reply_skb); 1017 1018 return qdf_status_from_os_return(errno); 1019 1020 free_skb: 1021 wlan_cfg80211_vendor_free_skb(reply_skb); 1022 free_event: 1023 osif_request_put(request); 1024 1025 return status; 1026 } 1027 1028 #define MLD_MAX_SUPPORTED_LINKS 2 1029 1030 int wlan_handle_mlo_link_state_operation(struct hdd_adapter *adapter, 1031 struct wiphy *wiphy, 1032 struct wlan_objmgr_vdev *vdev, 1033 struct hdd_context *hdd_ctx, 1034 const void *data, int data_len) 1035 { 1036 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1]; 1037 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1]; 1038 enum qca_wlan_vendor_link_state_op_types ml_link_op; 1039 struct nlattr *link_oper_attr, *mode_attr, *curr_attr, *num_link_attr; 1040 int rem_len = 0, rc; 1041 uint32_t attr_id, ml_config_state; 1042 uint8_t ml_active_num_links, ml_link_control_mode; 1043 uint8_t ml_config_link_id, num_links = 0; 1044 uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; 1045 uint8_t link_id_list[MLD_MAX_SUPPORTED_LINKS] = {0}; 1046 uint32_t config_state_list[MLD_MAX_SUPPORTED_LINKS] = {0}; 1047 QDF_STATUS status; 1048 1049 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX, 1050 data, data_len, 1051 ml_link_state_request_policy)) { 1052 hdd_debug("vdev %d: invalid mlo link state attr", vdev_id); 1053 return -EINVAL; 1054 } 1055 1056 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE; 1057 link_oper_attr = tb[attr_id]; 1058 if (!link_oper_attr) { 1059 hdd_debug("vdev %d: link state op not specified", vdev_id); 1060 return -EINVAL; 1061 } 1062 ml_link_op = nla_get_u8(link_oper_attr); 1063 switch (ml_link_op) { 1064 case QCA_WLAN_VENDOR_LINK_STATE_OP_GET: 1065 status = wlan_hdd_link_state_request(adapter, wiphy, 1066 hdd_ctx->psoc, vdev); 1067 return qdf_status_to_os_return(status); 1068 case QCA_WLAN_VENDOR_LINK_STATE_OP_SET: 1069 if (policy_mgr_is_set_link_in_progress(hdd_ctx->psoc)) { 1070 hdd_debug("vdev %d: change link already in progress", 1071 vdev_id); 1072 return -EBUSY; 1073 } 1074 1075 break; 1076 default: 1077 hdd_debug("vdev %d: Invalid op type:%d", vdev_id, ml_link_op); 1078 return -EINVAL; 1079 } 1080 1081 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE; 1082 mode_attr = tb[attr_id]; 1083 if (!mode_attr) { 1084 hdd_debug("vdev %d: ml links control mode attr not present", 1085 vdev_id); 1086 return -EINVAL; 1087 } 1088 ml_link_control_mode = nla_get_u8(mode_attr); 1089 1090 switch (ml_link_control_mode) { 1091 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT: 1092 /* clear mlo link(s) settings in fw as per driver */ 1093 status = policy_mgr_clear_ml_links_settings_in_fw(hdd_ctx->psoc, 1094 vdev_id); 1095 if (QDF_IS_STATUS_ERROR(status)) 1096 return -EINVAL; 1097 break; 1098 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER: 1099 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG; 1100 if (!tb[attr_id]) { 1101 hdd_debug("vdev %d: state config attr not present", 1102 vdev_id); 1103 return -EINVAL; 1104 } 1105 1106 nla_for_each_nested(curr_attr, tb[attr_id], rem_len) { 1107 rc = wlan_cfg80211_nla_parse_nested( 1108 tb2, QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX, 1109 curr_attr, 1110 ml_link_state_config_policy); 1111 if (rc) { 1112 hdd_debug("vdev %d: nested attr not present", 1113 vdev_id); 1114 return -EINVAL; 1115 } 1116 1117 attr_id = 1118 QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID; 1119 if (!tb2[attr_id]) { 1120 hdd_debug("vdev %d: link id attr not present", 1121 vdev_id); 1122 return -EINVAL; 1123 } 1124 1125 ml_config_link_id = nla_get_u8(tb2[attr_id]); 1126 1127 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE; 1128 if (!tb2[attr_id]) { 1129 hdd_debug("vdev %d: config attr not present", 1130 vdev_id); 1131 return -EINVAL; 1132 } 1133 1134 ml_config_state = nla_get_u32(tb2[attr_id]); 1135 hdd_debug("vdev %d: ml_link_id %d, ml_link_state:%d", 1136 vdev_id, ml_config_link_id, ml_config_state); 1137 link_id_list[num_links] = ml_config_link_id; 1138 config_state_list[num_links] = ml_config_state; 1139 num_links++; 1140 1141 if (num_links >= MLD_MAX_SUPPORTED_LINKS) 1142 break; 1143 } 1144 1145 status = policy_mgr_update_mlo_links_based_on_linkid( 1146 hdd_ctx->psoc, 1147 vdev_id, num_links, 1148 link_id_list, 1149 config_state_list); 1150 if (QDF_IS_STATUS_ERROR(status)) 1151 return -EINVAL; 1152 break; 1153 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED: 1154 attr_id = 1155 QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS; 1156 num_link_attr = tb[attr_id]; 1157 if (!num_link_attr) { 1158 hdd_debug("number of active state links not specified"); 1159 return -EINVAL; 1160 } 1161 ml_active_num_links = nla_get_u8(num_link_attr); 1162 hdd_debug("vdev %d: ml_active_num_links: %d", vdev_id, 1163 ml_active_num_links); 1164 if (ml_active_num_links > MLD_MAX_SUPPORTED_LINKS) 1165 return -EINVAL; 1166 status = policy_mgr_update_active_mlo_num_links(hdd_ctx->psoc, 1167 vdev_id, ml_active_num_links); 1168 if (QDF_IS_STATUS_ERROR(status)) 1169 return -EINVAL; 1170 break; 1171 default: 1172 hdd_debug("vdev %d: invalid ml_link_control_mode: %d", vdev_id, 1173 ml_link_control_mode); 1174 return -EINVAL; 1175 } 1176 1177 ucfg_mlme_set_ml_link_control_mode(hdd_ctx->psoc, vdev_id, 1178 ml_link_control_mode); 1179 1180 hdd_debug("vdev: %d, processed link state command successfully", 1181 vdev_id); 1182 return 0; 1183 } 1184 1185 static uint32_t 1186 hdd_get_t2lm_setup_event_len(void) 1187 { 1188 uint32_t len = 0; 1189 uint32_t info_len = 0; 1190 1191 len = NLMSG_HDRLEN; 1192 1193 /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR */ 1194 len += nla_total_size(QDF_MAC_ADDR_SIZE); 1195 1196 /* nest */ 1197 info_len = NLA_HDRLEN; 1198 /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK */ 1199 info_len += NLA_HDRLEN + sizeof(u16); 1200 /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK */ 1201 info_len += NLA_HDRLEN + sizeof(u16); 1202 1203 /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS */ 1204 len += NLA_HDRLEN + (info_len * T2LM_MAX_NUM_TIDS); 1205 1206 return len; 1207 } 1208 1209 static QDF_STATUS 1210 hdd_t2lm_pack_nl_response(struct sk_buff *skb, 1211 struct wlan_objmgr_vdev *vdev, 1212 struct wlan_t2lm_info *t2lm, 1213 struct qdf_mac_addr mld_addr) 1214 { 1215 struct nlattr *config_attr, *config_params; 1216 uint32_t i = 0, attr, attr1; 1217 int errno; 1218 uint32_t value; 1219 uint8_t tid_num; 1220 1221 attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR; 1222 if (nla_put(skb, attr, QDF_MAC_ADDR_SIZE, mld_addr.bytes)) { 1223 hdd_err("Failed to put mac_addr"); 1224 return QDF_STATUS_E_INVAL; 1225 } 1226 1227 if (t2lm->default_link_mapping) { 1228 hdd_debug("update mld addr for default mapping"); 1229 return QDF_STATUS_SUCCESS; 1230 } 1231 1232 attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS; 1233 config_attr = nla_nest_start(skb, attr); 1234 if (!config_attr) { 1235 hdd_err("nla_nest_start error"); 1236 return QDF_STATUS_E_INVAL; 1237 } 1238 1239 switch (t2lm->direction) { 1240 case WLAN_T2LM_UL_DIRECTION: 1241 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 1242 config_params = nla_nest_start(skb, tid_num + 1); 1243 if (!config_params) 1244 return -EINVAL; 1245 1246 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; 1247 value = t2lm->ieee_link_map_tid[i]; 1248 errno = nla_put_u16(skb, attr1, value); 1249 if (errno) 1250 return errno; 1251 1252 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; 1253 value = 0; 1254 errno = nla_put_u16(skb, attr1, value); 1255 if (errno) 1256 return errno; 1257 nla_nest_end(skb, config_params); 1258 } 1259 break; 1260 case WLAN_T2LM_DL_DIRECTION: 1261 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 1262 config_params = nla_nest_start(skb, tid_num + 1); 1263 if (!config_params) 1264 return -EINVAL; 1265 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; 1266 value = t2lm->ieee_link_map_tid[i]; 1267 errno = nla_put_u16(skb, attr1, value); 1268 if (errno) 1269 return errno; 1270 1271 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; 1272 value = 0; 1273 errno = nla_put_u16(skb, attr1, value); 1274 if (errno) 1275 return errno; 1276 nla_nest_end(skb, config_params); 1277 } 1278 break; 1279 case WLAN_T2LM_BIDI_DIRECTION: 1280 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 1281 config_params = nla_nest_start(skb, tid_num + 1); 1282 if (!config_params) 1283 return -EINVAL; 1284 1285 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; 1286 value = t2lm->ieee_link_map_tid[i]; 1287 errno = nla_put_u16(skb, attr1, value); 1288 if (errno) 1289 return errno; 1290 1291 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; 1292 value = t2lm->ieee_link_map_tid[i]; 1293 errno = nla_put_u16(skb, attr1, value); 1294 if (errno) 1295 return errno; 1296 nla_nest_end(skb, config_params); 1297 } 1298 break; 1299 default: 1300 return -EINVAL; 1301 } 1302 nla_nest_end(skb, config_attr); 1303 return QDF_STATUS_SUCCESS; 1304 } 1305 1306 QDF_STATUS wlan_hdd_send_t2lm_event(struct wlan_objmgr_vdev *vdev, 1307 struct wlan_t2lm_info *t2lm) 1308 { 1309 struct sk_buff *skb; 1310 size_t data_len; 1311 QDF_STATUS status; 1312 struct qdf_mac_addr mld_addr; 1313 struct hdd_adapter *adapter; 1314 struct wlan_hdd_link_info *link_info; 1315 1316 enum qca_nl80211_vendor_subcmds_index index = 1317 QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP_INDEX; 1318 1319 link_info = wlan_hdd_get_link_info_from_objmgr(vdev); 1320 if (!link_info) { 1321 hdd_err("Invalid VDEV"); 1322 return QDF_STATUS_E_FAILURE; 1323 } 1324 1325 adapter = link_info->adapter; 1326 data_len = hdd_get_t2lm_setup_event_len(); 1327 skb = wlan_cfg80211_vendor_event_alloc(adapter->hdd_ctx->wiphy, 1328 NULL, 1329 data_len, 1330 index, GFP_KERNEL); 1331 if (!skb) { 1332 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 1333 return -EINVAL; 1334 } 1335 1336 /* get mld addr */ 1337 status = wlan_vdev_get_bss_peer_mld_mac(vdev, &mld_addr); 1338 if (QDF_IS_STATUS_ERROR(status)) { 1339 hdd_err("Failed to get mld address"); 1340 goto free_skb; 1341 } 1342 1343 status = hdd_t2lm_pack_nl_response(skb, vdev, t2lm, mld_addr); 1344 if (QDF_IS_STATUS_ERROR(status)) { 1345 hdd_err("Failed to pack nl response"); 1346 goto free_skb; 1347 } 1348 1349 wlan_cfg80211_vendor_event(skb, GFP_KERNEL); 1350 1351 return status; 1352 free_skb: 1353 wlan_cfg80211_vendor_free_skb(skb); 1354 1355 return status; 1356 } 1357 #endif 1358