1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2023 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 800 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 eht_capab, 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 ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); 471 if (!(eht_capab && 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 ret = wlan_handle_mlo_link_state_operation(wiphy, vdev, hdd_ctx, 638 data, data_len); 639 640 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); 641 642 return ret; 643 } 644 645 int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy, 646 struct wireless_dev *wdev, 647 const void *data, int data_len) 648 { 649 int errno; 650 struct osif_vdev_sync *vdev_sync; 651 652 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 653 if (errno) 654 return errno; 655 656 errno = __wlan_hdd_cfg80211_process_ml_link_state(wiphy, wdev, data, 657 data_len); 658 659 osif_vdev_sync_op_stop(vdev_sync); 660 661 return errno; 662 } 663 664 static inline void ml_link_state_resp_cb(struct ml_link_state_info_event *ev, 665 void *cookie) 666 { 667 struct ml_link_state_info_event *priv; 668 struct osif_request *request; 669 670 request = osif_request_get(cookie); 671 672 if (!request) { 673 hdd_err("Obsolete request"); 674 return; 675 } 676 677 priv = osif_request_priv(request); 678 679 qdf_mem_copy(priv, ev, sizeof(*priv)); 680 osif_request_complete(request); 681 osif_request_put(request); 682 } 683 684 static uint32_t 685 hdd_get_ml_link_state_response_len(const struct ml_link_state_info_event *event) 686 { 687 uint32_t len = 0; 688 uint32_t info_len = 0; 689 690 len = NLMSG_HDRLEN; 691 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE */ 692 len += NLA_HDRLEN + sizeof(u32); 693 694 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE */ 695 len += NLA_HDRLEN + sizeof(u32); 696 697 /* nest */ 698 info_len = NLA_HDRLEN; 699 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID */ 700 info_len += NLA_HDRLEN + sizeof(u8); 701 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE */ 702 info_len += NLA_HDRLEN + sizeof(u32); 703 704 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG */ 705 len += NLA_HDRLEN + (info_len * event->num_mlo_vdev_link_info); 706 707 return len; 708 } 709 710 static int 711 hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb, 712 struct wlan_objmgr_psoc *psoc, 713 struct ml_link_state_info_event *params, 714 uint32_t num_link_info) 715 { 716 struct nlattr *nla_config_attr, *nla_config_params; 717 uint32_t i = 0, attr; 718 int errno; 719 uint32_t value; 720 721 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE; 722 value = ucfg_mlme_get_ml_link_control_mode(psoc, params->vdev_id); 723 errno = nla_put_u32(skb, attr, value); 724 if (errno) 725 return errno; 726 727 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE; 728 729 /* Default link state operation mode is only supported */ 730 value = QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT; 731 errno = nla_put_u32(skb, attr, value); 732 if (errno) 733 return errno; 734 735 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG; 736 nla_config_attr = nla_nest_start(skb, attr); 737 738 if (!nla_config_attr) 739 return -EINVAL; 740 741 for (i = 0; i < num_link_info; i++) { 742 nla_config_params = nla_nest_start(skb, attr); 743 if (!nla_config_params) 744 return -EINVAL; 745 746 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID; 747 value = params->link_info[i].link_id; 748 errno = nla_put_u8(skb, attr, value); 749 if (errno) 750 return errno; 751 752 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE; 753 value = params->link_info[i].link_status; 754 errno = nla_put_u32(skb, attr, value); 755 756 if (errno) 757 return errno; 758 759 nla_nest_end(skb, nla_config_params); 760 } 761 762 nla_nest_end(skb, nla_config_attr); 763 764 return 0; 765 } 766 767 static char *link_state_status_id_to_str(uint32_t status) 768 { 769 switch (status) { 770 case WLAN_LINK_INFO_EVENT_SUCCESS: 771 return "LINK_INFO_EVENT_SUCCESS"; 772 case WLAN_LINK_INFO_EVENT_REJECT_FAILURE: 773 return "LINK_INFO_EVENT_REJECT_FAILURE"; 774 case WLAN_LINK_INFO_EVENT_REJECT_VDEV_NOT_UP: 775 return "LINK_INFO_EVENT_REJECT_VDEV_NOT_UP"; 776 case WLAN_LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS: 777 return "LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS"; 778 case WLAN_LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION: 779 return "LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION"; 780 } 781 return "Undefined link state status ID"; 782 } 783 784 static QDF_STATUS wlan_hdd_link_state_request(struct wiphy *wiphy, 785 struct wlan_objmgr_psoc *psoc, 786 struct wlan_objmgr_vdev *vdev) 787 { 788 int errno; 789 int skb_len; 790 struct sk_buff *reply_skb = NULL; 791 QDF_STATUS status = QDF_STATUS_E_INVAL; 792 void *cookie; 793 struct ml_link_state_info_event *link_state_event = NULL; 794 struct osif_request *request; 795 struct ml_link_state_cmd_info info = {0}; 796 int num_info = 0; 797 static const struct osif_request_params params = { 798 .priv_size = sizeof(*link_state_event), 799 .timeout_ms = WLAN_WAIT_TIME_LINK_STATE, 800 .dealloc = NULL, 801 }; 802 803 if (!wiphy || !vdev) 804 return status; 805 806 request = osif_request_alloc(¶ms); 807 if (!request) 808 return QDF_STATUS_E_NOMEM; 809 810 cookie = osif_request_cookie(request); 811 link_state_event = osif_request_priv(request); 812 813 info.request_cookie = cookie; 814 info.ml_link_state_resp_cb = ml_link_state_resp_cb; 815 816 status = mlo_get_link_state_register_resp_cb(vdev, 817 &info); 818 if (QDF_IS_STATUS_ERROR(status)) { 819 hdd_err("Failed to register resp callback: %d", status); 820 status = qdf_status_to_os_return(status); 821 goto free_event; 822 } 823 824 status = ml_post_get_link_state_msg(vdev); 825 if (QDF_IS_STATUS_ERROR(status)) { 826 hdd_err("Failed to post scheduler msg"); 827 goto free_event; 828 return status; 829 } 830 831 status = osif_request_wait_for_response(request); 832 if (status) { 833 hdd_err("wait failed or timed out ret: %d", status); 834 goto free_event; 835 } 836 837 hdd_debug("ml_link_state_resp: vdev id %d status %d num %d MAC addr " QDF_MAC_ADDR_FMT, 838 link_state_event->vdev_id, link_state_event->status, 839 link_state_event->num_mlo_vdev_link_info, 840 QDF_MAC_ADDR_REF(link_state_event->mldaddr.bytes)); 841 842 if (QDF_IS_STATUS_ERROR(link_state_event->status)) { 843 hdd_debug("ml_link_state_status failed %s", 844 link_state_status_id_to_str(link_state_event->status)); 845 return QDF_STATUS_E_INVAL; 846 } 847 848 for (num_info = 0; num_info < link_state_event->num_mlo_vdev_link_info; 849 num_info++) { 850 hdd_debug("ml_link_state_resp: chan_freq %d vdev_id %d link_id %d link_status %d", 851 link_state_event->link_info[num_info].chan_freq, 852 link_state_event->link_info[num_info].vdev_id, 853 link_state_event->link_info[num_info].link_id, 854 link_state_event->link_info[num_info].link_status); 855 } 856 857 skb_len = hdd_get_ml_link_state_response_len(link_state_event); 858 859 reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb( 860 wiphy, 861 skb_len); 862 if (!reply_skb) { 863 hdd_err("Get stats - alloc reply_skb failed"); 864 status = QDF_STATUS_E_NOMEM; 865 goto free_event; 866 } 867 868 status = hdd_ml_generate_link_state_resp_nlmsg( 869 reply_skb, psoc, link_state_event, 870 link_state_event->num_mlo_vdev_link_info); 871 if (QDF_IS_STATUS_ERROR(status)) { 872 hdd_err("Failed to pack nl response"); 873 goto free_skb; 874 } 875 876 osif_request_put(request); 877 878 errno = wlan_cfg80211_vendor_cmd_reply(reply_skb); 879 return qdf_status_from_os_return(errno); 880 881 free_skb: 882 wlan_cfg80211_vendor_free_skb(reply_skb); 883 free_event: 884 osif_request_put(request); 885 886 return status; 887 } 888 889 #define MLD_MAX_SUPPORTED_LINKS 2 890 891 int wlan_handle_mlo_link_state_operation(struct wiphy *wiphy, 892 struct wlan_objmgr_vdev *vdev, 893 struct hdd_context *hdd_ctx, 894 const void *data, int data_len) 895 { 896 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1]; 897 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1]; 898 enum qca_wlan_vendor_link_state_op_types ml_link_op; 899 struct nlattr *link_oper_attr, *mode_attr, *curr_attr, *num_link_attr; 900 int rem_len = 0, rc; 901 uint32_t attr_id, ml_config_state; 902 uint8_t ml_active_num_links, ml_link_control_mode; 903 uint8_t ml_config_link_id, num_links = 0; 904 uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; 905 uint8_t link_id_list[MLD_MAX_SUPPORTED_LINKS] = {0}; 906 uint32_t config_state_list[MLD_MAX_SUPPORTED_LINKS] = {0}; 907 QDF_STATUS status; 908 909 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX, 910 data, data_len, 911 ml_link_state_request_policy)) { 912 hdd_debug("vdev %d: invalid mlo link state attr", vdev_id); 913 return -EINVAL; 914 } 915 916 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE; 917 link_oper_attr = tb[attr_id]; 918 if (!link_oper_attr) { 919 hdd_debug("vdev %d: link state op not specified", vdev_id); 920 return -EINVAL; 921 } 922 ml_link_op = nla_get_u8(link_oper_attr); 923 switch (ml_link_op) { 924 case QCA_WLAN_VENDOR_LINK_STATE_OP_GET: 925 return wlan_hdd_link_state_request(wiphy, hdd_ctx->psoc, vdev); 926 case QCA_WLAN_VENDOR_LINK_STATE_OP_SET: 927 if (policy_mgr_is_set_link_in_progress(hdd_ctx->psoc)) { 928 hdd_debug("vdev %d: change link already in progress", 929 vdev_id); 930 return -EBUSY; 931 } 932 933 break; 934 default: 935 hdd_debug("vdev %d: Invalid op type:%d", vdev_id, ml_link_op); 936 return -EINVAL; 937 } 938 939 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE; 940 mode_attr = tb[attr_id]; 941 if (!mode_attr) { 942 hdd_debug("vdev %d: ml links control mode attr not present", 943 vdev_id); 944 return -EINVAL; 945 } 946 ml_link_control_mode = nla_get_u8(mode_attr); 947 948 switch (ml_link_control_mode) { 949 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT: 950 /* clear mlo link(s) settings in fw as per driver */ 951 status = policy_mgr_clear_ml_links_settings_in_fw(hdd_ctx->psoc, 952 vdev_id); 953 if (QDF_IS_STATUS_ERROR(status)) 954 return -EINVAL; 955 break; 956 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER: 957 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG; 958 if (!tb[attr_id]) { 959 hdd_debug("vdev %d: state config attr not present", 960 vdev_id); 961 return -EINVAL; 962 } 963 964 nla_for_each_nested(curr_attr, tb[attr_id], rem_len) { 965 rc = wlan_cfg80211_nla_parse_nested( 966 tb2, QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX, 967 curr_attr, 968 ml_link_state_config_policy); 969 if (rc) { 970 hdd_debug("vdev %d: nested attr not present", 971 vdev_id); 972 return -EINVAL; 973 } 974 975 attr_id = 976 QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID; 977 if (!tb2[attr_id]) { 978 hdd_debug("vdev %d: link id attr not present", 979 vdev_id); 980 return -EINVAL; 981 } 982 983 ml_config_link_id = nla_get_u8(tb2[attr_id]); 984 985 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE; 986 if (!tb2[attr_id]) { 987 hdd_debug("vdev %d: config attr not present", 988 vdev_id); 989 return -EINVAL; 990 } 991 992 ml_config_state = nla_get_u32(tb2[attr_id]); 993 hdd_debug("vdev %d: ml_link_id %d, ml_link_state:%d", 994 vdev_id, ml_config_link_id, ml_config_state); 995 link_id_list[num_links] = ml_config_link_id; 996 config_state_list[num_links] = ml_config_state; 997 num_links++; 998 999 if (num_links >= MLD_MAX_SUPPORTED_LINKS) 1000 break; 1001 } 1002 1003 status = policy_mgr_update_mlo_links_based_on_linkid( 1004 hdd_ctx->psoc, 1005 vdev_id, num_links, 1006 link_id_list, 1007 config_state_list); 1008 if (QDF_IS_STATUS_ERROR(status)) 1009 return -EINVAL; 1010 break; 1011 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED: 1012 attr_id = 1013 QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS; 1014 num_link_attr = tb[attr_id]; 1015 if (!num_link_attr) { 1016 hdd_debug("number of active state links not specified"); 1017 return -EINVAL; 1018 } 1019 ml_active_num_links = nla_get_u8(num_link_attr); 1020 hdd_debug("vdev %d: ml_active_num_links: %d", vdev_id, 1021 ml_active_num_links); 1022 if (ml_active_num_links > MLD_MAX_SUPPORTED_LINKS) 1023 return -EINVAL; 1024 status = policy_mgr_update_active_mlo_num_links(hdd_ctx->psoc, 1025 vdev_id, ml_active_num_links); 1026 if (QDF_IS_STATUS_ERROR(status)) 1027 return -EINVAL; 1028 break; 1029 default: 1030 hdd_debug("vdev %d: invalid ml_link_control_mode: %d", vdev_id, 1031 ml_link_control_mode); 1032 return -EINVAL; 1033 } 1034 1035 ucfg_mlme_set_ml_link_control_mode(hdd_ctx->psoc, vdev_id, 1036 ml_link_control_mode); 1037 1038 hdd_debug("vdev: %d, processed link state command successfully", 1039 vdev_id); 1040 return 0; 1041 } 1042 1043 static uint32_t 1044 hdd_get_t2lm_setup_event_len(void) 1045 { 1046 uint32_t len = 0; 1047 uint32_t info_len = 0; 1048 1049 len = NLMSG_HDRLEN; 1050 1051 /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR */ 1052 len += nla_total_size(QDF_MAC_ADDR_SIZE); 1053 1054 /* nest */ 1055 info_len = NLA_HDRLEN; 1056 /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK */ 1057 info_len += NLA_HDRLEN + sizeof(u16); 1058 /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK */ 1059 info_len += NLA_HDRLEN + sizeof(u16); 1060 1061 /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS */ 1062 len += NLA_HDRLEN + (info_len * T2LM_MAX_NUM_TIDS); 1063 1064 return len; 1065 } 1066 1067 static QDF_STATUS 1068 hdd_t2lm_pack_nl_response(struct sk_buff *skb, 1069 struct wlan_objmgr_vdev *vdev, 1070 struct wlan_t2lm_info *t2lm, 1071 struct qdf_mac_addr mld_addr) 1072 { 1073 struct nlattr *config_attr, *config_params; 1074 uint32_t i = 0, attr, attr1; 1075 int errno; 1076 uint32_t value; 1077 uint8_t tid_num; 1078 1079 attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR; 1080 if (nla_put(skb, attr, QDF_MAC_ADDR_SIZE, mld_addr.bytes)) { 1081 hdd_err("Failed to put mac_addr"); 1082 return QDF_STATUS_E_INVAL; 1083 } 1084 1085 if (t2lm->default_link_mapping) { 1086 hdd_debug("update mld addr for default mapping"); 1087 return QDF_STATUS_SUCCESS; 1088 } 1089 1090 attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS; 1091 config_attr = nla_nest_start(skb, attr); 1092 if (!config_attr) { 1093 hdd_err("nla_nest_start error"); 1094 return QDF_STATUS_E_INVAL; 1095 } 1096 1097 switch (t2lm->direction) { 1098 case WLAN_T2LM_UL_DIRECTION: 1099 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 1100 config_params = nla_nest_start(skb, tid_num + 1); 1101 if (!config_params) 1102 return -EINVAL; 1103 1104 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; 1105 value = t2lm->ieee_link_map_tid[i]; 1106 errno = nla_put_u16(skb, attr1, value); 1107 if (errno) 1108 return errno; 1109 1110 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; 1111 value = 0; 1112 errno = nla_put_u16(skb, attr1, value); 1113 if (errno) 1114 return errno; 1115 nla_nest_end(skb, config_params); 1116 } 1117 break; 1118 case WLAN_T2LM_DL_DIRECTION: 1119 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 1120 config_params = nla_nest_start(skb, tid_num + 1); 1121 if (!config_params) 1122 return -EINVAL; 1123 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; 1124 value = t2lm->ieee_link_map_tid[i]; 1125 errno = nla_put_u16(skb, attr1, value); 1126 if (errno) 1127 return errno; 1128 1129 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; 1130 value = 0; 1131 errno = nla_put_u16(skb, attr1, value); 1132 if (errno) 1133 return errno; 1134 nla_nest_end(skb, config_params); 1135 } 1136 break; 1137 case WLAN_T2LM_BIDI_DIRECTION: 1138 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 1139 config_params = nla_nest_start(skb, tid_num + 1); 1140 if (!config_params) 1141 return -EINVAL; 1142 1143 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; 1144 value = t2lm->ieee_link_map_tid[i]; 1145 errno = nla_put_u16(skb, attr1, value); 1146 if (errno) 1147 return errno; 1148 1149 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; 1150 value = t2lm->ieee_link_map_tid[i]; 1151 errno = nla_put_u16(skb, attr1, value); 1152 if (errno) 1153 return errno; 1154 nla_nest_end(skb, config_params); 1155 } 1156 break; 1157 default: 1158 return -EINVAL; 1159 } 1160 nla_nest_end(skb, config_attr); 1161 return QDF_STATUS_SUCCESS; 1162 } 1163 1164 QDF_STATUS wlan_hdd_send_t2lm_event(struct wlan_objmgr_vdev *vdev, 1165 struct wlan_t2lm_info *t2lm) 1166 { 1167 struct sk_buff *skb; 1168 size_t data_len; 1169 QDF_STATUS status; 1170 struct qdf_mac_addr mld_addr; 1171 struct hdd_adapter *adapter; 1172 struct wlan_hdd_link_info *link_info; 1173 1174 enum qca_nl80211_vendor_subcmds_index index = 1175 QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP_INDEX; 1176 1177 link_info = wlan_hdd_get_link_info_from_objmgr(vdev); 1178 if (!link_info) { 1179 hdd_err("Invalid VDEV"); 1180 return QDF_STATUS_E_FAILURE; 1181 } 1182 1183 adapter = link_info->adapter; 1184 data_len = hdd_get_t2lm_setup_event_len(); 1185 skb = wlan_cfg80211_vendor_event_alloc(adapter->hdd_ctx->wiphy, 1186 NULL, 1187 data_len, 1188 index, GFP_KERNEL); 1189 if (!skb) { 1190 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 1191 return -EINVAL; 1192 } 1193 1194 /* get mld addr */ 1195 status = wlan_vdev_get_bss_peer_mld_mac(vdev, &mld_addr); 1196 if (QDF_IS_STATUS_ERROR(status)) { 1197 hdd_err("Failed to get mld address"); 1198 goto free_skb; 1199 } 1200 1201 status = hdd_t2lm_pack_nl_response(skb, vdev, t2lm, mld_addr); 1202 if (QDF_IS_STATUS_ERROR(status)) { 1203 hdd_err("Failed to pack nl response"); 1204 goto free_skb; 1205 } 1206 1207 wlan_cfg80211_vendor_event(skb, GFP_KERNEL); 1208 1209 return status; 1210 free_skb: 1211 wlan_cfg80211_vendor_free_skb(skb); 1212 1213 return status; 1214 } 1215 #endif 1216