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
This commit is contained in:
Paul Zhang
2023-04-03 13:58:22 +08:00
committed by Madan Koyyalamudi
parent 7d518a4ab9
commit 0752365a21
9 changed files with 429 additions and 55 deletions

View File

@@ -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;
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);

View File

@@ -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
*/

View File

@@ -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;
};

View File

@@ -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)

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}
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,
ret = wlan_cfg80211_tdls_mgmt_mlo(adapter, peer,
action_code, dialog_token,
status_code, peer_capability,
buf, len);
hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID);
buf, len, link_id);
return ret;
}

View File

@@ -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 <wlan_tdls_public_structs.h>
#include <qdf_list.h>
#include <qdf_types.h>
#include <wlan_hdd_main.h>
#include <wlan_tdls_ucfg_api.h>
#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,
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);
const uint8_t *buf, size_t len, int link_id);
/**
* wlan_tdls_antenna_switch() - process TDLS antenna switch

View File

@@ -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,7 +106,7 @@ 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,
static int wlan_cfg80211_tdls_add_peer(struct wlan_objmgr_vdev *vdev,
const uint8_t *mac)
{
struct tdls_add_peer_params *add_peer_req;
@@ -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)
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,
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)
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;