From db2a8bed511aca095ba11147c8c6b8b12d0d89bf Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Wed, 20 Dec 2017 11:49:56 -0800 Subject: [PATCH] qcacld-3.0: Close FTM vdev leak When the driver transitions into Factory Test Mode (FTM), the existing vdev is not properly destroyed. This ultimately leads to a vdev object leak when the driver is unloaded while in FTM. To close the leak, tear down the existing station vdev before doing the module stop operation. Change-Id: I48ca4e6fc5750e593b6afc4e6b44a603570101cc CRs-Fixed: 2137144 --- core/hdd/inc/wlan_hdd_main.h | 9 ++-- core/hdd/src/wlan_hdd_cfg80211.c | 6 +-- core/hdd/src/wlan_hdd_hostapd.c | 8 +-- core/hdd/src/wlan_hdd_main.c | 90 +++++++++----------------------- core/hdd/src/wlan_hdd_p2p.c | 4 +- 5 files changed, 38 insertions(+), 79 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 09d97b3a2934..87ed0a8c7b05 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1840,8 +1840,7 @@ QDF_STATUS hdd_close_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter, bool rtnl_held); QDF_STATUS hdd_close_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held); -QDF_STATUS hdd_stop_all_adapters(struct hdd_context *hdd_ctx, - bool close_session); +QDF_STATUS hdd_stop_all_adapters(struct hdd_context *hdd_ctx); void hdd_deinit_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held); QDF_STATUS hdd_reset_all_adapters(struct hdd_context *hdd_ctx); QDF_STATUS hdd_start_all_adapters(struct hdd_context *hdd_ctx); @@ -1862,8 +1861,7 @@ void hdd_deinit_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter, bool rtnl_held); QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, - struct hdd_adapter *adapter, - const bool bCloseSession); + struct hdd_adapter *adapter); void hdd_set_station_ops(struct net_device *dev); uint8_t *wlan_hdd_get_intf_addr(struct hdd_context *hdd_ctx); void wlan_hdd_release_intf_addr(struct hdd_context *hdd_ctx, @@ -2377,7 +2375,6 @@ void hdd_deregister_cb(struct hdd_context *hdd_ctx); int hdd_start_station_adapter(struct hdd_adapter *adapter); int hdd_start_ap_adapter(struct hdd_adapter *adapter); int hdd_configure_cds(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter); -int hdd_start_ftm_adapter(struct hdd_adapter *adapter); int hdd_set_fw_params(struct hdd_adapter *adapter); int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter, diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index e286d4fc8a7a..b961582560b4 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -9718,7 +9718,7 @@ int wlan_hdd_request_pre_cac(uint8_t channel) return 0; stop_close_pre_cac_adapter: - hdd_stop_adapter(hdd_ctx, pre_cac_adapter, true); + hdd_stop_adapter(hdd_ctx, pre_cac_adapter); qdf_mem_free(pre_cac_adapter->session.ap.beacon); pre_cac_adapter->session.ap.beacon = NULL; close_pre_cac_adapter: @@ -14123,7 +14123,7 @@ static int wlan_hdd_change_client_iface_to_new_mode(struct net_device *ndev, } wdev = ndev->ieee80211_ptr; - hdd_stop_adapter(hdd_ctx, adapter, true); + hdd_stop_adapter(hdd_ctx, adapter); hdd_deinit_adapter(hdd_ctx, adapter, true); wdev->iftype = type; /*Check for sub-string p2p to confirm its a p2p interface */ @@ -14293,7 +14293,7 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, (adapter); } - hdd_stop_adapter(hdd_ctx, adapter, true); + hdd_stop_adapter(hdd_ctx, adapter); /* De-init the adapter */ hdd_deinit_adapter(hdd_ctx, adapter, true); memset(&adapter->session, 0, diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 61ff04c90a63..7ee8e6e31808 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -515,7 +515,7 @@ static int __hdd_hostapd_stop(struct net_device *dev) * needs to de-init the sap session here and re-init when * __hdd_hostapd_open() API */ - hdd_stop_adapter(hdd_ctx, adapter, true); + hdd_stop_adapter(hdd_ctx, adapter); hdd_deinit_adapter(hdd_ctx, adapter, true); clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); /* Stop all tx queues */ @@ -1107,7 +1107,7 @@ static void __wlan_hdd_sap_pre_cac_failure(void *data) wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes); - hdd_stop_adapter(hdd_ctx, adapter, true); + hdd_stop_adapter(hdd_ctx, adapter); hdd_close_adapter(hdd_ctx, adapter, false); } @@ -1158,7 +1158,7 @@ static void wlan_hdd_sap_pre_cac_success(void *data) cds_ssr_protect(__func__); wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes); - hdd_stop_adapter(hdd_ctx, adapter, true); + hdd_stop_adapter(hdd_ctx, adapter); hdd_close_adapter(hdd_ctx, adapter, false); cds_ssr_unprotect(__func__); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index f0f7a98627bd..241eb74589b4 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2099,19 +2099,16 @@ int hdd_start_adapter(struct hdd_adapter *adapter) * For IBSS interface is initialized as part of * hdd_init_station_mode() */ - return 0; + goto exit_with_success; case QDF_FTM_MODE: - ret = hdd_start_ftm_adapter(adapter); - if (ret) - goto err_start_adapter; - else - goto ftm_complete; - break; + /* vdevs are dynamically managed by firmware in FTM */ + goto exit_with_success; default: hdd_err("Invalid session type %d", device_mode); QDF_ASSERT(0); goto err_start_adapter; } + if (hdd_set_fw_params(adapter)) hdd_err("Failed to set the FW params for the adapter!"); @@ -2125,9 +2122,11 @@ int hdd_start_adapter(struct hdd_adapter *adapter) goto err_start_adapter; } -ftm_complete: +exit_with_success: EXIT(); + return 0; + err_start_adapter: return -EINVAL; } @@ -2859,7 +2858,7 @@ static int __hdd_stop(struct net_device *dev) * Notice that hdd_stop_adapter is requested not to close the session * That is intentional to be able to scan if it is a STA/P2P interface */ - hdd_stop_adapter(hdd_ctx, adapter, true); + hdd_stop_adapter(hdd_ctx, adapter); /* DeInit the adapter. This ensures datapath cleanup as well */ hdd_deinit_adapter(hdd_ctx, adapter, true); @@ -4554,8 +4553,8 @@ void wlan_hdd_reset_prob_rspies(struct hdd_adapter *adapter) } } -QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter, - const bool bCloseSession) +QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) { QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; struct hdd_wext_state *pWextState = @@ -4651,19 +4650,14 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *ada if (adapter->device_mode == QDF_STA_MODE) wlan_cfg80211_sched_scan_stop(hdd_ctx->hdd_pdev, adapter->dev); - /* - * It is possible that the caller of this function does not - * wish to close the session - */ - if (true == bCloseSession) { - if (0 != wlan_hdd_try_disconnect(adapter)) { - hdd_err("Error: Can't disconnect adapter"); - return QDF_STATUS_E_FAILURE; - } - hdd_debug("Destroying adapter: %d", - adapter->session_id); - hdd_vdev_destroy(adapter); + + if (wlan_hdd_try_disconnect(adapter)) { + hdd_err("Error: Can't disconnect adapter"); + return QDF_STATUS_E_FAILURE; } + + hdd_vdev_destroy(adapter); + break; case QDF_SAP_MODE: @@ -4765,11 +4759,9 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *ada cancel_work_sync(&adapter->ipv6_notifier_work); #endif #endif - if (true == bCloseSession) { - hdd_debug("Destroying adapter: %d", - adapter->session_id); - hdd_vdev_destroy(adapter); - } + + hdd_vdev_destroy(adapter); + mutex_unlock(&hdd_ctx->sap_lock); break; case QDF_OCB_MODE: @@ -4809,8 +4801,7 @@ void hdd_deinit_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held) EXIT(); } -QDF_STATUS hdd_stop_all_adapters(struct hdd_context *hdd_ctx, - bool close_session) +QDF_STATUS hdd_stop_all_adapters(struct hdd_context *hdd_ctx) { struct hdd_adapter *adapter; @@ -4819,7 +4810,7 @@ QDF_STATUS hdd_stop_all_adapters(struct hdd_context *hdd_ctx, cds_flush_work(&hdd_ctx->sap_pre_cac_work); hdd_for_each_adapter(hdd_ctx, adapter) - hdd_stop_adapter(hdd_ctx, adapter, close_session); + hdd_stop_adapter(hdd_ctx, adapter); EXIT(); @@ -6235,7 +6226,7 @@ static void hdd_wlan_exit(struct hdd_context *hdd_ctx) */ hdd_abort_mac_scan_all_adapters(hdd_ctx); hdd_abort_sched_scan_all_adapters(hdd_ctx); - hdd_stop_all_adapters(hdd_ctx, true); + hdd_stop_all_adapters(hdd_ctx); hdd_deinit_all_adapters(hdd_ctx, false); } @@ -8396,31 +8387,6 @@ int hdd_start_ap_adapter(struct hdd_adapter *adapter) return 0; } -/** - * hdd_start_ftm_adapter()- Start FTM adapter - * @adapter: HDD adapter - * - * This function initializes the adapter for the FTM mode. - * - * Return: 0 on success or errno on failure. - */ -int hdd_start_ftm_adapter(struct hdd_adapter *adapter) -{ - QDF_STATUS qdf_status; - - ENTER_DEV(adapter->dev); - - qdf_status = hdd_init_tx_rx(adapter); - - if (QDF_STATUS_SUCCESS != qdf_status) { - hdd_err("Failed to start FTM adapter: %d", qdf_status); - return qdf_status_to_os_return(qdf_status); - } - - return 0; - EXIT(); -} - static int hdd_open_concurrent_interface(struct hdd_context *hdd_ctx, bool rtnl_held) { @@ -11895,9 +11861,8 @@ static void hdd_stop_present_mode(struct hdd_context *hdd_ctx, case QDF_GLOBAL_FTM_MODE: hdd_abort_mac_scan_all_adapters(hdd_ctx); wlan_cfg80211_cleanup_scan_queue(hdd_ctx->hdd_pdev); + hdd_stop_all_adapters(hdd_ctx); - /* re-use the existing session */ - hdd_stop_all_adapters(hdd_ctx, false); break; default: break; @@ -12071,16 +12036,13 @@ static int __con_mode_handler(const char *kmessage, struct kernel_param *kp, goto reset_flags; } - if (con_mode == QDF_GLOBAL_MONITOR_MODE || - con_mode == QDF_GLOBAL_FTM_MODE) { + if (con_mode == QDF_GLOBAL_MONITOR_MODE) { if (hdd_start_adapter(adapter)) { hdd_err("Failed to start %s adapter", kmessage); ret = -EINVAL; goto reset_flags; } - } - if (con_mode == QDF_GLOBAL_MONITOR_MODE) { hdd_info("Acquire wakelock for monitor mode!"); qdf_wake_lock_acquire(&hdd_ctx->monitor_mode_wakelock, WIFI_POWER_EVENT_WAKELOCK_MONITOR_MODE); diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c index 66286f1c7580..03ac6f5d3ef7 100644 --- a/core/hdd/src/wlan_hdd_p2p.c +++ b/core/hdd/src/wlan_hdd_p2p.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -855,7 +855,7 @@ int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) } else { wlan_hdd_release_intf_addr(hdd_ctx, pVirtAdapter->mac_addr.bytes); - hdd_stop_adapter(hdd_ctx, pVirtAdapter, true); + hdd_stop_adapter(hdd_ctx, pVirtAdapter); hdd_deinit_adapter(hdd_ctx, pVirtAdapter, true); hdd_close_adapter(hdd_ctx, pVirtAdapter, true); }