qcacld-3.0: Fix deadlock when SAP interface down during pre_cac failure

While pre cac is in progress and if the SAP is stopped from UI, It may
lead to dead-lock due to rtnl lock. This is because, stopping SAP will
trigger the stop_ap first and then hostapd_stop. Stop_ap will schedule
a work to handle pre_cac failure (Thread1). hostapd_stop will be
triggered in parallel (Thread2). This will result in a below dead-lock
scenario.
   Thread1: Waiting to acquire rtnl_lock to unregister pre_cac adapter.
   Thread2: Acquired the rtnl_lock and waiting for Thread1 to complete

To resolve this dead-lock, unregister pre_cac_adapter during
hostapd_stop without requesting for rtnl_lock.

Change-Id: I222df9ee0d75b16f79c28b7cdd86369c340a15c2
CRs-Fixed: 2832256
This commit is contained in:
Bapiraju Alla 2020-12-14 10:17:19 +05:30 • committed by snandini
commit 742f919c75
5 changed files with 103 additions and 40 deletions

View file

@ -1439,6 +1439,8 @@ struct hdd_adapter {
ol_txrx_rx_fp rx_stack;
qdf_work_t netdev_features_update_work;
/* Flag to indicate whether it is a pre cac adapter or not */
bool is_pre_cac_adapter;
};
#define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station)

View file

@ -1081,9 +1081,7 @@ static void __wlan_hdd_sap_pre_cac_failure(struct hdd_adapter *adapter)
if (wlan_hdd_validate_context(hdd_ctx))
return;
wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes);
hdd_stop_adapter(hdd_ctx, adapter);
hdd_close_adapter(hdd_ctx, adapter, false);
hdd_exit();
}
@ -1106,13 +1104,10 @@ void wlan_hdd_sap_pre_cac_failure(void *data)
if (errno)
return;
osif_vdev_sync_unregister(adapter->dev);
osif_vdev_sync_wait_for_ops(vdev_sync);
__wlan_hdd_sap_pre_cac_failure(data);
osif_vdev_sync_trans_stop(vdev_sync);
osif_vdev_sync_destroy(vdev_sync);
}
/**
@ -1140,7 +1135,6 @@ static void __wlan_hdd_sap_pre_cac_success(struct hdd_adapter *adapter)
wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes);
hdd_stop_adapter(hdd_ctx, adapter);
hdd_close_adapter(hdd_ctx, adapter, false);
/* Prepare to switch AP from 2.4GHz channel to the pre CAC channel */
ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);

View file

@ -6787,6 +6787,8 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
hdd_periodic_sta_stats_init(adapter);
adapter->is_pre_cac_adapter = false;
return adapter;
err_destroy_adapter_features_update_work:
@ -6979,6 +6981,32 @@ static inline void hdd_dump_func_call_map(void)
}
#endif
static void hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx)
{
struct hdd_adapter *pre_cac_adapter;
struct osif_vdev_sync *vdev_sync;
int errno;
pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx,
SAP_PRE_CAC_IFNAME);
if (!pre_cac_adapter)
return;
errno = osif_vdev_sync_trans_start_wait(pre_cac_adapter->dev,
&vdev_sync);
if (errno)
return;
osif_vdev_sync_unregister(pre_cac_adapter->dev);
osif_vdev_sync_wait_for_ops(vdev_sync);
wlan_hdd_release_intf_addr(hdd_ctx, pre_cac_adapter->mac_addr.bytes);
hdd_close_adapter(hdd_ctx, pre_cac_adapter, true);
osif_vdev_sync_trans_stop(vdev_sync);
osif_vdev_sync_destroy(vdev_sync);
}
QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter)
{
@ -7176,11 +7204,23 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
ucfg_ipa_flush(hdd_ctx->pdev);
/* don't flush pre-cac destroy if we are destroying pre-cac */
sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter);
if (!wlan_sap_is_pre_cac_context(sap_ctx) &&
(hdd_ctx->sap_pre_cac_work.fn))
cds_flush_work(&hdd_ctx->sap_pre_cac_work);
if (!adapter->is_pre_cac_adapter) {
/**
* don't flush pre-cac destroy if we are destroying
* pre-cac adapter
*/
sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter);
if (!wlan_sap_is_pre_cac_context(sap_ctx) &&
(hdd_ctx->sap_pre_cac_work.fn))
cds_flush_work(&hdd_ctx->sap_pre_cac_work);
hdd_close_pre_cac_adapter(hdd_ctx);
} else {
if (wlan_sap_set_pre_cac_status(
WLAN_HDD_GET_SAP_CTX_PTR(adapter), false))
hdd_err("Failed to set is_pre_cac_on to false");
}
/* fallthrough */

View file

