diff --git a/components/ipa/core/inc/wlan_ipa_core.h b/components/ipa/core/inc/wlan_ipa_core.h index e528936a18cd..9543783166f8 100644 --- a/components/ipa/core/inc/wlan_ipa_core.h +++ b/components/ipa/core/inc/wlan_ipa_core.h @@ -637,6 +637,19 @@ int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr); */ bool wlan_ipa_is_fw_wdi_activated(struct wlan_ipa_priv *ipa_ctx); +/** + * wlan_ipa_uc_cleanup_sta - disconnect and cleanup sta iface + * @ipa_ctx: IPA context + * @net_dev: Interface net device + * + * Send disconnect sta event to IPA driver and cleanup IPA iface + * if not yet done + * + * Return: void + */ +void wlan_ipa_uc_cleanup_sta(struct wlan_ipa_priv *ipa_ctx, + qdf_netdev_t net_dev); + /** * wlan_ipa_uc_disconnect_ap() - send ap disconnect event * @ipa_ctx: IPA context diff --git a/components/ipa/core/inc/wlan_ipa_main.h b/components/ipa/core/inc/wlan_ipa_main.h index 5a40e037f603..7fe4a3277fa1 100644 --- a/components/ipa/core/inc/wlan_ipa_main.h +++ b/components/ipa/core/inc/wlan_ipa_main.h @@ -377,6 +377,19 @@ int ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr); */ bool ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev); +/** + * ipa_uc_cleanup_sta() - disconnect and cleanup sta iface + * @pdev: pdev obj + * @net_dev: Interface net device + * + * Send disconnect sta event to IPA driver and cleanup IPA iface, + * if not yet done + * + * Return: void + */ +void ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev); + /** * ipa_uc_disconnect_ap() - send ap disconnect event * @pdev: pdev obj diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c index 6a2a2521523e..b8832800107b 100644 --- a/components/ipa/core/src/wlan_ipa_core.c +++ b/components/ipa/core/src/wlan_ipa_core.c @@ -3343,6 +3343,27 @@ static QDF_STATUS wlan_ipa_uc_send_evt(qdf_netdev_t net_dev, return QDF_STATUS_SUCCESS; } +void wlan_ipa_uc_cleanup_sta(struct wlan_ipa_priv *ipa_ctx, + qdf_netdev_t net_dev) +{ + struct wlan_ipa_iface_context *iface_ctx; + int i; + + ipa_debug("enter"); + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_ctx = &ipa_ctx->iface_context[i]; + if (iface_ctx && iface_ctx->device_mode == QDF_STA_MODE && + iface_ctx->dev == net_dev && iface_ctx->tl_context) { + wlan_ipa_uc_send_evt(net_dev, QDF_IPA_STA_DISCONNECT, + net_dev->dev_addr); + wlan_ipa_cleanup_iface(iface_ctx); + } + } + + ipa_debug("exit"); +} + QDF_STATUS wlan_ipa_uc_disconnect_ap(struct wlan_ipa_priv *ipa_ctx, qdf_netdev_t net_dev) { diff --git a/components/ipa/core/src/wlan_ipa_main.c b/components/ipa/core/src/wlan_ipa_main.c index de174a8334c3..fadf08963d7b 100644 --- a/components/ipa/core/src/wlan_ipa_main.c +++ b/components/ipa/core/src/wlan_ipa_main.c @@ -541,6 +541,20 @@ bool ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev) return wlan_ipa_is_fw_wdi_activated(ipa_obj); } +void ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ + struct wlan_ipa_priv *ipa_obj; + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_cleanup_sta(ipa_obj, net_dev); +} + QDF_STATUS ipa_uc_disconnect_ap(struct wlan_objmgr_pdev *pdev, qdf_netdev_t net_dev) { diff --git a/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h b/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h index 12ca7edc020d..4f349076d0fb 100644 --- a/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h +++ b/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h @@ -285,6 +285,19 @@ int ucfg_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr); */ bool ucfg_ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev); +/** + * ucfg_ipa_uc_cleanup_sta() - disconnect and cleanup sta iface + * @pdev: pdev obj + * @net_dev: Interface net device + * + * Send disconnect sta event to IPA driver and cleanup IPA iface, + * if not yet done + * + * Return: void + */ +void ucfg_ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev); + /** * ucfg_ipa_uc_disconnect_ap() - send ap disconnect event * @pdev: pdev obj @@ -507,6 +520,12 @@ bool ucfg_ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev) return false; } +static inline +void ucfg_ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ +} + static inline QDF_STATUS ucfg_ipa_uc_disconnect_ap(struct wlan_objmgr_pdev *pdev, qdf_netdev_t net_dev) diff --git a/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c b/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c index cc8ab8b66003..b1fedfaf4921 100644 --- a/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c +++ b/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c @@ -174,6 +174,12 @@ bool ucfg_ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev) return ipa_is_fw_wdi_activated(pdev); } +void ucfg_ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ + return ipa_uc_cleanup_sta(pdev, net_dev); +} + QDF_STATUS ucfg_ipa_uc_disconnect_ap(struct wlan_objmgr_pdev *pdev, qdf_netdev_t net_dev) { diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index d49e2d6f2220..10b679491f2b 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -5857,14 +5857,21 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, mac_handle, adapter->vdev_id, eCSR_DISCONNECT_REASON_IBSS_LEAVE); - else if (adapter->device_mode == QDF_STA_MODE) - wlan_hdd_disconnect(adapter, - eCSR_DISCONNECT_REASON_DEAUTH); - else + else if (adapter->device_mode == QDF_STA_MODE) { + rc = wlan_hdd_disconnect( + adapter, + eCSR_DISCONNECT_REASON_DEAUTH); + if (rc != 0 && ucfg_ipa_is_enabled()) { + hdd_err("STA disconnect failed"); + ucfg_ipa_uc_cleanup_sta(hdd_ctx->pdev, + adapter->dev); + } + } else { status = sme_roam_disconnect( mac_handle, adapter->vdev_id, eCSR_DISCONNECT_REASON_UNSPECIFIED); + } /* success implies disconnect is queued */ if (QDF_IS_STATUS_SUCCESS(status) && adapter->device_mode != QDF_STA_MODE) {