diff --git a/target_if/core/src/target_if_main.c b/target_if/core/src/target_if_main.c index 80e9a667b8..efd282dd8c 100644 --- a/target_if/core/src/target_if_main.c +++ b/target_if/core/src/target_if_main.c @@ -211,6 +211,10 @@ QDF_STATUS target_if_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) /* Converged UMAC components to register P2P TX-ops */ target_if_p2p_register_tx_ops(tx_ops); #endif +#ifdef CONVERGED_TDLS_ENABLE + target_if_tdls_register_tx_ops(tx_ops); +#endif + return QDF_STATUS_SUCCESS; } diff --git a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h index d676ceec2e..2d20618848 100644 --- a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h +++ b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h @@ -644,6 +644,22 @@ struct wlan_objmgr_pdev *wlan_objmgr_get_pdev_by_macaddr_no_state( struct wlan_objmgr_psoc *psoc, uint8_t *macaddr, wlan_objmgr_ref_dbgid dbg_id); +/** + * wlan_objmgr_get_vdev_by_opmode_from_psoc() - retrieve vdev by opmode + * @psoc: PSOC object + * @opmode: vdev operating mode + * @dbg_id: id of the caller + * + * API to find vdev object pointer by vdev operating mode from psoc + * + * Return: vdev pointer + * NULL on FAILURE + */ +struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_opmode_from_psoc( + struct wlan_objmgr_psoc *psoc, + enum tQDF_ADAPTER_MODE opmode, + wlan_objmgr_ref_dbgid dbg_id); + /** * wlan_objmgr_get_vdev_by_id_from_psoc() - retrieve vdev by id * @psoc: PSOC object diff --git a/umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c b/umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c index 4e75286cd8..c7a060c3e9 100644 --- a/umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c +++ b/umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c @@ -858,6 +858,40 @@ QDF_STATUS wlan_objmgr_psoc_vdev_detach(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } +struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_opmode_from_psoc( + struct wlan_objmgr_psoc *psoc, + enum tQDF_ADAPTER_MODE opmode, + wlan_objmgr_ref_dbgid dbg_id) +{ + struct wlan_objmgr_vdev *vdev; + int vdev_cnt = 0; + + /* if PSOC is NULL, return */ + if (psoc == NULL) + return NULL; + + wlan_psoc_obj_lock(psoc); + + /* retrieve vdev pointer from vdev list */ + while (vdev_cnt < WLAN_UMAC_PSOC_MAX_VDEVS) { + vdev = psoc->soc_objmgr.wlan_vdev_list[vdev_cnt]; + vdev_cnt++; + if (vdev == NULL) + continue; + wlan_vdev_obj_lock(vdev); + if (vdev->vdev_mlme.vdev_opmode == opmode) { + wlan_vdev_obj_unlock(vdev); + if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) != + QDF_STATUS_SUCCESS) + vdev = NULL; + break; + } + wlan_vdev_obj_unlock(vdev); + } + wlan_psoc_obj_unlock(psoc); + + return vdev; +} struct wlan_objmgr_vdev *wlan_objmgr_get_vdev_by_id_from_psoc( struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, diff --git a/umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h b/umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h index 3eb4a58158..fd61826656 100644 --- a/umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h +++ b/umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h @@ -796,8 +796,8 @@ struct policy_mgr_hdd_cbacks { * @check_is_tdls_allowed: check if tdls allowed or not */ struct policy_mgr_tdls_cbacks { - void (*set_tdls_ct_mode)(struct wlan_objmgr_psoc *psoc); - bool (*check_is_tdls_allowed)(enum tQDF_ADAPTER_MODE device_mode); + void (*tdls_notify_increment_session)(struct wlan_objmgr_psoc *psoc); + void (*tdls_notify_decrement_session)(struct wlan_objmgr_psoc *psoc); }; /** diff --git a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c index 771f7e3744..46cb046618 100644 --- a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c +++ b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c @@ -1114,9 +1114,10 @@ void policy_mgr_incr_active_session(struct wlan_objmgr_psoc *psoc, qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); } - /* set tdls connection tracker state */ - if (pm_ctx->tdls_cbacks.set_tdls_ct_mode) - pm_ctx->tdls_cbacks.set_tdls_ct_mode(psoc); + /* Notify tdls */ + if (pm_ctx->tdls_cbacks.tdls_notify_increment_session) + pm_ctx->tdls_cbacks.tdls_notify_increment_session(psoc); + policy_mgr_dump_current_concurrency(psoc); qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); @@ -1152,9 +1153,9 @@ void policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc, policy_mgr_decr_connection_count(psoc, session_id); - /* set tdls connection tracker state */ - if (pm_ctx->tdls_cbacks.set_tdls_ct_mode) - pm_ctx->tdls_cbacks.set_tdls_ct_mode(psoc); + /* Notify tdls */ + if (pm_ctx->tdls_cbacks.tdls_notify_decrement_session) + pm_ctx->tdls_cbacks.tdls_notify_decrement_session(psoc); policy_mgr_dump_current_concurrency(psoc); } diff --git a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c index 9c2fde0ae2..dcf5d882f3 100644 --- a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c +++ b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c @@ -605,10 +605,10 @@ QDF_STATUS policy_mgr_register_tdls_cb(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_E_FAILURE; } - pm_ctx->tdls_cbacks.check_is_tdls_allowed = - tdls_cbacks->check_is_tdls_allowed; - pm_ctx->tdls_cbacks.set_tdls_ct_mode = - tdls_cbacks->set_tdls_ct_mode; + pm_ctx->tdls_cbacks.tdls_notify_increment_session = + tdls_cbacks->tdls_notify_increment_session; + pm_ctx->tdls_cbacks.tdls_notify_decrement_session = + tdls_cbacks->tdls_notify_decrement_session; return QDF_STATUS_SUCCESS; } diff --git a/umac/tdls/core/src/wlan_tdls_main.c b/umac/tdls/core/src/wlan_tdls_main.c index b4b28c0b83..6faeb5dd92 100644 --- a/umac/tdls/core/src/wlan_tdls_main.c +++ b/umac/tdls/core/src/wlan_tdls_main.c @@ -27,6 +27,10 @@ #include "wlan_tdls_peer.h" #include "wlan_tdls_ct.h" #include "wlan_tdls_mgmt.h" +#include "wlan_tdls_tgt_api.h" +#include "wlan_policy_mgr_public_struct.h" +#include "wlan_policy_mgr_api.h" + QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, void *arg_list) @@ -387,3 +391,665 @@ QDF_STATUS tdls_get_vdev_objects(struct wlan_objmgr_vdev *vdev, return QDF_STATUS_SUCCESS; } + +/** + * tdls_state_param_setting_dump() - print tdls state & parameters to send to fw + * @info: tdls setting to be sent to fw + * + * Return: void + */ +static void tdls_state_param_setting_dump(struct tdls_info *info) +{ + if (!info) + return; + + tdls_debug("Setting tdls state and param in fw: vdev_id: %d, tdls_state: %d, notification_interval_ms: %d, tx_discovery_threshold: %d, tx_teardown_threshold: %d, rssi_teardown_threshold: %d, rssi_delta: %d, tdls_options: 0x%x, peer_traffic_ind_window: %d, peer_traffic_response_timeout: %d, puapsd_mask: 0x%x, puapsd_inactivity_time: %d, puapsd_rx_frame_threshold: %d, teardown_notification_ms: %d, tdls_peer_kickout_threshold: %d", + info->vdev_id, + info->tdls_state, + info->notification_interval_ms, + info->tx_discovery_threshold, + info->tx_teardown_threshold, + info->rssi_teardown_threshold, + info->rssi_delta, + info->tdls_options, + info->peer_traffic_ind_window, + info->peer_traffic_response_timeout, + info->puapsd_mask, + info->puapsd_inactivity_time, + info->puapsd_rx_frame_threshold, + info->teardown_notification_ms, + info->tdls_peer_kickout_threshold); + +} + +/** + * tdls_update_fw_tdls_state() - update tdls status info + * @tdls_soc_obj: TDLS soc object + * @tdls_info_to_fw: TDLS state info to update in f/w. + * + * send message to WMA to set TDLS state in f/w + * + * Return: QDF_STATUS. + */ +static +QDF_STATUS tdls_update_fw_tdls_state(struct tdls_soc_priv_obj *tdls_soc_obj, + struct tdls_info *tdls_info_to_fw) +{ + QDF_STATUS status; + + /* wmi_unified_update_fw_tdls_state_cmd() will be called directly */ + status = tgt_tdls_set_fw_state(tdls_soc_obj->soc, tdls_info_to_fw); + + if (!QDF_IS_STATUS_SUCCESS(status)) + status = QDF_STATUS_E_FAILURE; + + return status; +} + +bool tdls_check_is_tdls_allowed(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + bool state = false; + + if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(vdev, + WLAN_TDLS_NB_ID)) + return state; + + if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj, + &tdls_soc_obj)) { + wlan_objmgr_vdev_release_ref(vdev, + WLAN_TDLS_NB_ID); + return state; + } + + if (policy_mgr_get_connection_count(tdls_soc_obj->soc) == 1) + state = true; + else + tdls_warn("Concurrent sessions are running or TDLS disabled"); + /* If any concurrency is detected */ + /* print session information */ + wlan_objmgr_vdev_release_ref(vdev, + WLAN_TDLS_NB_ID); + return state; +} + +/** + * cds_set_tdls_ct_mode() - Set the tdls connection tracker mode + * @hdd_ctx: hdd context + * + * This routine is called to set the tdls connection tracker operation status + * + * Return: NONE + */ +void tdls_set_ct_mode(struct wlan_objmgr_psoc *psoc) +{ + bool state = false; + struct tdls_soc_priv_obj *tdls_soc_obj; + + tdls_soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (NULL == tdls_soc_obj) + return; + + /* If any concurrency is detected, skip tdls pkt tracker */ + if (policy_mgr_get_connection_count(psoc) > 1) { + state = false; + goto set_state; + } + + if (TDLS_SUPPORT_DISABLED == tdls_soc_obj->tdls_current_mode || + TDLS_SUPPORT_SUSPENDED == tdls_soc_obj->tdls_current_mode || + !TDLS_IS_IMPLICIT_TRIG_ENABLED( + tdls_soc_obj->tdls_configs.tdls_feature_flags)) { + state = false; + goto set_state; + } else if (policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, + NULL) == 1) { + state = true; + } else if (policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_CLIENT_MODE, + NULL) == 1){ + state = true; + } else { + state = false; + goto set_state; + } + + /* In case of TDLS external control, peer should be added + * by the user space to start connection tracker. + */ + if (TDLS_IS_EXTERNAL_CONTROL_ENABLED( + tdls_soc_obj->tdls_configs.tdls_feature_flags)) { + if (tdls_soc_obj->tdls_external_peer_count) + state = true; + else + state = false; + } + +set_state: + tdls_soc_obj->enable_tdls_connection_tracker = state; + + tdls_notice("enable_tdls_connection_tracker %d", + tdls_soc_obj->enable_tdls_connection_tracker); +} + +QDF_STATUS +tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc) +{ + if (!psoc) { + tdls_err("psoc: %p", psoc); + return QDF_STATUS_E_NULL_VALUE; + } + tdls_debug("enter "); + tdls_set_ct_mode(psoc); + tdls_debug("exit "); + return QDF_STATUS_SUCCESS; +} + +/** + * tdls_get_vdev() - Get tdls specific vdev object manager + * @psoc: wlan psoc object manager + * @dbg_id: debug id + * + * If TDLS possible, return the corresponding vdev + * to enable TDLS in the system. + * + * Return: vdev manager pointer or NULL. + */ +struct wlan_objmgr_vdev *tdls_get_vdev(struct wlan_objmgr_psoc *psoc, + wlan_objmgr_ref_dbgid dbg_id) +{ + if (policy_mgr_get_connection_count(psoc) > 1) + return NULL; + if (policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, + NULL) == 1) + return wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, + QDF_STA_MODE, + dbg_id); + if (policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_CLIENT_MODE, + NULL) == 1) + return wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, + QDF_P2P_CLIENT_MODE, + dbg_id); + return NULL; +} + +/** + * tdls_process_session_update() - update session count information + * @psoc: soc object + * @notification: TDLS os if notification + * + * update the session information in connection tracker + * + * Return: None + */ +static void tdls_process_session_update(struct wlan_objmgr_psoc *psoc, + enum tdls_command_type cmd_type) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + msg.bodyptr = psoc; + msg.callback = tdls_process_cmd; + msg.type = (uint16_t)cmd_type; + + status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) + tdls_alert("message post failed "); +} + +void tdls_notify_increment_session(struct wlan_objmgr_psoc *psoc) +{ + tdls_process_session_update(psoc, TDLS_CMD_SESSION_INCREMENT); +} + +void tdls_notify_decrement_session(struct wlan_objmgr_psoc *psoc) +{ + tdls_process_session_update(psoc, TDLS_CMD_SESSION_DECREMENT); +} + +/** + * tdls_send_update_to_fw - update tdls status info + * @tdls_vdev_obj: tdls vdev private object. + * @tdls_prohibited: indicates whether tdls is prohibited. + * @tdls_chan_swit_prohibited: indicates whether tdls channel switch + * is prohibited. + * @sta_connect_event: indicate sta connect or disconnect event + * @session_id: session id + * + * Normally an AP does not influence TDLS connection between STAs + * associated to it. But AP may set bits for TDLS Prohibited or + * TDLS Channel Switch Prohibited in Extended Capability IE in + * Assoc/Re-assoc response to STA. So after STA is connected to + * an AP, call this function to update TDLS status as per those + * bits set in Ext Cap IE in received Assoc/Re-assoc response + * from AP. + * + * Return: None. + */ +static void tdls_send_update_to_fw(struct tdls_vdev_priv_obj *tdls_vdev_obj, + struct tdls_soc_priv_obj *tdls_soc_obj, + bool tdls_prohibited, + bool tdls_chan_swit_prohibited, + bool sta_connect_event, + uint8_t session_id) +{ + struct tdls_info *tdls_info_to_fw; + struct tdls_config_params *threshold_params; + uint32_t tdls_feature_flags; + QDF_STATUS status; + + + /* If TDLS support is disabled then no need to update target */ + if (tdls_soc_obj->tdls_current_mode <= TDLS_SUPPORT_SUSPENDED) { + tdls_err("TDLS not enabled or suspended"); + return; + } + + if (tdls_soc_obj->set_state_info.set_state_cnt == 0 && + !sta_connect_event) { + return; + } + + tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags; + + /* If AP or caller indicated TDLS Prohibited then disable tdls mode */ + if (tdls_prohibited) { + tdls_soc_obj->tdls_current_mode = TDLS_SUPPORT_DISABLED; + } else { + tdls_debug("TDLS feature flags from ini %d ", + tdls_feature_flags); + if (!TDLS_IS_IMPLICIT_TRIG_ENABLED(tdls_feature_flags)) + tdls_soc_obj->tdls_current_mode = + TDLS_SUPPORT_EXP_TRIG_ONLY; + else if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(tdls_feature_flags)) + tdls_soc_obj->tdls_current_mode = + TDLS_SUPPORT_EXT_CONTROL; + else + tdls_soc_obj->tdls_current_mode = + TDLS_SUPPORT_IMP_MODE; + } + + tdls_info_to_fw = qdf_mem_malloc(sizeof(struct tdls_info)); + + if (!tdls_info_to_fw) { + tdls_err("memory allocation failed for tdlsParams"); + QDF_ASSERT(0); + return; + } + + threshold_params = &tdls_vdev_obj->threshold_config; + + tdls_info_to_fw->notification_interval_ms = + threshold_params->tx_period_t; + tdls_info_to_fw->tx_discovery_threshold = + threshold_params->tx_packet_n; + tdls_info_to_fw->tx_teardown_threshold = + threshold_params->idle_packet_n; + tdls_info_to_fw->rssi_teardown_threshold = + threshold_params->rssi_teardown_threshold; + tdls_info_to_fw->rssi_delta = threshold_params->rssi_delta; + + if (tdls_soc_obj->set_state_info.set_state_cnt == 1 && + sta_connect_event) { + tdls_warn("Concurrency not allowed in TDLS! set state cnt %d", + tdls_soc_obj->set_state_info.set_state_cnt); + /* disable off channel and teardown links */ + /* Go through the peer list and delete them */ + tdls_soc_obj->tdls_current_mode = TDLS_SUPPORT_DISABLED; + tdls_info_to_fw->vdev_id = tdls_soc_obj->set_state_info.vdev_id; + } else { + tdls_info_to_fw->vdev_id = session_id; + } + + tdls_info_to_fw->tdls_state = tdls_soc_obj->tdls_current_mode; + tdls_info_to_fw->tdls_options = 0; + + /* Do not enable TDLS offchannel, if AP prohibited TDLS + * channel switch + */ + if (TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) && + (!tdls_chan_swit_prohibited)) + tdls_info_to_fw->tdls_options = ENA_TDLS_OFFCHAN; + + if (TDLS_IS_BUFFER_STA_ENABLED(tdls_feature_flags)) + tdls_info_to_fw->tdls_options |= ENA_TDLS_BUFFER_STA; + if (TDLS_IS_SLEEP_STA_ENABLED(tdls_feature_flags)) + tdls_info_to_fw->tdls_options |= ENA_TDLS_SLEEP_STA; + + + tdls_info_to_fw->peer_traffic_ind_window = + tdls_soc_obj->tdls_configs.tdls_uapsd_pti_window; + tdls_info_to_fw->peer_traffic_response_timeout = + tdls_soc_obj->tdls_configs.tdls_uapsd_ptr_timeout; + tdls_info_to_fw->puapsd_mask = + tdls_soc_obj->tdls_configs.tdls_uapsd_mask; + tdls_info_to_fw->puapsd_inactivity_time = + tdls_soc_obj->tdls_configs.tdls_uapsd_inactivity_time; + tdls_info_to_fw->puapsd_rx_frame_threshold = + tdls_soc_obj->tdls_configs.tdls_rx_pkt_threshold; + tdls_info_to_fw->teardown_notification_ms = + tdls_soc_obj->tdls_configs.tdls_idle_timeout; + tdls_info_to_fw->tdls_peer_kickout_threshold = + tdls_soc_obj->tdls_configs.tdls_peer_kickout_threshold; + + tdls_state_param_setting_dump(tdls_info_to_fw); + + status = tdls_update_fw_tdls_state(tdls_soc_obj, tdls_info_to_fw); + if (QDF_STATUS_SUCCESS != status) { + qdf_mem_free(tdls_info_to_fw); + goto done; + } + + if (sta_connect_event) { + tdls_soc_obj->set_state_info.set_state_cnt++; + tdls_soc_obj->set_state_info.vdev_id = session_id; + } else { + tdls_soc_obj->set_state_info.set_state_cnt--; + } + + tdls_debug("TDLS Set state cnt %d", + tdls_soc_obj->set_state_info.set_state_cnt); + + if (tdls_soc_obj->set_state_info.set_state_cnt == 1) + /* register callbacks with tx/rx mgmt */ + tdls_mgmt_rx_ops(tdls_soc_obj->soc, true); + else + /* deregister callbacks with tx/rx mgmt */ + tdls_mgmt_rx_ops(tdls_soc_obj->soc, false); + +done: + tdls_process_session_update(tdls_soc_obj->soc, + TDLS_CMD_SESSION_INCREMENT); + return; +} + +static QDF_STATUS +tdls_process_sta_connect(struct tdls_sta_notify_params *notify) +{ + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + + if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(notify->vdev, + &tdls_vdev_obj, + &tdls_soc_obj)) + return QDF_STATUS_E_INVAL; + + + tdls_debug("Check and update TDLS state"); + + /* Association event */ + if (!tdls_soc_obj->tdls_disable_in_progress) { + tdls_send_update_to_fw(tdls_vdev_obj, + tdls_soc_obj, + notify->tdls_prohibited, + notify->tdls_chan_swit_prohibited, + true, + notify->session_id); + } + + /* check and set the connection tracker */ + tdls_set_ct_mode(tdls_soc_obj->soc); + if (tdls_soc_obj->enable_tdls_connection_tracker) + tdls_implicit_enable(tdls_vdev_obj); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify) +{ + QDF_STATUS status; + + if (!notify || !notify->vdev) + return QDF_STATUS_E_INVAL; + + if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(notify->vdev, + WLAN_TDLS_NB_ID)) + return QDF_STATUS_E_INVAL; + + status = tdls_process_sta_connect(notify); + + wlan_objmgr_vdev_release_ref(notify->vdev, + WLAN_TDLS_NB_ID); + qdf_mem_free(notify); + return status; +} + +static QDF_STATUS +tdls_process_sta_disconnect(struct tdls_sta_notify_params *notify) +{ + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_vdev_priv_obj *curr_tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc_obj; + struct tdls_soc_priv_obj *curr_tdls_soc; + struct wlan_objmgr_vdev *temp_vdev = NULL; + + + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(notify->vdev, + &tdls_vdev_obj, + &tdls_soc_obj)) + return QDF_STATUS_E_INVAL; + + tdls_debug("Check and update TDLS state"); + + curr_tdls_vdev = tdls_vdev_obj; + curr_tdls_soc = tdls_soc_obj; + + /* Disassociation event */ + if (!tdls_soc_obj->tdls_disable_in_progress) + tdls_send_update_to_fw(tdls_vdev_obj, tdls_soc_obj, false, + false, false, notify->session_id); + + /* If concurrency is not marked, then we have to + * check, whether TDLS could be enabled in the + * system after this disassoc event. + */ + if (!notify->lfr_roam && !tdls_soc_obj->tdls_disable_in_progress) { + temp_vdev = tdls_get_vdev(tdls_soc_obj->soc, WLAN_TDLS_NB_ID); + if (NULL != temp_vdev) { + status = tdls_get_vdev_objects(temp_vdev, + &tdls_vdev_obj, + &tdls_soc_obj); + if (QDF_STATUS_SUCCESS == status) { + tdls_send_update_to_fw(tdls_vdev_obj, + tdls_soc_obj, + false, + false, + true, + notify->session_id); + curr_tdls_vdev = tdls_vdev_obj; + curr_tdls_soc = tdls_soc_obj; + } + } + } + + /* Check and set the connection tracker and implicit timers */ + tdls_set_ct_mode(curr_tdls_soc->soc); + if (curr_tdls_soc->enable_tdls_connection_tracker) + tdls_implicit_enable(curr_tdls_vdev); + else + tdls_implicit_disable(curr_tdls_vdev); + + /* release the vdev ref , if temp vdev was acquired */ + if (temp_vdev) + wlan_objmgr_vdev_release_ref(temp_vdev, + WLAN_TDLS_NB_ID); + + return status; +} + +QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify) +{ + QDF_STATUS status; + + if (!notify || !notify->vdev) + return QDF_STATUS_E_INVAL; + + if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(notify->vdev, + WLAN_TDLS_NB_ID)) + return QDF_STATUS_E_INVAL; + + status = tdls_process_sta_disconnect(notify); + + wlan_objmgr_vdev_release_ref(notify->vdev, + WLAN_TDLS_NB_ID); + + qdf_mem_free(notify); + return status; +} + +/** + * tdls_set_mode_in_vdev() - set TDLS mode + * @tdls_vdev: tdls vdev object + * @tdls_soc: tdls soc object + * @tdls_mode: TDLS mode + * @source: TDLS disable source enum values + * + * Return: Void + */ +static void tdls_set_mode_in_vdev(struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_soc_priv_obj *tdls_soc, + enum tdls_feature_mode tdls_mode, + enum tdls_disable_sources source) +{ + if (!tdls_vdev) + return; + tdls_debug("enter tdls mode is %d", tdls_mode); + + if (TDLS_SUPPORT_IMP_MODE == tdls_mode || + TDLS_SUPPORT_EXT_CONTROL == tdls_mode) { + clear_bit((unsigned long)source, + &tdls_soc->tdls_source_bitmap); + /* + * Check if any TDLS source bit is set and if + * bitmap is not zero then we should not + * enable TDLS + */ + if (tdls_soc->tdls_source_bitmap) { + tdls_notice("Don't enable TDLS, source bitmap: %lu", + tdls_soc->tdls_source_bitmap); + return; + } + tdls_implicit_enable(tdls_vdev); + /* tdls implicit mode is enabled, so + * enable the connection tracker + */ + tdls_soc->enable_tdls_connection_tracker = + true; + } else if (TDLS_SUPPORT_DISABLED == tdls_mode) { + set_bit((unsigned long)source, + &tdls_soc->tdls_source_bitmap); + tdls_implicit_disable(tdls_vdev); + /* If tdls implicit mode is disabled, then + * stop the connection tracker. + */ + tdls_soc->enable_tdls_connection_tracker = + false; + } else if (TDLS_SUPPORT_EXP_TRIG_ONLY == + tdls_mode) { + clear_bit((unsigned long)source, + &tdls_soc->tdls_source_bitmap); + tdls_implicit_disable(tdls_vdev); + /* If tdls implicit mode is disabled, then + * stop the connection tracker. + */ + tdls_soc->enable_tdls_connection_tracker = + false; + + /* + * Check if any TDLS source bit is set and if + * bitmap is not zero then we should not + * enable TDLS + */ + if (tdls_soc->tdls_source_bitmap) + return; + } + tdls_debug("exit "); + +} + +/** + * tdls_set_current_mode() - set TDLS mode + * @tdls_soc: tdls soc object + * @tdls_mode: TDLS mode + * @update_last: indicate to record the last tdls mode + * @source: TDLS disable source enum values + * + * Return: Void + */ +static void tdls_set_current_mode(struct tdls_soc_priv_obj *tdls_soc, + enum tdls_feature_mode tdls_mode, + bool update_last, + enum tdls_disable_sources source) +{ + struct wlan_objmgr_vdev *vdev; + struct tdls_vdev_priv_obj *tdls_vdev; + + if (!tdls_soc) + return; + + tdls_debug("mode %d", (int)tdls_mode); + + if (update_last) + tdls_soc->tdls_last_mode = tdls_mode; + + if (tdls_soc->tdls_current_mode == tdls_mode) { + tdls_debug("already in mode %d", tdls_mode); + + switch (tdls_mode) { + /* TDLS is already enabled hence clear source mask, return */ + case TDLS_SUPPORT_IMP_MODE: + case TDLS_SUPPORT_EXP_TRIG_ONLY: + case TDLS_SUPPORT_EXT_CONTROL: + clear_bit((unsigned long)source, + &tdls_soc->tdls_source_bitmap); + tdls_debug("clear source mask:%d", source); + return; + /* TDLS is already disabled hence set source mask, return */ + case TDLS_SUPPORT_DISABLED: + set_bit((unsigned long)source, + &tdls_soc->tdls_source_bitmap); + tdls_debug("set source mask:%d", source); + return; + default: + return; + } + } + + /* get sta vdev */ + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(tdls_soc->soc, + QDF_STA_MODE, + WLAN_TDLS_NB_ID); + if (NULL != vdev) { + tdls_debug("set mode in tdls vdev "); + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_vdev) + tdls_set_mode_in_vdev(tdls_vdev, tdls_soc, + tdls_mode, source); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + } + + /* get p2p client vdev */ + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(tdls_soc->soc, + QDF_P2P_CLIENT_MODE, + WLAN_TDLS_NB_ID); + if (NULL != vdev) { + tdls_debug("set mode in tdls vdev "); + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_vdev) + tdls_set_mode_in_vdev(tdls_vdev, tdls_soc, + tdls_mode, source); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + } + + if (!update_last) + tdls_soc->tdls_last_mode = tdls_soc->tdls_current_mode; + + tdls_soc->tdls_current_mode = tdls_mode; + +} diff --git a/umac/tdls/core/src/wlan_tdls_main.h b/umac/tdls/core/src/wlan_tdls_main.h index cf758e772e..e6929facff 100644 --- a/umac/tdls/core/src/wlan_tdls_main.h +++ b/umac/tdls/core/src/wlan_tdls_main.h @@ -145,7 +145,8 @@ struct tdls_set_state_info { * struct tdls_psoc_priv_ctx - tdls context * @soc: objmgr psoc * @tdls_current_mode: current tdls mode - * @tdls_user_config_mode: user configure tdls mode + * @tdls_last_mode: last tdls mode + * @tdls_source_bitmap: bit map to set/reset TDLS by different sources * @tdls_conn_info: this tdls_conn_info can be removed and we can use peer type * of peer object to get the active tdls peers * @tdls_configs: tdls user configure @@ -180,7 +181,8 @@ struct tdls_set_state_info { struct tdls_soc_priv_obj { struct wlan_objmgr_psoc *soc; enum tdls_feature_mode tdls_current_mode; - enum tdls_feature_mode tdls_user_config_mode; + enum tdls_feature_mode tdls_last_mode; + unsigned long tdls_source_bitmap; struct tdls_conn_info tdls_conn_info[WLAN_TDLS_STA_MAX_NUM]; struct tdls_user_config tdls_configs; uint16_t max_num_tdls_sta; @@ -192,6 +194,7 @@ struct tdls_soc_priv_obj { uint8_t tdls_external_peer_count; bool tdls_nss_switch_in_progress; bool tdls_nss_teardown_complete; + bool tdls_disable_in_progress; enum tdls_nss_transition_state tdls_nss_transition_mode; int32_t tdls_teardown_peers_cnt; struct tdls_set_state_info set_state_info; @@ -320,6 +323,25 @@ struct tdls_peer { struct tdls_peer_mlme_info *tdls_info; }; +/** + * struct tdls_os_if_event - TDLS os event info + * @type: type of event + * @info: pointer to event information + */ +struct tdls_os_if_event { + uint32_t type; + void *info; +}; + +/** + * enum tdls_os_if_notification - TDLS notification from OS IF + * @TDLS_NOTIFY_STA_SESSION_INCREMENT: sta session count incremented + * @TDLS_NOTIFY_STA_SESSION_DECREMENT: sta session count decremented + */ +enum tdls_os_if_notification { + TDLS_NOTIFY_STA_SESSION_INCREMENT, + TDLS_NOTIFY_STA_SESSION_DECREMENT +}; /** * wlan_vdev_get_tdls_soc_obj - private API to get tdls soc object from vdev * @vdev: vdev object @@ -501,4 +523,103 @@ QDF_STATUS tdls_get_vdev_objects(struct wlan_objmgr_vdev *vdev, struct tdls_vdev_priv_obj **tdls_vdev_obj, struct tdls_soc_priv_obj **tdls_soc_obj); +/** + * cds_set_tdls_ct_mode() - Set the tdls connection tracker mode + * @hdd_ctx: hdd context + * + * This routine is called to set the tdls connection tracker operation status + * + * Return: NONE + */ +void tdls_set_ct_mode(struct wlan_objmgr_psoc *psoc); + +/** + * tdls_notify_sta_connect() - Update tdls state for every + * connect event. + * @vdev: vdev object manager + * @tdls_prohibited: flag to tell whether tdls prohibited in this bss + * @tdls_chan_swit_prohibited: flag to tell whether tdls channel switch + * prohibited in this bss + * @session_id: session id + * + * After every connect event in the system, check whether TDLS + * can be enabled in the system. If TDLS can be enabled, update the + * TDLS state as needed. + * + * Return: None + */ +void tdls_notify_sta_connect(struct wlan_objmgr_vdev *vdev, + bool tdls_prohibited, + bool tdls_chan_swit_prohibited, + uint8_t session_id); + +/** + * tdls_notify_sta_disconnect() - Update tdls state for every + * disconnect event. + * @vdev: vdev object manager + * @lfr_roam: roaming case + * @session_id: session id + * + * After every disconnect event in the system, check whether TDLS + * can be disabled/enabled in the system and update the + * TDLS state as needed. + * + * Return: None + */ +void tdls_notify_sta_disconnect(struct wlan_objmgr_vdev *vdev, + bool lfr_roam, + uint8_t session_id); + +/** + * tdls_notify_decrement_session() - Notify the session decrement + * @psoc: psoc object manager + * + * Policy manager notify TDLS about session decrement + * + * Return: None + */ +void tdls_notify_decrement_session(struct wlan_objmgr_psoc *psoc); + +/** + * tdls_notify_increment_session() - Notify the session increment + * @psoc: psoc object manager + * + * Policy manager notify TDLS about session increment + * + * Return: None + */ +void tdls_notify_increment_session(struct wlan_objmgr_psoc *psoc); + +/** + * tdls_check_is_tdls_allowed() - check is tdls allowed or not + * @vdev: vdev object + * + * Function determines the whether TDLS allowed in the system + * + * Return: true or false + */ +bool tdls_check_is_tdls_allowed(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_get_vdev() - Get tdls specific vdev object manager + * @psoc: wlan psoc object manager + * @dbg_id: debug id + * + * If TDLS possible, return the corresponding vdev + * to enable TDLS in the system. + * + * Return: vdev manager pointer or NULL. + */ +struct wlan_objmgr_vdev *tdls_get_vdev(struct wlan_objmgr_psoc *psoc, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * tdls_process_policy_mgr_notification() - process policy manager notification + * @psoc: soc object manager + * + * Return: QDF_STATUS + */ +QDF_STATUS +tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc); + #endif diff --git a/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h b/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h index dc43e792e3..39e9ddebe7 100644 --- a/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h +++ b/umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h @@ -286,6 +286,22 @@ enum tdls_event_reason { TDLS_SCAN_COMPLETED, }; +/** + * enum tdls_disable_sources - TDLS disable sources + * @TDLS_SET_MODE_SOURCE_USER: disable from user + * @TDLS_SET_MODE_SOURCE_SCAN: disable during scan + * @TDLS_SET_MODE_SOURCE_OFFCHANNEL: disable during offchannel + * @TDLS_SET_MODE_SOURCE_BTC: disable during bluetooth + * @TDLS_SET_MODE_SOURCE_P2P: disable during p2p + */ +enum tdls_disable_sources { + TDLS_SET_MODE_SOURCE_USER = 0, + TDLS_SET_MODE_SOURCE_SCAN, + TDLS_SET_MODE_SOURCE_OFFCHANNEL, + TDLS_SET_MODE_SOURCE_BTC, + TDLS_SET_MODE_SOURCE_P2P, +}; + /** * struct tdls_osif_indication - tdls indication to os if layer * @vdev: vdev object diff --git a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c index c57008a19f..be63fbdbd8 100644 --- a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c +++ b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -28,6 +28,7 @@ #include "../../core/src/wlan_tdls_cmds_process.h" #include #include +#include "wlan_policy_mgr_api.h" QDF_STATUS ucfg_tdls_init(void) { @@ -122,7 +123,6 @@ static QDF_STATUS tdls_global_init(struct tdls_soc_priv_obj *soc_obj) soc_obj->tdls_teardown_peers_cnt = 0; soc_obj->tdls_nss_teardown_complete = false; soc_obj->tdls_nss_transition_mode = TDLS_NSS_TRANSITION_S_UNKNOWN; - soc_obj->tdls_user_config_mode = TDLS_SUPPORT_DISABLED; feature = soc_obj->tdls_configs.tdls_feature_flags; if (TDLS_IS_BUFFER_STA_ENABLED(feature) || @@ -178,6 +178,7 @@ QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc, { struct tdls_soc_priv_obj *soc_obj; uint32_t tdls_feature_flags; + struct policy_mgr_tdls_cbacks tdls_pm_call_backs; tdls_notice("tdls update config "); if (!psoc || !req) { @@ -208,6 +209,16 @@ QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc, soc_obj->tdls_add_sta_req = req->tdls_add_sta_req; soc_obj->tdls_del_sta_req = req->tdls_del_sta_req; soc_obj->tdls_update_peer_state = req->tdls_update_peer_state; + tdls_pm_call_backs.tdls_notify_increment_session = + tdls_notify_increment_session; + + tdls_pm_call_backs.tdls_notify_decrement_session = + tdls_notify_decrement_session; + if (QDF_STATUS_SUCCESS != policy_mgr_register_tdls_cb( + psoc, &tdls_pm_call_backs)) { + tdls_err("policy manager callback registration failed "); + return QDF_STATUS_E_FAILURE; + } /* Update TDLS user config */ qdf_mem_copy(&soc_obj->tdls_configs, &req->config, sizeof(req->config));