diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 897b9023d4ea..23680310c696 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -257,6 +257,9 @@ enum hdd_adapter_flags { /* Maximum time(ms) to wait for external acs response */ #define WLAN_VENDOR_ACS_WAIT_TIME 1000 +/* Maximum time(ms) to wait for monitor mode vdev up event completion*/ +#define WLAN_MONITOR_MODE_VDEV_UP_EVT SME_CMD_VDEV_START_BSS_TIMEOUT + /* Mac Address string length */ #define MAC_ADDRESS_STR_LEN 18 /* Including null terminator */ /* Max and min IEs length in bytes */ @@ -1116,6 +1119,11 @@ struct hdd_adapter { /* QDF event for session open */ qdf_event_t qdf_session_open_event; +#ifdef FEATURE_MONITOR_MODE_SUPPORT + /* QDF event for monitor mode vdev up */ + qdf_event_t qdf_monitor_mode_vdev_up_event; +#endif + /* TODO: move these to sta ctx. These may not be used in AP */ /** completion variable for disconnect callback */ struct completion disconnect_comp_var; @@ -1296,7 +1304,9 @@ struct hdd_adapter { uint32_t mon_chan_freq; uint32_t mon_bandwidth; uint16_t latency_level; - +#ifdef FEATURE_MONITOR_MODE_SUPPORT + bool monitor_mode_vdev_up_in_progress; +#endif /* rcpi information */ struct rcpi_info rcpi; bool send_mode_change; @@ -4240,4 +4250,29 @@ int hdd_crash_inject(struct hdd_adapter *adapter, uint32_t v1, uint32_t v2) } #endif +#ifdef FEATURE_MONITOR_MODE_SUPPORT + +void hdd_sme_monitor_mode_callback(uint8_t vdev_id); + +QDF_STATUS hdd_monitor_mode_vdev_status(struct hdd_adapter *adapter); + +QDF_STATUS hdd_monitor_mode_qdf_create_event(struct hdd_adapter *adapter, + uint8_t session_type); +#else +static inline void hdd_sme_monitor_mode_callback(uint8_t vdev_id) {} + +static inline QDF_STATUS +hdd_monitor_mode_vdev_status(struct hdd_adapter *adapter) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +hdd_monitor_mode_qdf_create_event(struct hdd_adapter *adapter, + uint8_t session_type) +{ + return QDF_STATUS_SUCCESS; +} +#endif + #endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 4ae79bed39b7..ca4a99d597a7 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -22450,15 +22450,53 @@ static int __wlan_hdd_cfg80211_set_mon_ch(struct wiphy *wiphy, hdd_err("Failed to change hw mode"); return -EINVAL; } + + if (adapter->monitor_mode_vdev_up_in_progress) { + hdd_err_rl("monitor mode vdev up in progress"); + return -EBUSY; + } + + status = qdf_event_reset(&adapter->qdf_monitor_mode_vdev_up_event); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("failed to reinit monitor mode vdev up event"); + return qdf_status_to_os_return(status); + } + adapter->monitor_mode_vdev_up_in_progress = true; + status = sme_roam_channel_change_req(mac_handle, bssid, &roam_profile.ch_params, &roam_profile); if (status) { - hdd_err("Failed to set sme_RoamChannel for monitor mode status: %d", - status); + hdd_err_rl("Failed to set sme_RoamChannel for monitor mode status: %d", + status); + adapter->monitor_mode_vdev_up_in_progress = false; ret = qdf_status_to_os_return(status); return ret; } + + /* block on a completion variable until vdev up success*/ + status = qdf_wait_for_event_completion( + &adapter->qdf_monitor_mode_vdev_up_event, + WLAN_MONITOR_MODE_VDEV_UP_EVT); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("monitor vdev up event time out vdev id: %d", + adapter->vdev_id); + if (adapter->qdf_monitor_mode_vdev_up_event.force_set) + /* + * SSR/PDR has caused shutdown, which has + * forcefully set the event. + */ + hdd_err_rl("monitor mode vdev up event forcefully set"); + else if (status == QDF_STATUS_E_TIMEOUT) + hdd_err_rl("monitor mode vdev up timed out"); + else + hdd_err_rl("Failed monitor mode vdev up(status-%d)", + status); + + adapter->monitor_mode_vdev_up_in_progress = false; + return qdf_status_to_os_return(status); + } + hdd_exit(); return 0; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index b1ed94cf62ef..9bcf801bac23 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -4713,6 +4713,12 @@ hdd_alloc_station_adapter(struct hdd_context *hdd_ctx, tSirMacAddr mac_addr, if (QDF_IS_STATUS_ERROR(qdf_status)) goto free_net_dev; + qdf_status = hdd_monitor_mode_qdf_create_event(adapter, session_type); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err_rl("create monitor mode vdve up event failed"); + goto free_net_dev; + } + init_completion(&adapter->vdev_destroy_event); adapter->offloads_configured = false; @@ -6396,6 +6402,9 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, wlan_hdd_scan_abort(adapter); hdd_deregister_hl_netdev_fc_timer(adapter); hdd_deregister_tx_flow_control(adapter); + status = hdd_monitor_mode_vdev_status(adapter); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("stop failed montior mode"); sme_delete_mon_session(mac_handle, adapter->vdev_id); hdd_vdev_destroy(adapter); break; @@ -7313,16 +7322,53 @@ int wlan_hdd_set_mon_chan(struct hdd_adapter *adapter, qdf_freq_t freq, return -EINVAL; } + if (adapter->monitor_mode_vdev_up_in_progress) { + hdd_err_rl("monitor mode vdev up in progress"); + return -EBUSY; + } + + status = qdf_event_reset(&adapter->qdf_monitor_mode_vdev_up_event); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("failed to reinit monitor mode vdev up event"); + return qdf_status_to_os_return(status); + } + adapter->monitor_mode_vdev_up_in_progress = true; + status = sme_roam_channel_change_req(hdd_ctx->mac_handle, bssid, &roam_profile.ch_params, &roam_profile); if (status) { hdd_err("Status: %d Failed to set sme_roam Channel for monitor mode", status); + adapter->monitor_mode_vdev_up_in_progress = false; + return qdf_status_to_os_return(status); } adapter->mon_chan_freq = freq; adapter->mon_bandwidth = bandwidth; + + /* block on a completion variable until vdev up success*/ + status = qdf_wait_for_event_completion( + &adapter->qdf_monitor_mode_vdev_up_event, + WLAN_MONITOR_MODE_VDEV_UP_EVT); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("monitor vdev up event time out vdev id: %d", + adapter->vdev_id); + if (adapter->qdf_monitor_mode_vdev_up_event.force_set) + /* + * SSR/PDR has caused shutdown, which has + * forcefully set the event. + */ + hdd_err_rl("monitor mode vdev up event forcefully set"); + else if (status == QDF_STATUS_E_TIMEOUT) + hdd_err("monitor mode vdev up timed out"); + else + hdd_err_rl("Failed monitor mode vdev up(status-%d)", + status); + + adapter->monitor_mode_vdev_up_in_progress = false; + } + return qdf_status_to_os_return(status); } #endif @@ -13557,6 +13603,10 @@ int hdd_register_cb(struct hdd_context *hdd_ctx) sme_set_oem_data_event_handler_cb(mac_handle, hdd_oem_event_handler_cb); sme_set_roam_scan_ch_event_cb(mac_handle, hdd_get_roam_scan_ch_cb); + status = sme_set_monitor_mode_cb(mac_handle, + hdd_sme_monitor_mode_callback); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("Register monitor mode callback failed"); hdd_exit(); @@ -16777,6 +16827,84 @@ wlan_hdd_add_monitor_check(struct hdd_context *hdd_ctx, } #endif /* WLAN_FEATURE_PKT_CAPTURE */ + +#ifdef FEATURE_MONITOR_MODE_SUPPORT + +void hdd_sme_monitor_mode_callback(uint8_t vdev_id) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err_rl("Invalid HDD_CTX"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) { + hdd_err_rl("NULL adapter"); + return; + } + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err_rl("Invalid magic"); + return; + } + + if (adapter->magic == WLAN_HDD_ADAPTER_MAGIC) + qdf_event_set(&adapter->qdf_monitor_mode_vdev_up_event); + + hdd_debug("monitor mode vdev up completed"); + adapter->monitor_mode_vdev_up_in_progress = false; +} + +QDF_STATUS hdd_monitor_mode_qdf_create_event(struct hdd_adapter *adapter, + uint8_t session_type) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (session_type == QDF_MONITOR_MODE) { + qdf_status = qdf_event_create( + &adapter->qdf_monitor_mode_vdev_up_event); + } + return qdf_status; +} + +QDF_STATUS hdd_monitor_mode_vdev_status(struct hdd_adapter *adapter) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!adapter->monitor_mode_vdev_up_in_progress) + return status; + + /* block on a completion variable until vdev up success*/ + status = qdf_wait_for_event_completion( + &adapter->qdf_monitor_mode_vdev_up_event, + WLAN_MONITOR_MODE_VDEV_UP_EVT); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("monitor mode vdev up event time out vdev id: %d", + adapter->vdev_id); + if (adapter->qdf_monitor_mode_vdev_up_event.force_set) + /* + * SSR/PDR has caused shutdown, which has + * forcefully set the event. + */ + hdd_err_rl("monitor mode vdev up event forcefully set"); + else if (status == QDF_STATUS_E_TIMEOUT) + hdd_err_rl("mode vdev up event timed out"); + else + hdd_err_rl("Failed to wait for monitor vdev up(status-%d)", + status); + + adapter->monitor_mode_vdev_up_in_progress = false; + return status; + } + + return QDF_STATUS_SUCCESS; +} +#endif + #ifdef CONFIG_WLAN_DEBUG_CRASH_INJECT int hdd_crash_inject(struct hdd_adapter *adapter, uint32_t v1, uint32_t v2) { diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h index 67bfa9d16a43..6700ba578b95 100644 --- a/core/mac/inc/wni_api.h +++ b/core/mac/inc/wni_api.h @@ -244,7 +244,8 @@ enum eWniMsgTypes { eWNI_SME_ROAM_SEND_PER_REQ = SIR_SME_MSG_TYPES_BEGIN + 159, eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT = SIR_SME_MSG_TYPES_BEGIN + 160, - eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 161 + eWNI_SME_MONITOR_MODE_VDEV_UP = SIR_SME_MSG_TYPES_BEGIN + 161, + eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 162 }; typedef struct sAniCfgTxRateCtrs { diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c index 31bb8bf86d0a..b5cbf6c1d8b7 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -2816,6 +2816,8 @@ error: static void lim_handle_mon_switch_channel_rsp(struct pe_session *session, QDF_STATUS status) { + struct scheduler_msg message = {0}; + if (session->bssType != eSIR_MONITOR_MODE) return; @@ -2829,6 +2831,17 @@ static void lim_handle_mon_switch_channel_rsp(struct pe_session *session, wlan_vdev_mlme_sm_deliver_evt(session->vdev, WLAN_VDEV_SM_EV_START_SUCCESS, 0, NULL); + + message.type = eWNI_SME_MONITOR_MODE_VDEV_UP; + message.bodyval = session->vdev_id; + pe_debug("vdev id %d ", session->vdev_id); + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &message)) { + pe_err("Failed to post message montior mode vdev up"); + } } /** diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 8eef63ff5f26..1958d72194ee 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -4177,4 +4177,38 @@ QDF_STATUS sme_vdev_self_peer_delete_resp(struct del_vdev_params *param); * Return: None */ void sme_vdev_del_resp(uint8_t vdev_id); + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * sme_set_monitor_mode_cb() - Register monitor mode vdev up operation callback + * @mac_handle: Opaque handle to the MAC context + * @monitor_mode_cb: callback to be registered + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_monitor_mode_cb(mac_handle_t mac_handle, + void (*monitor_mode_cb)(uint8_t vdev_id)); + +/* + * sme_process_monitor_mode_vdev_up_evt() - Handle vdev up completion + * @vdev_id: vdev id + * + * Return: QDF_STATUS. + */ +QDF_STATUS sme_process_monitor_mode_vdev_up_evt(uint8_t vdev_id); +#else +static inline +QDF_STATUS sme_set_monitor_mode_cb(mac_handle_t mac_handle, + void (*monitor_mode_cb)(uint8_t vdev_id)) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +sme_process_monitor_mode_vdev_up_evt(uint8_t vdev_id) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 46ce736f0f30..987fe650a950 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -394,6 +394,9 @@ struct sme_context { #endif sme_get_raom_scan_ch_callback roam_scan_ch_callback; void *roam_scan_ch_get_context; +#ifdef FEATURE_MONITOR_MODE_SUPPORT + void (*monitor_mode_cb)(uint8_t vdev_id); +#endif }; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 63eb5796a883..d3900a983655 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -2409,6 +2409,9 @@ QDF_STATUS sme_process_msg(struct mac_context *mac, struct scheduler_msg *pMsg) sme_process_roam_scan_ch_list_resp(mac, pMsg->bodyptr); qdf_mem_free(pMsg->bodyptr); break; + case eWNI_SME_MONITOR_MODE_VDEV_UP: + status = sme_process_monitor_mode_vdev_up_evt(pMsg->bodyval); + break; default: if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN) @@ -16474,3 +16477,46 @@ end: sme_release_global_lock(&mac->sme); return status; } + +#ifdef FEATURE_MONITOR_MODE_SUPPORT + +QDF_STATUS sme_set_monitor_mode_cb(mac_handle_t mac_handle, + void (*monitor_mode_cb)(uint8_t vdev_id)) +{ + QDF_STATUS qdf_status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + sme_err("Failed to acquire sme lock; status: %d", qdf_status); + return qdf_status; + } + mac->sme.monitor_mode_cb = monitor_mode_cb; + sme_release_global_lock(&mac->sme); + + return qdf_status; +} + +QDF_STATUS sme_process_monitor_mode_vdev_up_evt(uint8_t vdev_id) +{ + mac_handle_t mac_handle; + struct mac_context *mac; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) { + sme_err("mac_handle is not valid"); + return QDF_STATUS_E_INVAL; + } + + mac = MAC_CONTEXT(mac_handle); + + if (mac->sme.monitor_mode_cb) + mac->sme.monitor_mode_cb(vdev_id); + else { + sme_warn_rl("monitor_mode_cb is not registered"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif