mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-26 06:33:19 -04:00
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:
parent
b230203823
commit
742f919c75
5 changed files with 103 additions and 40 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue