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("Default VDEV %d not equal", adapter->deflink->vdev_id); 296 QDF_ASSERT(0); 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 /* Fill current link info's actual VDEV info */ 421 qdf_spin_lock_bh(&link_info->vdev_lock); 422 link_info->vdev = vdev; 423 link_info->vdev_id = vdev_id; 424 qdf_spin_unlock_bh(&link_info->vdev_lock); 425 426 /* Swap link flags */ 427 link_flags = temp_link_info->link_flags; 428 temp_link_info->link_flags = link_info->link_flags; 429 link_info->link_flags = link_flags; 430 431 /* Update VDEV-OSIF priv pointer to new link info. */ 432 if (!vdev) 433 continue; 434 435 osif_priv = wlan_vdev_get_ospriv(vdev); 436 if (!osif_priv) 437 continue; 438 osif_priv->legacy_osif_priv = link_info; 439 440 /* Update the mapping, current link info's mapping will be 441 * set to be proper. 442 */ 443 adapter->curr_link_info_map[temp_link_idx] = 444 adapter->curr_link_info_map[cur_link_idx]; 445 adapter->curr_link_info_map[cur_link_idx] = cur_link_idx; 446 } 447 hdd_adapter_disable_all_links(adapter); 448 } 449 450 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter, 451 struct qdf_mac_addr mac_addr) 452 { 453 int idx, i, ret = 0; 454 bool eht_capab, update_self_peer; 455 QDF_STATUS status; 456 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 457 struct wlan_hdd_link_info *link_info; 458 uint8_t *addr_list[WLAN_MAX_ML_BSS_LINKS + 1] = {0}; 459 struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0}; 460 461 /* This API is only called with is ml adapter set for STA mode adapter. 462 * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for 463 * MAC address update. 464 */ 465 ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); 466 if (!(eht_capab && hdd_adapter_is_ml_adapter(adapter))) { 467 struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; 468 469 ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr, 470 mld_addr, true); 471 return ret; 472 } 473 474 status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, 475 &mac_addr, &link_addrs[0], 476 WLAN_MAX_ML_BSS_LINKS); 477 478 if (QDF_IS_STATUS_ERROR(status)) 479 return qdf_status_to_os_return(status); 480 481 hdd_adapter_restore_link_vdev_map(adapter); 482 483 i = 0; 484 hdd_adapter_for_each_active_link_info(adapter, link_info) { 485 idx = hdd_adapter_get_index_of_link_info(link_info); 486 addr_list[i++] = &link_addrs[idx].bytes[0]; 487 } 488 489 status = sme_check_for_duplicate_session(hdd_ctx->mac_handle, 490 &addr_list[0]); 491 if (QDF_IS_STATUS_ERROR(status)) 492 return qdf_status_to_os_return(status); 493 494 i = 0; 495 hdd_adapter_for_each_link_info(adapter, link_info) 496 qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]); 497 498 hdd_adapter_for_each_active_link_info(adapter, link_info) { 499 idx = hdd_adapter_get_index_of_link_info(link_info); 500 update_self_peer = 501 (link_info == adapter->deflink) ? true : false; 502 ret = hdd_dynamic_mac_address_set(link_info, link_addrs[idx], 503 mac_addr, update_self_peer); 504 if (ret) 505 return ret; 506 507 qdf_copy_macaddr(&link_info->link_addr, &link_addrs[idx]); 508 } 509 510 hdd_adapter_update_mlo_mgr_mac_addr(adapter); 511 return ret; 512 } 513 #else 514 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter, 515 struct qdf_mac_addr mac_addr) 516 { 517 int i, ret = 0; 518 QDF_STATUS status; 519 bool eht_capab, update_self_peer; 520 struct hdd_adapter *link_adapter; 521 struct hdd_mlo_adapter_info *mlo_adapter_info; 522 struct hdd_context *hdd_ctx = adapter->hdd_ctx; 523 uint8_t *addr_list[WLAN_MAX_MLD + 1] = {0}; 524 struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0}; 525 526 /* This API is only called with is ml adapter set for STA mode adapter. 527 * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for 528 * MAC address update. 529 */ 530 ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); 531 if (!(eht_capab && hdd_adapter_is_ml_adapter(adapter))) { 532 struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; 533 534 ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr, 535 mld_addr, true); 536 return ret; 537 } 538 539 status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, 540 &mac_addr, &link_addrs[0], 541 WLAN_MAX_ML_BSS_LINKS); 542 543 if (QDF_IS_STATUS_ERROR(status)) 544 return qdf_status_to_os_return(status); 545 546 for (i = 0; i < WLAN_MAX_MLD; i++) 547 addr_list[i] = &link_addrs[i].bytes[0]; 548 549 status = sme_check_for_duplicate_session(hdd_ctx->mac_handle, 550 &addr_list[0]); 551 if (QDF_IS_STATUS_ERROR(status)) 552 return qdf_status_to_os_return(status); 553 554 mlo_adapter_info = &adapter->mlo_adapter_info; 555 for (i = 0; i < WLAN_MAX_MLD; i++) { 556 link_adapter = mlo_adapter_info->link_adapter[i]; 557 if (!link_adapter) 558 continue; 559 560 if (hdd_adapter_is_associated_with_ml_adapter(link_adapter)) 561 update_self_peer = true; 562 else 563 update_self_peer = false; 564 565 ret = hdd_dynamic_mac_address_set(link_adapter->deflink, 566 link_addrs[i], mac_addr, 567 update_self_peer); 568 if (ret) 569 return ret; 570 571 /* Update DP intf and new link address in link adapter 572 */ 573 ucfg_dp_update_intf_mac(hdd_ctx->psoc, &link_adapter->mac_addr, 574 &link_addrs[i], 575 link_adapter->deflink->vdev); 576 qdf_copy_macaddr(&link_adapter->mac_addr, &link_addrs[i]); 577 qdf_copy_macaddr(&adapter->link_info[i].link_addr, 578 &link_addrs[i]); 579 } 580 581 qdf_copy_macaddr(&adapter->link_info[i].link_addr, &link_addrs[i]); 582 hdd_adapter_update_mlo_mgr_mac_addr(adapter); 583 584 return ret; 585 } 586 #endif 587 #endif /* WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE */ 588 589 const struct nla_policy 590 ml_link_state_config_policy [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1] = { 591 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID] = {.type = NLA_U8}, 592 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE] = {.type = NLA_U32}, 593 }; 594 595 const struct nla_policy 596 ml_link_state_request_policy[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1] = { 597 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE] = {.type = NLA_U32}, 598 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE] = {.type = NLA_U32}, 599 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG] = {.type = NLA_NESTED}, 600 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS] = { 601 .type = NLA_U8}, 602 }; 603 604 static int 605 __wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy, 606 struct wireless_dev *wdev, 607 const void *data, int data_len) 608 { 609 int ret = 0; 610 struct net_device *dev = wdev->netdev; 611 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 612 struct wlan_objmgr_vdev *vdev; 613 struct hdd_context *hdd_ctx = NULL; 614 615 hdd_enter_dev(wdev->netdev); 616 617 if (hdd_validate_adapter(adapter)) 618 return -EINVAL; 619 620 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 621 if (!hdd_ctx) 622 return -EINVAL; 623 624 if (adapter->device_mode != QDF_STA_MODE) 625 return -EINVAL; 626 627 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); 628 629 if (!vdev) 630 return -EINVAL; 631 632 ret = wlan_handle_mlo_link_state_operation(wiphy, vdev, hdd_ctx, 633 data, data_len); 634 635 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); 636 637 return ret; 638 } 639 640 int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy, 641 struct wireless_dev *wdev, 642 const void *data, int data_len) 643 { 644 int errno; 645 struct osif_vdev_sync *vdev_sync; 646 647 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 648 if (errno) 649 return errno; 650 651 errno = __wlan_hdd_cfg80211_process_ml_link_state(wiphy, wdev, data, 652 data_len); 653 654 osif_vdev_sync_op_stop(vdev_sync); 655 656 return errno; 657 } 658 659 static inline void ml_link_state_resp_cb(struct ml_link_state_info_event *ev, 660 void *cookie) 661 { 662 struct ml_link_state_info_event *priv; 663 struct osif_request *request; 664 665 request = osif_request_get(cookie); 666 667 if (!request) { 668 hdd_err("Obsolete request"); 669 return; 670 } 671 672 priv = osif_request_priv(request); 673 674 qdf_mem_copy(priv, ev, sizeof(*priv)); 675 osif_request_complete(request); 676 osif_request_put(request); 677 } 678 679 static uint32_t 680 hdd_get_ml_link_state_response_len(const struct ml_link_state_info_event *event) 681 { 682 uint32_t len = 0; 683 uint32_t info_len = 0; 684 685 len = NLMSG_HDRLEN; 686 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE */ 687 len += NLA_HDRLEN + sizeof(u32); 688 689 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE */ 690 len += NLA_HDRLEN + sizeof(u32); 691 692 /* nest */ 693 info_len = NLA_HDRLEN; 694 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID */ 695 info_len += NLA_HDRLEN + sizeof(u8); 696 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE */ 697 info_len += NLA_HDRLEN + sizeof(u32); 698 699 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG */ 700 len += NLA_HDRLEN + (info_len * event->num_mlo_vdev_link_info); 701 702 return len; 703 } 704 705 static int 706 hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb, 707 struct wlan_objmgr_psoc *psoc, 708 struct ml_link_state_info_event *params, 709 uint32_t num_link_info) 710 { 711 struct nlattr *nla_config_attr, *nla_config_params; 712 uint32_t i = 0, attr; 713 int errno; 714 uint32_t value; 715 716 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE; 717 value = ucfg_mlme_get_ml_link_control_mode(psoc, params->vdev_id); 718 errno = nla_put_u32(skb, attr, value); 719 if (errno) 720 return errno; 721 722 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE; 723 724 /* Default link state operation mode is only supported */ 725 value = QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT; 726 errno = nla_put_u32(skb, attr, value); 727 if (errno) 728 return errno; 729 730 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG; 731 nla_config_attr = nla_nest_start(skb, attr); 732 733 if (!nla_config_attr) 734 return -EINVAL; 735 736 for (i = 0; i < num_link_info; i++) { 737 nla_config_params = nla_nest_start(skb, attr); 738 if (!nla_config_params) 739 return -EINVAL; 740 741 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID; 742 value = params->link_info[i].link_id; 743 errno = nla_put_u8(skb, attr, value); 744 if (errno) 745 return errno; 746 747 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE; 748 value = params->link_info[i].link_status; 749 errno = nla_put_u32(skb, attr, value); 750 751 if (errno) 752 return errno; 753 754 nla_nest_end(skb, nla_config_params); 755 } 756 757 nla_nest_end(skb, nla_config_attr); 758 759 return 0; 760 } 761 762 static QDF_STATUS wlan_hdd_link_state_request(struct wiphy *wiphy, 763 struct wlan_objmgr_psoc *psoc, 764 struct wlan_objmgr_vdev *vdev) 765 { 766 int errno; 767 int skb_len; 768 struct sk_buff *reply_skb = NULL; 769 QDF_STATUS status = QDF_STATUS_E_INVAL; 770 void *cookie; 771 struct ml_link_state_info_event *link_state_event = NULL; 772 struct osif_request *request; 773 struct ml_link_state_cmd_info info = {0}; 774 int num_info = 0; 775 static const struct osif_request_params params = { 776 .priv_size = sizeof(*link_state_event), 777 .timeout_ms = WLAN_WAIT_TIME_LINK_STATE, 778 .dealloc = NULL, 779 }; 780 781 if (!wiphy || !vdev) 782 return status; 783 784 request = osif_request_alloc(¶ms); 785 if (!request) 786 return QDF_STATUS_E_NOMEM; 787 788 cookie = osif_request_cookie(request); 789 link_state_event = osif_request_priv(request); 790 791 info.request_cookie = cookie; 792 info.ml_link_state_resp_cb = ml_link_state_resp_cb; 793 794 status = mlo_get_link_state_register_resp_cb(vdev, 795 &info); 796 if (QDF_IS_STATUS_ERROR(status)) { 797 hdd_err("Failed to register resp callback: %d", status); 798 status = qdf_status_to_os_return(status); 799 goto free_event; 800 } 801 802 status = ml_post_get_link_state_msg(vdev); 803 if (QDF_IS_STATUS_ERROR(status)) { 804 hdd_err("Failed to post scheduler msg"); 805 goto free_event; 806 return status; 807 } 808 809 status = osif_request_wait_for_response(request); 810 if (status) { 811 hdd_err("wait failed or timed out ret: %d", status); 812 goto free_event; 813 } 814 815 hdd_debug("ml_link_state_resp: vdev id %d status %d num %d MAC addr " QDF_MAC_ADDR_FMT, 816 link_state_event->vdev_id, link_state_event->status, 817 link_state_event->num_mlo_vdev_link_info, 818 QDF_MAC_ADDR_REF(link_state_event->mldaddr.bytes)); 819 820 for (num_info = 0; num_info < link_state_event->num_mlo_vdev_link_info; 821 num_info++) { 822 hdd_debug("ml_link_state_resp: chan_freq %d vdev_id %d link_id %d link_status %d", 823 link_state_event->link_info[num_info].chan_freq, 824 link_state_event->link_info[num_info].vdev_id, 825 link_state_event->link_info[num_info].link_id, 826 link_state_event->link_info[num_info].link_status); 827 } 828 829 skb_len = hdd_get_ml_link_state_response_len(link_state_event); 830 831 reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb( 832 wiphy, 833 skb_len); 834 if (!reply_skb) { 835 hdd_err("Get stats - alloc reply_skb failed"); 836 status = QDF_STATUS_E_NOMEM; 837 goto free_event; 838 } 839 840 status = hdd_ml_generate_link_state_resp_nlmsg( 841 reply_skb, psoc, link_state_event, 842 link_state_event->num_mlo_vdev_link_info); 843 if (QDF_IS_STATUS_ERROR(status)) { 844 hdd_err("Failed to pack nl response"); 845 goto free_skb; 846 } 847 848 osif_request_put(request); 849 850 errno = wlan_cfg80211_vendor_cmd_reply(reply_skb); 851 return qdf_status_from_os_return(errno); 852 853 free_skb: 854 wlan_cfg80211_vendor_free_skb(reply_skb); 855 free_event: 856 osif_request_put(request); 857 858 return status; 859 } 860 861 #define MLD_MAX_SUPPORTED_LINKS 2 862 863 int wlan_handle_mlo_link_state_operation(struct wiphy *wiphy, 864 struct wlan_objmgr_vdev *vdev, 865 struct hdd_context *hdd_ctx, 866 const void *data, int data_len) 867 { 868 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1]; 869 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1]; 870 enum qca_wlan_vendor_link_state_op_types ml_link_op; 871 struct nlattr *link_oper_attr, *mode_attr, *curr_attr, *num_link_attr; 872 int rem_len = 0, rc; 873 uint32_t attr_id, ml_config_state; 874 uint8_t ml_active_num_links, ml_link_control_mode; 875 uint8_t ml_config_link_id, num_links = 0; 876 uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; 877 uint8_t link_id_list[MLD_MAX_SUPPORTED_LINKS] = {0}; 878 uint32_t config_state_list[MLD_MAX_SUPPORTED_LINKS] = {0}; 879 QDF_STATUS status; 880 881 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX, 882 data, data_len, 883 ml_link_state_request_policy)) { 884 hdd_debug("vdev %d: invalid mlo link state attr", vdev_id); 885 return -EINVAL; 886 } 887 888 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE; 889 link_oper_attr = tb[attr_id]; 890 if (!link_oper_attr) { 891 hdd_debug("vdev %d: link state op not specified", vdev_id); 892 return -EINVAL; 893 } 894 ml_link_op = nla_get_u8(link_oper_attr); 895 switch (ml_link_op) { 896 case QCA_WLAN_VENDOR_LINK_STATE_OP_GET: 897 return wlan_hdd_link_state_request(wiphy, hdd_ctx->psoc, vdev); 898 case QCA_WLAN_VENDOR_LINK_STATE_OP_SET: 899 break; 900 default: 901 hdd_debug("vdev %d: Invalid op type:%d", vdev_id, ml_link_op); 902 return -EINVAL; 903 } 904 905 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE; 906 mode_attr = tb[attr_id]; 907 if (!mode_attr) { 908 hdd_debug("vdev %d: ml links control mode attr not present", 909 vdev_id); 910 return -EINVAL; 911 } 912 ml_link_control_mode = nla_get_u8(mode_attr); 913 914 switch (ml_link_control_mode) { 915 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT: 916 /* clear mlo link(s) settings in fw as per driver */ 917 status = policy_mgr_clear_ml_links_settings_in_fw(hdd_ctx->psoc, 918 vdev_id); 919 if (QDF_IS_STATUS_ERROR(status)) 920 return -EINVAL; 921 break; 922 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER: 923 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG; 924 if (!tb[attr_id]) { 925 hdd_debug("vdev %d: state config attr not present", 926 vdev_id); 927 return -EINVAL; 928 } 929 930 nla_for_each_nested(curr_attr, tb[attr_id], rem_len) { 931 rc = wlan_cfg80211_nla_parse_nested( 932 tb2, QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX, 933 curr_attr, 934 ml_link_state_config_policy); 935 if (rc) { 936 hdd_debug("vdev %d: nested attr not present", 937 vdev_id); 938 return -EINVAL; 939 } 940 941 attr_id = 942 QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID; 943 if (!tb2[attr_id]) { 944 hdd_debug("vdev %d: link id attr not present", 945 vdev_id); 946 return -EINVAL; 947 } 948 949 ml_config_link_id = nla_get_u8(tb2[attr_id]); 950 951 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE; 952 if (!tb2[attr_id]) { 953 hdd_debug("vdev %d: config attr not present", 954 vdev_id); 955 return -EINVAL; 956 } 957 958 ml_config_state = nla_get_u32(tb2[attr_id]); 959 hdd_debug("vdev %d: ml_link_id %d, ml_link_state:%d", 960 vdev_id, ml_config_link_id, ml_config_state); 961 link_id_list[num_links] = ml_config_link_id; 962 config_state_list[num_links] = ml_config_state; 963 num_links++; 964 965 if (num_links >= MLD_MAX_SUPPORTED_LINKS) 966 break; 967 } 968 969 status = policy_mgr_update_mlo_links_based_on_linkid( 970 hdd_ctx->psoc, 971 vdev_id, num_links, 972 link_id_list, 973 config_state_list); 974 if (QDF_IS_STATUS_ERROR(status)) 975 return -EINVAL; 976 break; 977 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED: 978 attr_id = 979 QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS; 980 num_link_attr = tb[attr_id]; 981 if (!num_link_attr) { 982 hdd_debug("number of active state links not specified"); 983 return -EINVAL; 984 } 985 ml_active_num_links = nla_get_u8(num_link_attr); 986 hdd_debug("vdev %d: ml_active_num_links: %d", vdev_id, 987 ml_active_num_links); 988 if (ml_active_num_links > MLD_MAX_SUPPORTED_LINKS) 989 return -EINVAL; 990 status = policy_mgr_update_active_mlo_num_links(hdd_ctx->psoc, 991 vdev_id, ml_active_num_links); 992 if (QDF_IS_STATUS_ERROR(status)) 993 return -EINVAL; 994 break; 995 default: 996 hdd_debug("vdev %d: invalid ml_link_control_mode: %d", vdev_id, 997 ml_link_control_mode); 998 return -EINVAL; 999 } 1000 1001 ucfg_mlme_set_ml_link_control_mode(hdd_ctx->psoc, vdev_id, 1002 ml_link_control_mode); 1003 1004 hdd_debug("vdev: %d, processed link state command successfully", 1005 vdev_id); 1006 return 0; 1007 } 1008 1009 static uint32_t 1010 hdd_get_t2lm_setup_event_len(void) 1011 { 1012 uint32_t len = 0; 1013 uint32_t info_len = 0; 1014 1015 len = NLMSG_HDRLEN; 1016 1017 /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR */ 1018 len += nla_total_size(QDF_MAC_ADDR_SIZE); 1019 1020 /* nest */ 1021 info_len = NLA_HDRLEN; 1022 /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK */ 1023 info_len += NLA_HDRLEN + sizeof(u16); 1024 /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK */ 1025 info_len += NLA_HDRLEN + sizeof(u16); 1026 1027 /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS */ 1028 len += NLA_HDRLEN + (info_len * T2LM_MAX_NUM_TIDS); 1029 1030 return len; 1031 } 1032 1033 static QDF_STATUS 1034 hdd_t2lm_pack_nl_response(struct sk_buff *skb, 1035 struct wlan_objmgr_vdev *vdev, 1036 struct wlan_t2lm_info *t2lm, 1037 struct qdf_mac_addr mld_addr) 1038 { 1039 struct nlattr *config_attr, *config_params; 1040 uint32_t i = 0, attr, attr1; 1041 int errno; 1042 uint32_t value; 1043 uint8_t tid_num; 1044 1045 attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR; 1046 if (nla_put(skb, attr, QDF_MAC_ADDR_SIZE, mld_addr.bytes)) { 1047 hdd_err("Failed to put mac_addr"); 1048 return QDF_STATUS_E_INVAL; 1049 } 1050 1051 if (t2lm->default_link_mapping) { 1052 hdd_debug("update mld addr for default mapping"); 1053 return QDF_STATUS_SUCCESS; 1054 } 1055 1056 attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS; 1057 config_attr = nla_nest_start(skb, attr); 1058 if (!config_attr) { 1059 hdd_err("nla_nest_start error"); 1060 return QDF_STATUS_E_INVAL; 1061 } 1062 1063 switch (t2lm->direction) { 1064 case WLAN_T2LM_UL_DIRECTION: 1065 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 1066 config_params = nla_nest_start(skb, tid_num + 1); 1067 if (!config_params) 1068 return -EINVAL; 1069 1070 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; 1071 value = t2lm->ieee_link_map_tid[i]; 1072 errno = nla_put_u16(skb, attr1, value); 1073 if (errno) 1074 return errno; 1075 1076 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; 1077 value = 0; 1078 errno = nla_put_u16(skb, attr1, value); 1079 if (errno) 1080 return errno; 1081 nla_nest_end(skb, config_params); 1082 } 1083 break; 1084 case WLAN_T2LM_DL_DIRECTION: 1085 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 1086 config_params = nla_nest_start(skb, tid_num + 1); 1087 if (!config_params) 1088 return -EINVAL; 1089 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; 1090 value = t2lm->ieee_link_map_tid[i]; 1091 errno = nla_put_u16(skb, attr1, value); 1092 if (errno) 1093 return errno; 1094 1095 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; 1096 value = 0; 1097 errno = nla_put_u16(skb, attr1, value); 1098 if (errno) 1099 return errno; 1100 nla_nest_end(skb, config_params); 1101 } 1102 break; 1103 case WLAN_T2LM_BIDI_DIRECTION: 1104 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 1105 config_params = nla_nest_start(skb, tid_num + 1); 1106 if (!config_params) 1107 return -EINVAL; 1108 1109 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; 1110 value = t2lm->ieee_link_map_tid[i]; 1111 errno = nla_put_u16(skb, attr1, value); 1112 if (errno) 1113 return errno; 1114 1115 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; 1116 value = t2lm->ieee_link_map_tid[i]; 1117 errno = nla_put_u16(skb, attr1, value); 1118 if (errno) 1119 return errno; 1120 nla_nest_end(skb, config_params); 1121 } 1122 break; 1123 default: 1124 return -EINVAL; 1125 } 1126 nla_nest_end(skb, config_attr); 1127 return QDF_STATUS_SUCCESS; 1128 } 1129 1130 QDF_STATUS wlan_hdd_send_t2lm_event(struct wlan_objmgr_vdev *vdev, 1131 struct wlan_t2lm_info *t2lm) 1132 { 1133 struct sk_buff *skb; 1134 size_t data_len; 1135 QDF_STATUS status; 1136 struct qdf_mac_addr mld_addr; 1137 struct hdd_adapter *adapter; 1138 struct wlan_hdd_link_info *link_info; 1139 1140 enum qca_nl80211_vendor_subcmds_index index = 1141 QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP_INDEX; 1142 1143 link_info = wlan_hdd_get_link_info_from_objmgr(vdev); 1144 if (!link_info) { 1145 hdd_err("Invalid VDEV"); 1146 return QDF_STATUS_E_FAILURE; 1147 } 1148 1149 adapter = link_info->adapter; 1150 data_len = hdd_get_t2lm_setup_event_len(); 1151 skb = wlan_cfg80211_vendor_event_alloc(adapter->hdd_ctx->wiphy, 1152 NULL, 1153 data_len, 1154 index, GFP_KERNEL); 1155 if (!skb) { 1156 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 1157 return -EINVAL; 1158 } 1159 1160 /* get mld addr */ 1161 status = wlan_vdev_get_bss_peer_mld_mac(vdev, &mld_addr); 1162 if (QDF_IS_STATUS_ERROR(status)) { 1163 hdd_err("Failed to get mld address"); 1164 goto free_skb; 1165 } 1166 1167 status = hdd_t2lm_pack_nl_response(skb, vdev, t2lm, mld_addr); 1168 if (QDF_IS_STATUS_ERROR(status)) { 1169 hdd_err("Failed to pack nl response"); 1170 goto free_skb; 1171 } 1172 1173 wlan_cfg80211_vendor_event(skb, GFP_KERNEL); 1174 1175 return status; 1176 free_skb: 1177 wlan_cfg80211_vendor_free_skb(skb); 1178 1179 return status; 1180 } 1181 #endif 1182