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
This commit is contained in:
Dustin Brown 2017-12-20 11:49:56 -08:00
commit db2a8bed51
5 changed files with 38 additions and 79 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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__);

View file

@ -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);

View file

@ -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);
}