From 0752365a21a84eb988fc342870569066c3f3f02b Mon Sep 17 00:00:00 2001 From: Paul Zhang Date: Mon, 3 Apr 2023 13:58:22 +0800 Subject: [PATCH] qcacld-3.0: Add logic to support tdls on MLO Since for MLD device, it can only choice one link for tdls, add logic like this: 1\ As initiator, it needs to send discovery request on each link, before send the frame, it needs to force active the link; 2\ As responder, it sends the discovery response the link id, before send the frame, it needs to force active the link; 3\ For other tdls management and tdls operation, it needs to find out which link(vdev) is used as tdls link first. Change-Id: I64e27219eb6c6b3fef62e541423aa8e5d84b1560 CRs-Fixed: 3439568 --- components/tdls/core/src/wlan_tdls_ct.c | 13 +- components/tdls/core/src/wlan_tdls_mgmt.c | 85 ++++++++- .../dispatcher/inc/wlan_tdls_public_structs.h | 4 + .../tdls/dispatcher/inc/wlan_tdls_ucfg_api.h | 48 +++++ .../tdls/dispatcher/src/wlan_tdls_ucfg_api.c | 44 +++++ core/hdd/src/wlan_hdd_cfg80211.c | 57 ++++-- core/hdd/src/wlan_hdd_tdls.c | 27 ++- os_if/tdls/inc/wlan_cfg80211_tdls.h | 28 +-- os_if/tdls/src/wlan_cfg80211_tdls.c | 178 ++++++++++++++++-- 9 files changed, 429 insertions(+), 55 deletions(-) diff --git a/components/tdls/core/src/wlan_tdls_ct.c b/components/tdls/core/src/wlan_tdls_ct.c index 8f50a8993c..cf173294b8 100644 --- a/components/tdls/core/src/wlan_tdls_ct.c +++ b/components/tdls/core/src/wlan_tdls_ct.c @@ -1008,6 +1008,7 @@ static void tdls_ct_process_handler(struct wlan_objmgr_vdev *vdev) void tdls_ct_handler(void *user_data) { struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *link_vdev; if (!user_data) return; @@ -1016,7 +1017,17 @@ void tdls_ct_handler(void *user_data) if (!vdev) return; - tdls_ct_process_handler(vdev); + link_vdev = tdls_mlo_get_tdls_link_vdev(vdev); + if (link_vdev) { + if (wlan_objmgr_vdev_try_get_ref(link_vdev, WLAN_TDLS_NB_ID) == + QDF_STATUS_SUCCESS) { + tdls_ct_process_handler(link_vdev); + wlan_objmgr_vdev_release_ref(link_vdev, + WLAN_TDLS_NB_ID); + } + } else { + tdls_ct_process_handler(vdev); + } wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); diff --git a/components/tdls/core/src/wlan_tdls_mgmt.c b/components/tdls/core/src/wlan_tdls_mgmt.c index 0c67a0a9f2..2d99d1b969 100644 --- a/components/tdls/core/src/wlan_tdls_mgmt.c +++ b/components/tdls/core/src/wlan_tdls_mgmt.c @@ -634,14 +634,15 @@ static QDF_STATUS tdls_activate_send_mgmt_request_flush_cb( return QDF_STATUS_SUCCESS; } -static QDF_STATUS tdls_activate_send_mgmt_request( - struct tdls_action_frame_request *action_req) +static QDF_STATUS +tdls_activate_send_mgmt_request(struct tdls_action_frame_request *action_req) { - struct wlan_objmgr_peer *peer; struct tdls_soc_priv_obj *tdls_soc_obj; - QDF_STATUS status = QDF_STATUS_SUCCESS; - struct scheduler_msg msg = {0}; + QDF_STATUS status; struct tdls_send_mgmt_request *tdls_mgmt_req; + struct wlan_objmgr_peer *peer; + struct scheduler_msg msg = {0}; + struct tdls_vdev_priv_obj *tdls_vdev; if (!action_req || !action_req->vdev) return QDF_STATUS_E_NULL_VALUE; @@ -684,6 +685,7 @@ static QDF_STATUS tdls_activate_send_mgmt_request( if (!peer) { tdls_err("bss peer is null"); qdf_mem_free(tdls_mgmt_req); + status = QDF_STATUS_E_NULL_VALUE; goto release_cmd; } @@ -707,6 +709,25 @@ static QDF_STATUS tdls_activate_send_mgmt_request( else tdls_mgmt_req->ac = WIFI_AC_BK; + if (wlan_vdev_mlme_is_mlo_vdev(action_req->vdev) && + !tdls_mlo_get_tdls_link_vdev(action_req->vdev) && + tdls_mgmt_req->req_type == TDLS_DISCOVERY_REQUEST) { + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(action_req->vdev); + if (QDF_TIMER_STATE_RUNNING != + qdf_mc_timer_get_current_state( + &tdls_vdev->peer_discovery_timer)) { + tdls_timer_restart(tdls_vdev->vdev, + &tdls_vdev->peer_discovery_timer, + tdls_vdev->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE); + qdf_atomic_inc(&tdls_soc_obj->timer_cnt); + } else { + qdf_mem_free(tdls_mgmt_req); + status = QDF_STATUS_E_NULL_VALUE; + goto release_cmd; + } + } + /* Send the request to PE. */ qdf_mem_zero(&msg, sizeof(msg)); @@ -781,6 +802,52 @@ tdls_send_mgmt_serialize_callback(struct wlan_serialization_command *cmd, return status; } +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) +{ + uint8_t mlo_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {-1}; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *mlo_tdls_vdev; + uint8_t vdev_count = 0; + bool is_mlo_vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(req->vdev); + if (!is_mlo_vdev) + return status; + + mlo_tdls_vdev = wlan_mlo_get_tdls_link_vdev(req->vdev); + if (mlo_tdls_vdev) + return status; + + psoc = wlan_vdev_get_psoc(req->vdev); + if (!psoc) { + tdls_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (req->tdls_mgmt.frame_type == TDLS_DISCOVERY_RESPONSE || + req->tdls_mgmt.frame_type == TDLS_DISCOVERY_REQUEST) { + mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev); + vdev_count = 1; + + status = policy_mgr_mlo_sta_set_link(psoc, + MLO_LINK_FORCE_REASON_TDLS, + MLO_LINK_FORCE_MODE_ACTIVE, + vdev_count, mlo_vdev_lst); + if (status == QDF_STATUS_SUCCESS) + req->link_active = true; + } + + return status; +} +#else +static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + QDF_STATUS tdls_process_mgmt_req( struct tdls_action_frame_request *tdls_mgmt_req) { @@ -796,6 +863,14 @@ QDF_STATUS tdls_process_mgmt_req( goto error_mgmt; } + status = tdls_set_link_mode(tdls_mgmt_req); + if (status != QDF_STATUS_SUCCESS) { + tdls_err("failed to set link active"); + status = tdls_internal_send_mgmt_tx_done(tdls_mgmt_req, + status); + goto error_mgmt; + } + /* update the responder, status code information * after the cmd validation */ diff --git a/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h b/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h index 102920c2e2..030cce202c 100644 --- a/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h +++ b/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h @@ -1176,20 +1176,24 @@ struct tdls_get_all_peers { * @vdev: vdev object * @chk_frame: This struct used to validate mgmt frame * @session_id: session id + * @link_id: link id * @vdev_id: vdev id * @cmd_buf: cmd buffer * @len: length of the frame * @use_default_ac: access category + * @link_active: whether link active command send successfully * @tdls_mgmt: tdls management */ struct tdls_action_frame_request { struct wlan_objmgr_vdev *vdev; struct tdls_validate_action_req chk_frame; uint8_t session_id; + uint8_t link_id; uint8_t vdev_id; const uint8_t *cmd_buf; uint8_t len; bool use_default_ac; + bool link_active; /* Variable length, do not add anything after this */ struct tdls_send_mgmt tdls_mgmt; }; diff --git a/components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h b/components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h index b301230f5a..3892ce552f 100644 --- a/components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h +++ b/components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h @@ -181,6 +181,35 @@ void ucfg_tdls_update_fw_mlo_capability(struct wlan_objmgr_psoc *psoc, } #endif +/** + * ucfg_tdls_link_vdev_is_matching() - check whether vdev is matching link vdev + * @vdev: vdev object + * + * Return: bool + */ +bool ucfg_tdls_link_vdev_is_matching(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_tdls_get_tdls_link_vdev() - get tdls link vdev + * @vdev: vdev object + * @dbg_id: debug id + * + * Return: vdev pointer + */ +struct wlan_objmgr_vdev * +ucfg_tdls_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * ucfg_tdls_put_tdls_link_vdev() - put tdls link vdev + * @vdev: vdev odject + * @dbg_id: debug id + * + * Return: void + */ +void ucfg_tdls_put_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id); + /** * ucfg_tdls_psoc_enable() - TDLS module enable API * @psoc: psoc object @@ -429,6 +458,25 @@ struct wlan_objmgr_vdev *ucfg_get_tdls_vdev(struct wlan_objmgr_psoc *psoc, wlan_objmgr_ref_dbgid dbg_id); #else +static inline +bool ucfg_tdls_link_vdev_is_matching(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline +struct wlan_objmgr_vdev * +ucfg_tdls_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ + return NULL; +} + +static inline +void ucfg_tdls_put_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ +} static inline QDF_STATUS ucfg_tdls_init(void) diff --git a/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c index cd8d764a78..15e76ce388 100644 --- a/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c +++ b/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -34,6 +34,7 @@ #include "wlan_policy_mgr_api.h" #include "wlan_scan_ucfg_api.h" #include "cfg_tdls.h" +#include "wlan_mlo_mgr_sta.h" #include "cfg_ucfg_api.h" #include "wlan_tdls_api.h" @@ -519,6 +520,49 @@ QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } +bool ucfg_tdls_link_vdev_is_matching(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_vdev *tdls_link_vdev; + + tdls_link_vdev = tdls_mlo_get_tdls_link_vdev(vdev); + if (!tdls_link_vdev) { + wlan_vdev_mlme_feat_ext2_cap_set(vdev, + WLAN_VDEV_FEXT2_MLO_STA_TDLS); + return true; + } + + if (tdls_link_vdev && tdls_link_vdev != vdev) { + tdls_debug("tdls vdev has been created on vdev %d", + wlan_vdev_get_id(tdls_link_vdev)); + return false; + } + + return true; +} + +struct wlan_objmgr_vdev * +ucfg_tdls_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ + struct wlan_objmgr_vdev *link_vdev; + + link_vdev = tdls_mlo_get_tdls_link_vdev(vdev); + if (!link_vdev) + return NULL; + + if (wlan_objmgr_vdev_try_get_ref(link_vdev, dbg_id) != + QDF_STATUS_SUCCESS) + return NULL; + + return link_vdev; +} + +void ucfg_tdls_put_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ + wlan_objmgr_vdev_release_ref(vdev, dbg_id); +} + QDF_STATUS ucfg_tdls_psoc_enable(struct wlan_objmgr_psoc *psoc) { QDF_STATUS status; diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 43fd78fbdc..336f1e0281 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -21684,12 +21684,34 @@ static int wlan_hdd_add_key_mlo_vdev(mac_handle_t mac_handle, } } - if (pairwise && link_id == -1) + link_vdev = ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (pairwise && link_id == -1 && !link_vdev) return wlan_hdd_add_key_all_mlo_vdev(mac_handle, vdev, key_index, pairwise, mac_addr, params, link_id, adapter); + if (pairwise && link_id == -1 && link_vdev) { + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + link_adapter = + hdd_get_adapter_by_vdev(hdd_ctx, + wlan_vdev_get_id(link_vdev)); + link_id = wlan_vdev_get_link_id(link_vdev); + if (!link_adapter) { + ucfg_tdls_put_tdls_link_vdev(link_vdev, + WLAN_OSIF_TDLS_ID); + hdd_err("couldn't set tdls key, link_id %d", link_id); + return -EINVAL; + } + + errno = wlan_hdd_add_key_vdev(mac_handle, link_vdev, key_index, + pairwise, mac_addr, params, + link_id, link_adapter); + ucfg_tdls_put_tdls_link_vdev(link_vdev, WLAN_OSIF_TDLS_ID); + + return errno; + } + if (wlan_vdev_get_link_id(adapter->deflink->vdev) == link_id) { hdd_debug("add_key for same vdev: %d", adapter->deflink->vdev_id); @@ -23234,6 +23256,19 @@ int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, } #endif +#ifdef TDLS_MGMT_VERSION5 +static inline +uint8_t wlan_hdd_get_link_id(struct station_parameters *params) +{ + return params->link_sta_params.link_id; +} +#else +static inline +uint8_t wlan_hdd_get_link_id(struct station_parameters *params) +{ + return 255; +} +#endif /** * __wlan_hdd_cfg80211_add_station() - add station * @wiphy: Pointer to wiphy @@ -23253,6 +23288,7 @@ static int __wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); struct hdd_context *hdd_ctx = wiphy_priv(wiphy); u32 mask, set; + uint8_t link_id; hdd_enter(); @@ -23272,24 +23308,15 @@ static int __wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, return -EINVAL; mask = params->sta_flags_mask; - set = params->sta_flags_set; - - hdd_debug("mask 0x%x set 0x%x " QDF_MAC_ADDR_FMT, mask, set, - QDF_MAC_ADDR_REF(mac)); + link_id = wlan_hdd_get_link_id(params); + hdd_debug("mask 0x%x set 0x%x link_id %d " QDF_MAC_ADDR_FMT, mask, set, + link_id, QDF_MAC_ADDR_REF(mac)); if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) { if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { - struct wlan_objmgr_vdev *vdev; - - vdev = hdd_objmgr_get_vdev_by_user(adapter, - WLAN_OSIF_TDLS_ID); - if (vdev) { - status = wlan_cfg80211_tdls_add_peer(vdev, - mac); - hdd_objmgr_put_vdev_by_user(vdev, - WLAN_OSIF_TDLS_ID); - } + status = wlan_cfg80211_tdls_add_peer_mlo(adapter, + mac, link_id); } } #endif diff --git a/core/hdd/src/wlan_hdd_tdls.c b/core/hdd/src/wlan_hdd_tdls.c index 809e462344..ebdf35de1c 100644 --- a/core/hdd/src/wlan_hdd_tdls.c +++ b/core/hdd/src/wlan_hdd_tdls.c @@ -80,6 +80,7 @@ int wlan_hdd_tdls_get_all_peers(struct hdd_adapter *adapter, int len; struct hdd_context *hdd_ctx; struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *link_vdev; int ret; hdd_enter(); @@ -103,7 +104,15 @@ int wlan_hdd_tdls_get_all_peers(struct hdd_adapter *adapter, len = scnprintf(buf, buflen, "\nVDEV is NULL\n"); return len; } - ret = wlan_cfg80211_tdls_get_all_peers(vdev, buf, buflen); + + link_vdev = ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (link_vdev) { + ret = wlan_cfg80211_tdls_get_all_peers(link_vdev, buf, buflen); + ucfg_tdls_put_tdls_link_vdev(link_vdev, WLAN_OSIF_TDLS_ID); + } else { + ret = wlan_cfg80211_tdls_get_all_peers(vdev, buf, buflen); + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); return ret; @@ -467,6 +476,9 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); struct hdd_context *hdd_ctx = wiphy_priv(wiphy); bool tdls_support; +#ifndef TDLS_MGMT_VERSION5 + int link_id = -1; +#endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) #if !(TDLS_MGMT_VERSION2) u32 peer_capability; @@ -498,17 +510,12 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, } if (hdd_ctx->tdls_umac_comp_active) { - struct wlan_objmgr_vdev *vdev; int ret; - vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_TDLS_ID); - if (!vdev) - return -EINVAL; - ret = wlan_cfg80211_tdls_mgmt(vdev, peer, - action_code, dialog_token, - status_code, peer_capability, - buf, len); - hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + ret = wlan_cfg80211_tdls_mgmt_mlo(adapter, peer, + action_code, dialog_token, + status_code, peer_capability, + buf, len, link_id); return ret; } diff --git a/os_if/tdls/inc/wlan_cfg80211_tdls.h b/os_if/tdls/inc/wlan_cfg80211_tdls.h index a0af909dac..1fdeac798b 100644 --- a/os_if/tdls/inc/wlan_cfg80211_tdls.h +++ b/os_if/tdls/inc/wlan_cfg80211_tdls.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -32,6 +32,7 @@ #include #include #include +#include #include #ifdef FEATURE_WLAN_TDLS @@ -110,14 +111,15 @@ QDF_STATUS wlan_cfg80211_tdls_osif_priv_init(struct wlan_objmgr_vdev *vdev); void wlan_cfg80211_tdls_osif_priv_deinit(struct wlan_objmgr_vdev *vdev); /** - * wlan_cfg80211_tdls_add_peer() - process cfg80211 add TDLS peer request - * @vdev: vdev object + * wlan_cfg80211_tdls_add_peer_mlo() - process cfg80211 add TDLS peer request + * @adapter: adapter pointer * @mac: MAC address for TDLS peer + * @link_id: link id * * Return: 0 for success; negative errno otherwise */ -int wlan_cfg80211_tdls_add_peer(struct wlan_objmgr_vdev *vdev, - const uint8_t *mac); +int wlan_cfg80211_tdls_add_peer_mlo(struct hdd_adapter *adapter, + const uint8_t *mac, uint8_t link_id); /** * wlan_cfg80211_tdls_update_peer() - process cfg80211 update TDLS peer request @@ -185,8 +187,9 @@ bool wlan_cfg80211_tdls_is_fw_6ghz_capable(struct wlan_objmgr_vdev *vdev); #endif /** - * wlan_cfg80211_tdls_mgmt() - process TDLS management frames from the supplicant - * @vdev: vdev object + * wlan_cfg80211_tdls_mgmt_mlo() - process TDLS management frames from + * the supplicant + * @adapter: adapter object * @peer: MAC address of the TDLS peer * @action_code: type of TDLS mgmt frame to be sent * @dialog_token: dialog token used in the frame @@ -194,14 +197,15 @@ bool wlan_cfg80211_tdls_is_fw_6ghz_capable(struct wlan_objmgr_vdev *vdev); * @peer_capability: peer capability information * @buf: additional IEs to be included * @len: length of additional Ies + * @link_id: link id * * Return: 0 on success; negative errno otherwise */ -int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_vdev *vdev, - const uint8_t *peer, - uint8_t action_code, uint8_t dialog_token, - uint16_t status_code, uint32_t peer_capability, - const uint8_t *buf, size_t len); +int wlan_cfg80211_tdls_mgmt_mlo(struct hdd_adapter *adapter, + const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len, int link_id); /** * wlan_tdls_antenna_switch() - process TDLS antenna switch diff --git a/os_if/tdls/src/wlan_cfg80211_tdls.c b/os_if/tdls/src/wlan_cfg80211_tdls.c index e0e4318bc4..b9b868c0d9 100644 --- a/os_if/tdls/src/wlan_cfg80211_tdls.c +++ b/os_if/tdls/src/wlan_cfg80211_tdls.c @@ -39,6 +39,8 @@ #include "wlan_tdls_ucfg_api.h" #include "wlan_cm_roam_api.h" #include "wlan_mlo_mgr_sta.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_object_manager.h" static int wlan_cfg80211_tdls_validate_mac_addr(const uint8_t *mac) { @@ -104,8 +106,8 @@ void hdd_notify_tdls_reset_adapter(struct wlan_objmgr_vdev *vdev) ucfg_tdls_notify_reset_adapter(vdev); } -int wlan_cfg80211_tdls_add_peer(struct wlan_objmgr_vdev *vdev, - const uint8_t *mac) +static int wlan_cfg80211_tdls_add_peer(struct wlan_objmgr_vdev *vdev, + const uint8_t *mac) { struct tdls_add_peer_params *add_peer_req; int status; @@ -163,6 +165,42 @@ error: return status; } +int wlan_cfg80211_tdls_add_peer_mlo(struct hdd_adapter *adapter, + const uint8_t *mac, uint8_t link_id) +{ + struct wlan_objmgr_vdev *vdev; + bool is_mlo_vdev; + int status; + + vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_TDLS_ID); + if (!vdev) + return -EINVAL; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + + vdev = wlan_key_get_link_vdev(adapter, WLAN_OSIF_TDLS_ID, + link_id); + if (!vdev) + return -EINVAL; + + if (!ucfg_tdls_link_vdev_is_matching(vdev)) { + wlan_key_put_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + return -EINVAL; + } + + osif_debug("tdls add peer for vdev %d", wlan_vdev_get_id(vdev)); + status = wlan_cfg80211_tdls_add_peer(vdev, mac); + wlan_key_put_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + } else { + status = wlan_cfg80211_tdls_add_peer(vdev, mac); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + } + + return status; +} + static bool is_duplicate_freq(qdf_freq_t *arr, uint8_t index, qdf_freq_t freq) { @@ -623,6 +661,7 @@ int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_vdev *vdev, struct wlan_objmgr_psoc *psoc; bool tdls_11ax_support = false; bool tdls_6g_support = false; + bool is_mlo_vdev; status = wlan_cfg80211_tdls_validate_mac_addr(mac); @@ -632,14 +671,25 @@ int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_vdev *vdev, osif_debug("Update TDLS peer " QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(mac)); - req_info = qdf_mem_malloc(sizeof(*req_info)); - if (!req_info) - return -EINVAL; + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + vdev = ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (!vdev) { + osif_err("no tdls link vdev"); + return -EINVAL; + } + } psoc = wlan_vdev_get_psoc(vdev); if (!psoc) { osif_err_rl("Invalid psoc"); - return -EINVAL; + goto relref; + } + + req_info = qdf_mem_malloc(sizeof(*req_info)); + if (!req_info) { + status = -EINVAL; + goto relref; } tdls_11ax_support = ucfg_tdls_is_fw_11ax_capable(psoc); @@ -682,6 +732,9 @@ int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_vdev *vdev, } error: qdf_mem_free(req_info); +relref: + if (is_mlo_vdev) + ucfg_tdls_put_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); return status; } @@ -759,6 +812,7 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_vdev *vdev, int status; unsigned long rc; enum tdls_command_type cmd; + bool is_mlo_vdev; status = wlan_cfg80211_tdls_validate_mac_addr(peer); @@ -771,6 +825,15 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_vdev *vdev, return -ENOTSUPP; } + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + vdev = ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (!vdev) { + osif_err("no tdls link vdev"); + return -EINVAL; + } + } + osif_debug("%s start", tdls_oper_to_str(oper)); cmd = tdls_oper_to_cmd(oper); switch (oper) { @@ -786,6 +849,9 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_vdev *vdev, } break; case NL80211_TDLS_DISABLE_LINK: + wlan_vdev_mlme_feat_ext2_cap_clear(vdev, + WLAN_VDEV_FEXT2_MLO_STA_TDLS); + osif_priv = wlan_vdev_get_ospriv(vdev); if (!osif_priv || !osif_priv->osif_tdls) { @@ -816,6 +882,8 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_vdev *vdev, } error: + if (is_mlo_vdev) + ucfg_tdls_put_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); return status; } @@ -844,7 +912,8 @@ void wlan_cfg80211_tdls_rx_callback(void *user_data, assoc_vdev = vdev; opmode = wlan_vdev_mlme_get_opmode(vdev); - if (opmode == QDF_STA_MODE && wlan_vdev_mlme_is_mlo_vdev(vdev)) { + if ((opmode == QDF_STA_MODE || opmode == QDF_TDLS_MODE) && + wlan_vdev_mlme_is_mlo_vdev(vdev)) { assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev); if (!assoc_vdev) { osif_err("assoc vdev is null"); @@ -1000,11 +1069,12 @@ bool wlan_cfg80211_tdls_is_fw_6ghz_capable(struct wlan_objmgr_vdev *vdev) } #endif -int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_vdev *vdev, - const uint8_t *peer_mac, - uint8_t action_code, uint8_t dialog_token, - uint16_t status_code, uint32_t peer_capability, - const uint8_t *buf, size_t len) +static int +wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_vdev *vdev, + const uint8_t *peer_mac, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len, int link_id) { struct tdls_action_frame_request mgmt_req; struct vdev_osif_priv *osif_priv; @@ -1060,6 +1130,8 @@ int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_vdev *vdev, mgmt_req.tdls_mgmt.peer_capability = peer_capability; mgmt_req.tdls_mgmt.status_code = mgmt_req.chk_frame.status_code; + mgmt_req.link_active = false; + mgmt_req.link_id = link_id; /*populate the additional IE's */ mgmt_req.cmd_buf = buf; mgmt_req.len = len; @@ -1111,6 +1183,88 @@ error_mgmt_req: return status; } +int +wlan_cfg80211_tdls_mgmt_mlo(struct hdd_adapter *adapter, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len, int link_id) +{ + struct wlan_objmgr_vdev *tdls_link_vdev = NULL; + struct wlan_objmgr_vdev *mlo_vdev = NULL; + struct wlan_objmgr_vdev *vdev; + bool is_mlo_vdev; + bool link_id_vdev = false; + bool dis_req_more = false; + uint8_t i; + int ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_TDLS_ID); + if (!vdev) + return -EINVAL; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + tdls_link_vdev = + ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (!tdls_link_vdev) { + if (action_code == TDLS_DISCOVERY_RESPONSE) { + hdd_objmgr_put_vdev_by_user(vdev, + WLAN_OSIF_TDLS_ID); + if (link_id < 0) { + osif_err("link id is invalid"); + return -EINVAL; + } + /* Get the candidate vdev per link id */ + link_id_vdev = true; + vdev = wlan_key_get_link_vdev(adapter, + WLAN_OSIF_TDLS_ID, + link_id); + } else if (action_code == TDLS_DISCOVERY_REQUEST) { + if (ucfg_tdls_discovery_on_going(vdev)) { + osif_err("discovery request is going"); + hdd_objmgr_put_vdev_by_user(vdev, + WLAN_OSIF_TDLS_ID); + return -EAGAIN; + } + dis_req_more = true; + } + } else { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + vdev = tdls_link_vdev; + } + } + + if (dis_req_more) { + /* it needs to send discovery request on each vdev */ + for (i = 0 ; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + mlo_vdev = ucfg_tdls_get_mlo_vdev(vdev, i, + WLAN_OSIF_TDLS_ID); + if (!mlo_vdev) { + osif_err("mlo vdev is NULL"); + continue; + } + ret = wlan_cfg80211_tdls_mgmt(mlo_vdev, peer, + action_code, + dialog_token, status_code, + peer_capability, buf, len, + link_id); + ucfg_tdls_release_mlo_vdev(mlo_vdev, WLAN_OSIF_TDLS_ID); + } + } else { + ret = wlan_cfg80211_tdls_mgmt(vdev, peer, + action_code, dialog_token, + status_code, peer_capability, + buf, len, link_id); + } + + if (vdev && link_id_vdev) + wlan_key_put_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + else if (!tdls_link_vdev) + ucfg_tdls_put_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + + return ret; +} + int wlan_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev, uint32_t mode) { struct vdev_osif_priv *osif_priv;