@ -165,7 +165,7 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
uint32_t chan_freq,
struct hdd_adapter **out_adapter)
{
uint8_t *mac_addr;
uint8_t *mac_addr = NULL;
uint32_t pre_cac_chan_freq = 0;
int ret;
struct hdd_adapter *ap_adapter, *pre_cac_adapter;
@ -216,12 +216,6 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
return -EINVAL;
}
mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_SAP_MODE);
if (!mac_addr) {
hdd_err("can't add virtual intf: Not getting valid mac addr");
return -EINVAL;
}
hdd_debug("channel: %d", chan_freq);
ret = wlan_hdd_validate_and_get_pre_cac_ch(
@ -233,28 +227,42 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
hdd_debug("starting pre cac SAP adapter");
/* Starting a SAP adapter:
* Instead of opening an adapter, we could just do a SME open session
* for AP type. But, start BSS would still need an adapter.
* So, this option is not taken.
*
* hdd open adapter is going to register this precac interface with
* user space. This interface though exposed to user space will be in
* DOWN state. Consideration was done to avoid this registration to the
* user space. But, as part of SAP operations multiple events are sent
* to user space. Some of these events received from unregistered
* interface was causing crashes. So, retaining the registration.
*
* So, this interface would remain registered and will remain in DOWN
* state for the CAC duration. We will add notes in the feature
* announcement to not use this temporary interface for any activity
* from user space.
*/
pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE, "precac%d",
mac_addr, NET_NAME_UNKNOWN, true);
pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx,
SAP_PRE_CAC_IFNAME);
if (!pre_cac_adapter) {
hdd_err("error opening the pre cac adapter");
goto release_intf_addr_and_return_failure;
mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_SAP_MODE);
if (!mac_addr) {
hdd_err("can't add virtual intf: Not getting valid mac addr");
return -EINVAL;
}
/**
* Starting a SAP adapter:
* Instead of opening an adapter, we could just do a SME open
* session for AP type. But, start BSS would still need an
* adapter. So, this option is not taken.
*
* hdd open adapter is going to register this precac interface
* with user space. This interface though exposed to user space
* will be in DOWN state. Consideration was done to avoid this
* registration to the user space. But, as part of SAP
* operations multiple events are sent to user space. Some of
* these events received from unregistered interface was
* causing crashes. So, retaining the registration.
*
* So, this interface would remain registered and will remain
* in DOWN state for the CAC duration. We will add notes in the
* feature announcement to not use this temporary interface for
* any activity from user space.
*/
pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE,
SAP_PRE_CAC_IFNAME, mac_addr,
NET_NAME_UNKNOWN, true);
if (!pre_cac_adapter) {
hdd_err("error opening the pre cac adapter");
goto release_intf_addr_and_return_failure;
}
}
/*
@ -370,6 +378,7 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
}
ap_adapter->pre_cac_freq = pre_cac_chan_freq;
pre_cac_adapter->is_pre_cac_adapter = true;
*out_adapter = pre_cac_adapter;
@ -388,7 +397,8 @@ release_intf_addr_and_return_failure:
* adapter which is trying to come wouldn't get valid
* mac address. Remember we have limited pool of mac addresses
*/
wlan_hdd_release_intf_addr(hdd_ctx, mac_addr);
if (mac_addr)
wlan_hdd_release_intf_addr(hdd_ctx, mac_addr);
return -EINVAL;
}

View file

@ -67,6 +67,8 @@ extern "C" {
#define SAP_DEFAULT_5GHZ_CHANNEL (40)
#define SAP_CHANNEL_NOT_SELECTED (0)
#define SAP_PRE_CAC_IFNAME "precac"
/*--------------------------------------------------------------------------
* reasonCode taken from 802.11 standard.
* ------------------------------------------------------------------------*/
@ -832,6 +834,7 @@ QDF_STATUS wlan_sap_update_next_channel(struct sap_context *sap_ctx,
uint8_t channel,
enum phy_ch_width chan_bw);
#ifdef FEATURE_SAP_COND_CHAN_SWITCH
/**
* wlan_sap_set_pre_cac_status() - Set the pre cac status
* @sap_ctx: SAP context
@ -855,6 +858,20 @@ QDF_STATUS wlan_sap_set_pre_cac_status(struct sap_context *sap_ctx,
*/
QDF_STATUS wlan_sap_set_chan_before_pre_cac(struct sap_context *sap_ctx,
uint8_t chan_before_pre_cac);
#else
static inline QDF_STATUS
wlan_sap_set_pre_cac_status(struct sap_context *sap_ctx, bool status)
{
return QDF_STATUS_SUCCESS;
}
static inline QDF_STATUS
wlan_sap_set_chan_before_pre_cac(struct sap_context *sap_ctx,
uint8_t chan_before_pre_cac)
{
return QDF_STATUS_SUCCESS;
}
#endif
/**
* wlan_sap_set_pre_cac_complete_status() - Sets pre cac complete status