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