diff --git a/umac/tdls/core/src/wlan_tdls_main.c b/umac/tdls/core/src/wlan_tdls_main.c index 879290e56b4d..5fef8c76e727 100644 --- a/umac/tdls/core/src/wlan_tdls_main.c +++ b/umac/tdls/core/src/wlan_tdls_main.c @@ -31,6 +31,11 @@ #include "wlan_policy_mgr_public_struct.h" #include "wlan_policy_mgr_api.h" +/* Global tdls soc pvt object + * this is useful for some functions which does not receive either vdev or psoc + * objects. + */ +static struct tdls_soc_priv_obj *tdls_soc_global; QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, void *arg_list) @@ -56,6 +61,7 @@ QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, qdf_mem_free(tdls_soc_obj); } + tdls_soc_global = tdls_soc_obj; tdls_notice("TDLS obj attach to psoc successfully"); return status; @@ -141,6 +147,8 @@ QDF_STATUS tdls_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, { QDF_STATUS status; struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct wlan_objmgr_pdev *pdev; + struct tdls_soc_priv_obj *tdls_soc; tdls_notice("tdls vdev mode %d", wlan_vdev_mlme_get_opmode(vdev)); if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE && @@ -169,6 +177,23 @@ QDF_STATUS tdls_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, if (QDF_IS_STATUS_ERROR(status)) goto out; + tdls_soc = wlan_vdev_get_tdls_soc_obj(vdev); + if (!tdls_soc) { + tdls_err("get soc by vdev failed "); + return QDF_STATUS_E_NOMEM; + } + + pdev = wlan_vdev_get_pdev(vdev); + + status = ucfg_scan_register_event_handler(pdev, + tdls_scan_complete_event_handler, + tdls_soc); + + if (QDF_STATUS_SUCCESS != status) { + tdls_err("scan event register failed "); + return QDF_STATUS_E_FAILURE; + } + tdls_notice("tdls object attach to vdev successfully"); out: return status; @@ -244,6 +269,9 @@ QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg) case TDLS_CMD_SET_RESPONDER: tdls_set_responder(msg->bodyptr); break; + case TDLS_CMD_SCAN_DONE: + tdls_scan_done_callback(msg->bodyptr); + break; case TDLS_NOTIFY_STA_CONNECTION: tdls_notify_sta_connect(msg->bodyptr); break; @@ -257,7 +285,6 @@ QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg) case TDLS_CMD_SESSION_DECREMENT: tdls_process_policy_mgr_notification(msg->bodyptr); break; - default: break; } @@ -1102,3 +1129,139 @@ release_mode_ref: return status; } +/** + * wlan_hdd_tdls_scan_done_callback() - callback for tdls scan done event + * @pAdapter: HDD adapter + * + * Return: Void + */ +void tdls_scan_done_callback(struct tdls_soc_priv_obj *tdls_soc) +{ + if (!tdls_soc) + return; + + if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode) { + tdls_notice("TDLS mode is disabled OR not enabled"); + return; + } + + /* if tdls was enabled before scan, re-enable tdls mode */ + if (TDLS_SUPPORT_IMP_MODE == tdls_soc->tdls_last_mode || + TDLS_SUPPORT_EXT_CONTROL == tdls_soc->tdls_last_mode || + TDLS_SUPPORT_EXP_TRIG_ONLY == tdls_soc->tdls_last_mode) { + tdls_notice("revert tdls mode %d", + tdls_soc->tdls_last_mode); + + tdls_set_current_mode(tdls_soc, tdls_soc->tdls_last_mode, + false, + TDLS_SET_MODE_SOURCE_SCAN); + } +} + +/** + * tdls_post_scan_done_msg() - post scan done message to tdls cmd queue + * @tdls_soc: tdls soc object + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_NULL_VALUE + */ +static QDF_STATUS tdls_post_scan_done_msg(struct tdls_soc_priv_obj *tdls_soc) +{ + struct scheduler_msg msg = {0, }; + + if (!tdls_soc) { + tdls_err("tdls_soc: %p ", tdls_soc); + return QDF_STATUS_E_NULL_VALUE; + } + + msg.bodyptr = tdls_soc; + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_SCAN_DONE; + scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg); + + return QDF_STATUS_SUCCESS; +} + +void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg) +{ + enum tQDF_ADAPTER_MODE device_mode; + struct tdls_soc_priv_obj *tdls_soc; + + if (!vdev || !event || !arg) + return; + + if (SCAN_EVENT_TYPE_COMPLETED != event->type) + return; + + device_mode = wlan_vdev_mlme_get_opmode(vdev); + + if (device_mode != QDF_STA_MODE && + device_mode != QDF_P2P_CLIENT_MODE) + return; + tdls_soc = (struct tdls_soc_priv_obj *) arg; + tdls_post_scan_done_msg(tdls_soc); +} + +QDF_STATUS tdls_scan_callback(struct tdls_soc_priv_obj *tdls_soc) +{ + struct tdls_peer *curr_peer; + struct tdls_vdev_priv_obj *tdls_vdev; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* if tdls is not enabled, then continue scan */ + if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode) + return status; + + /* Get the vdev based on vdev operating mode*/ + vdev = tdls_get_vdev(tdls_soc->soc, WLAN_TDLS_NB_ID); + if (!vdev) + return status; + + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_vdev) + goto return_success; + + curr_peer = tdls_is_progress(tdls_vdev, NULL, 0); + if (NULL != curr_peer) { + if (tdls_soc->scan_reject_count++ >= TDLS_SCAN_REJECT_MAX) { + tdls_notice(QDF_MAC_ADDRESS_STR + ". scan rejected %d. force it to idle", + QDF_MAC_ADDR_ARRAY( + curr_peer->peer_mac.bytes), + tdls_soc->scan_reject_count); + tdls_soc->scan_reject_count = 0; + + tdls_set_peer_link_status(curr_peer, + TDLS_LINK_IDLE, + TDLS_LINK_UNSPECIFIED); + status = QDF_STATUS_SUCCESS; + } else { + tdls_warn("tdls in progress. scan rejected %d", + tdls_soc->scan_reject_count); + status = QDF_STATUS_E_BUSY; + } + } +return_success: + wlan_objmgr_vdev_release_ref(vdev, + WLAN_TDLS_NB_ID); + return status; +} + +void tdls_scan_serialization_comp_info_cb( + union wlan_serialization_rules_info *comp_info) +{ + struct tdls_soc_priv_obj *tdls_soc; + QDF_STATUS status; + if (!comp_info) + return; + + tdls_soc = tdls_soc_global; + comp_info->scan_info.is_tdls_in_progress = false; + status = tdls_scan_callback(tdls_soc); + if (QDF_STATUS_E_BUSY == status) + comp_info->scan_info.is_tdls_in_progress = true; +} + + diff --git a/umac/tdls/core/src/wlan_tdls_main.h b/umac/tdls/core/src/wlan_tdls_main.h index 769f2533c52d..30ace4511980 100644 --- a/umac/tdls/core/src/wlan_tdls_main.h +++ b/umac/tdls/core/src/wlan_tdls_main.h @@ -33,6 +33,7 @@ #include #include #include +#include "wlan_serialization_api.h" /* Bit mask flag for tdls_option to FW */ #define ENA_TDLS_OFFCHAN (1 << 0) /* TDLS Off Channel support */ @@ -54,6 +55,8 @@ * should not be more than 2000. */ #define TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE 1000 +#define TDLS_SCAN_REJECT_MAX 5 + #define tdls_log(level, args...) \ QDF_TRACE(QDF_MODULE_ID_TDLS, level, ## args) @@ -146,6 +149,7 @@ struct tdls_set_state_info { * @soc: objmgr psoc * @tdls_current_mode: current tdls mode * @tdls_last_mode: last tdls mode + * @scan_reject_count: number of times scan rejected due to TDLS * @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 @@ -182,6 +186,7 @@ struct tdls_soc_priv_obj { struct wlan_objmgr_psoc *soc; enum tdls_feature_mode tdls_current_mode; enum tdls_feature_mode tdls_last_mode; + int scan_reject_count; unsigned long tdls_source_bitmap; struct tdls_conn_info tdls_conn_info[WLAN_TDLS_STA_MAX_NUM]; struct tdls_user_config tdls_configs; @@ -619,4 +624,42 @@ struct wlan_objmgr_vdev *tdls_get_vdev(struct wlan_objmgr_psoc *psoc, QDF_STATUS tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc); +/** + * tdls_scan_complete_event_handler() - scan complete event handler for tdls + * @vdev: vdev object + * @event: scan event + * @arg: tdls soc object + * + * Return: None + */ +void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg); + +/** + * tdls_scan_callback() - callback for TDLS scan operation + * @soc: tdls soc pvt object + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_scan_callback(struct tdls_soc_priv_obj *tdls_soc); + +/** + * wlan_hdd_tdls_scan_done_callback() - callback for tdls scan done event + * @tdls_soc: tdls soc object + * + * Return: Void + */ +void tdls_scan_done_callback(struct tdls_soc_priv_obj *tdls_soc); + +/** + * tdls_scan_serialization_comp_info_cb() - callback for scan start + * @comp_info: serialize rules info + * + * Return: negative = caller should stop and return error code immediately + * 1 = caller can continue to scan + */ +void tdls_scan_serialization_comp_info_cb( + union wlan_serialization_rules_info *comp_info); + #endif diff --git a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c index ce21c05bf406..1e4afdbfaa06 100644 --- a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c +++ b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -30,6 +30,7 @@ #include #include #include "wlan_policy_mgr_api.h" +#include "wlan_scan_ucfg_api.h" QDF_STATUS ucfg_tdls_init(void) { @@ -134,7 +135,6 @@ static QDF_STATUS tdls_global_init(struct tdls_soc_priv_obj *soc_obj) else soc_obj->max_num_tdls_sta = WLAN_TDLS_STA_MAX_NUM; - for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta; sta_idx++) { soc_obj->tdls_conn_info[sta_idx].sta_id = 0; soc_obj->tdls_conn_info[sta_idx].session_id = 255; @@ -247,6 +247,18 @@ QDF_STATUS ucfg_tdls_psoc_enable(struct wlan_objmgr_psoc *psoc) status = tgt_tdls_register_ev_handler(psoc); + if (status != QDF_STATUS_SUCCESS) + return status; + + status = wlan_serialization_register_comp_info_cb(psoc, + WLAN_UMAC_COMP_TDLS, + WLAN_SER_CMD_SCAN, + tdls_scan_serialization_comp_info_cb); + if (QDF_STATUS_SUCCESS != status) { + tdls_err("Serialize scan cmd register failed "); + status = QDF_STATUS_E_FAILURE; + } + return status; }