diff --git a/components/tdls/core/src/wlan_tdls_cmds_process.c b/components/tdls/core/src/wlan_tdls_cmds_process.c index d3acee2f82..810c1a9e12 100644 --- a/components/tdls/core/src/wlan_tdls_cmds_process.c +++ b/components/tdls/core/src/wlan_tdls_cmds_process.c @@ -1661,6 +1661,48 @@ QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp) return QDF_STATUS_E_INVAL; } +static void tdls_process_unforce_link_mode(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_peer *peer; + qdf_list_t *head; + qdf_list_node_t *p_node; + QDF_STATUS status; + bool unforce = true; + int i; + + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_vdev) + return; + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev->peer_list[i]; + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + + tdls_debug("Peer: " QDF_MAC_ADDR_FMT "link status %d, vdev id %d", + QDF_MAC_ADDR_REF(peer->peer_mac.bytes), + peer->link_status, wlan_vdev_get_id(vdev)); + + if (peer->link_status == TDLS_LINK_CONNECTED || + peer->link_status == TDLS_LINK_CONNECTING) { + unforce = false; + goto unforce_exit; + } + + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + +unforce_exit: + if (unforce) { + tdls_debug("try to set vdev %d to unforce", + wlan_vdev_get_id(vdev)); + tdls_set_link_unforce(vdev); + } +} + QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp) { uint8_t sta_idx, id; @@ -1734,6 +1776,8 @@ QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp) TDLS_LINK_DROPPED_BY_REMOTE); } + tdls_process_unforce_link_mode(vdev); + cmddone: tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_DEL_PEER); wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); diff --git a/components/tdls/core/src/wlan_tdls_ct.c b/components/tdls/core/src/wlan_tdls_ct.c index 84d820b0b6..0e17c31083 100644 --- a/components/tdls/core/src/wlan_tdls_ct.c +++ b/components/tdls/core/src/wlan_tdls_ct.c @@ -97,6 +97,7 @@ void tdls_discovery_timeout_peer_cb(void *user_data) struct wlan_objmgr_vdev *tdls_link_vdev; struct tdls_rx_mgmt_frame *rx_mgmt; uint8_t *mac; + bool unforce = true; if (!user_data) { tdls_err("discovery time out data is null"); @@ -163,6 +164,15 @@ void tdls_discovery_timeout_peer_cb(void *user_data) while (QDF_IS_STATUS_SUCCESS(status)) { peer = qdf_container_of(p_node, struct tdls_peer, node); + + tdls_debug("Peer: " QDF_MAC_ADDR_FMT "link status %d, vdev id %d", + QDF_MAC_ADDR_REF(peer->peer_mac.bytes), + peer->link_status, wlan_vdev_get_id(vdev)); + + if (peer->link_status != TDLS_LINK_DISCOVERING && + peer->link_status != TDLS_LINK_IDLE) + unforce = false; + if (TDLS_LINK_DISCOVERING != peer->link_status) { status = qdf_list_peek_next(head, p_node, &p_node); @@ -176,6 +186,12 @@ void tdls_discovery_timeout_peer_cb(void *user_data) } } + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && unforce) { + tdls_debug("try to set vdev %d to unforce", + wlan_vdev_get_id(vdev)); + tdls_set_link_unforce(vdev); + } + tdls_vdev->discovery_sent_cnt = 0; /* add tdls power save prohibited */ @@ -1458,6 +1474,14 @@ void tdls_disable_offchan_and_teardown_links( QDF_STATUS status; uint8_t vdev_id; bool tdls_in_progress = false; + bool is_mlo_vdev; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + tdls_debug("try to set vdev %d to unforce", + wlan_vdev_get_id(vdev)); + tdls_set_link_unforce(vdev); + } status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc); if (QDF_STATUS_SUCCESS != status) { diff --git a/components/tdls/core/src/wlan_tdls_main.c b/components/tdls/core/src/wlan_tdls_main.c index 091302edc9..cd9838c539 100644 --- a/components/tdls/core/src/wlan_tdls_main.c +++ b/components/tdls/core/src/wlan_tdls_main.c @@ -80,6 +80,7 @@ static char *tdls_get_cmd_type_str(enum tdls_command_type cmd_type) CASE_RETURN_STRING(TDLS_CMD_SET_SECOFFCHANOFFSET); CASE_RETURN_STRING(TDLS_DELETE_ALL_PEERS_INDICATION); CASE_RETURN_STRING(TDLS_CMD_START_BSS); + CASE_RETURN_STRING(TDLS_CMD_SET_LINK_UNFORCE); default: return "Invalid TDLS command"; } @@ -582,6 +583,17 @@ QDF_STATUS tdls_handle_start_bss(struct wlan_objmgr_psoc *psoc) } #endif +static void tdls_handle_link_unforce(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_action_frame_request req = {0}; + + req.vdev = vdev; + req.tdls_mgmt.frame_type = TDLS_MAX_ACTION_CODE; + + tdls_debug("set vdev %d unforce", wlan_vdev_get_id(vdev)); + tdls_set_link_mode(&req); +} + QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg) { QDF_STATUS status = QDF_STATUS_SUCCESS; @@ -668,6 +680,9 @@ QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg) case TDLS_CMD_START_BSS: tdls_handle_start_bss(msg->bodyptr); break; + case TDLS_CMD_SET_LINK_UNFORCE: + tdls_handle_link_unforce(msg->bodyptr); + break; default: break; } @@ -2039,6 +2054,21 @@ void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev, tdls_post_scan_done_msg(tdls_soc); } +void tdls_set_link_unforce(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_SET_LINK_UNFORCE; + msg.bodyptr = vdev; + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) + tdls_err("failed to set tdls link mode"); +} + /** * tdls_check_peer_buf_capable() - Check buffer sta capable of tdls peers * @tdls_vdev: TDLS vdev object diff --git a/components/tdls/core/src/wlan_tdls_main.h b/components/tdls/core/src/wlan_tdls_main.h index 73f0caaf74..1313b5ff60 100644 --- a/components/tdls/core/src/wlan_tdls_main.h +++ b/components/tdls/core/src/wlan_tdls_main.h @@ -811,6 +811,14 @@ void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev, struct scan_event *event, void *arg); +/** + * tdls_set_link_unforce() - set link unforce + * @vdev: vdev object + * + * Return: void + */ +void tdls_set_link_unforce(struct wlan_objmgr_vdev *vdev); + /** * tdls_scan_callback() - callback for TDLS scan operation * @tdls_soc: tdls soc pvt object diff --git a/components/tdls/core/src/wlan_tdls_mgmt.c b/components/tdls/core/src/wlan_tdls_mgmt.c index b5961e62ee..16a63e50a3 100644 --- a/components/tdls/core/src/wlan_tdls_mgmt.c +++ b/components/tdls/core/src/wlan_tdls_mgmt.c @@ -87,6 +87,26 @@ tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev) return wlan_mlo_get_tdls_link_vdev(vdev); } +void +tdls_set_remain_links_unforce(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_objmgr_vdev *mlo_vdev; + int i; + + /* TDLS link is selected, unforce link for other vdevs */ + mlo_dev_ctx = vdev->mlo_dev_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!mlo_vdev || mlo_vdev == vdev) + continue; + + tdls_debug("try to set vdev %d to unforce", + wlan_vdev_get_id(mlo_vdev)); + tdls_set_link_unforce(mlo_vdev); + } +} + QDF_STATUS tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev) { @@ -425,6 +445,11 @@ tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev) return NULL; } +void +tdls_set_remain_links_unforce(struct wlan_objmgr_vdev *vdev) +{ +} + QDF_STATUS tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev) { @@ -852,7 +877,7 @@ tdls_send_mgmt_serialize_callback(struct wlan_serialization_command *cmd, } #ifdef WLAN_FEATURE_11BE_MLO -static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) +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; @@ -865,10 +890,6 @@ static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) 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"); @@ -877,6 +898,10 @@ static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) if (req->tdls_mgmt.frame_type == TDLS_DISCOVERY_RESPONSE || req->tdls_mgmt.frame_type == TDLS_DISCOVERY_REQUEST) { + mlo_tdls_vdev = wlan_mlo_get_tdls_link_vdev(req->vdev); + if (mlo_tdls_vdev) + return status; + mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev); vdev_count = 1; @@ -886,12 +911,20 @@ static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) vdev_count, mlo_vdev_lst); if (status == QDF_STATUS_SUCCESS) req->link_active = true; + } else if (req->tdls_mgmt.frame_type == TDLS_MAX_ACTION_CODE) { + 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_NO_FORCE, + vdev_count, mlo_vdev_lst); } return status; } #else -static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) +QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) { return QDF_STATUS_SUCCESS; } diff --git a/components/tdls/core/src/wlan_tdls_mgmt.h b/components/tdls/core/src/wlan_tdls_mgmt.h index 72053a00f5..5d29b60d13 100644 --- a/components/tdls/core/src/wlan_tdls_mgmt.h +++ b/components/tdls/core/src/wlan_tdls_mgmt.h @@ -99,6 +99,14 @@ tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev); struct wlan_objmgr_vdev * tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev); +/** + * tdls_set_remain_links_unforce() - unforce links + * @vdev: vdev object + * + * Return: void + */ +void tdls_set_remain_links_unforce(struct wlan_objmgr_vdev *vdev); + /** * tdls_mgmt_rx_ops() - register or unregister rx callback * @psoc: psoc object @@ -150,5 +158,13 @@ tdls_process_mlo_choice_tdls_vdev(struct wlan_objmgr_vdev *vdev); * Return: void */ void tdls_set_no_force_vdev(struct wlan_objmgr_vdev *vdev, bool flag); + +/** + * tdls_set_link_mode() - force active or unfore link for MLO case + * @req: the pointer of tdls_action_frame_request + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req); #endif diff --git a/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h b/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h index ab7b8db340..6f3fcad204 100644 --- a/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h +++ b/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h @@ -241,6 +241,7 @@ enum tdls_feature_mode { * @TDLS_CMD_SET_SECOFFCHANOFFSET: tdls secondary offchannel offset * @TDLS_DELETE_ALL_PEERS_INDICATION: tdls delete all peers indication * @TDLS_CMD_START_BSS: SAP start indication to tdls module + * @TDLS_CMD_SET_LINK_UNFORCE: tdls to unforce link for MLO case */ enum tdls_command_type { TDLS_CMD_TX_ACTION = 1, @@ -267,7 +268,8 @@ enum tdls_command_type { TDLS_CMD_SET_OFFCHANMODE, TDLS_CMD_SET_SECOFFCHANOFFSET, TDLS_DELETE_ALL_PEERS_INDICATION, - TDLS_CMD_START_BSS + TDLS_CMD_START_BSS, + TDLS_CMD_SET_LINK_UNFORCE }; /** diff --git a/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c index 87471e0d67..4194c77b37 100644 --- a/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c +++ b/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -528,6 +528,7 @@ bool ucfg_tdls_link_vdev_is_matching(struct wlan_objmgr_vdev *vdev) if (!tdls_link_vdev) { wlan_vdev_mlme_feat_ext2_cap_set(vdev, WLAN_VDEV_FEXT2_MLO_STA_TDLS); + tdls_set_remain_links_unforce(vdev); return true; }